{"id":455170,"date":"2025-04-08T15:01:21","date_gmt":"2025-04-08T15:01:21","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=455170"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=455170","title":{"rendered":"<span>SwiftUI: \u041f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0444\u0438\u0442\u043d\u0435\u0441-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c HealthKit<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d10\/e9c\/a0d\/d10e9ca0d8467b96c9d0ad1b1aab0c02.gif\" width=\"250\" height=\"298\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d10\/e9c\/a0d\/d10e9ca0d8467b96c9d0ad1b1aab0c02.gif\"\/><\/figure>\n<p><strong>\u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <\/strong><a href=\"https:\/\/github.com\/0Itsuki0\/SwiftUI_SimpleWorkoutApp\"><strong>GitHub<\/strong><\/a><strong>!<\/strong><\/p>\n<p>**************<\/p>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\"><strong>HealthKit<\/strong><\/a>\u00a0\u2014 \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u0434\u0430\u043d\u043d\u044b\u043c, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435\u043c \u0438 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0438\u043c\u0438, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u0438\u00a0\u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0412\u00a0\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c <strong>\u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f\u00a0\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u043a<\/strong>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u00a0\u043e\u0441\u043d\u043e\u0432\u0430\u043c\u0438 \u044d\u0442\u043e\u0433\u043e \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f\u00a0watchOS, \u0442\u0430\u043a \u043a\u0430\u043a\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430, \u043d\u0430\u00a0\u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043d\u0430\u0438\u043b\u0443\u0447\u0448\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b HealthKit.<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445:<\/p>\n<ul>\n<li>\n<p>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0440\u043e\u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a, \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430, \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0435\u0435 \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u044d\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0430\u043b\u043e!<\/p>\n<p>\u0427\u0442\u043e\u00a0\u0436\u0435 \u043d\u0430\u0441 \u0436\u0434\u0435\u0442 \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438? \u0412\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u0432\u00a0\u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438!<\/p>\n<h2>\u041e\u0431\u0437\u043e\u0440<\/h2>\n<p>HealthKit\u00a0\u2014 \u044d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u0443\u0436\u0438\u0442 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u00a0\u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0438 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u043d\u0430\u00a0iPhone \u0438 Apple Watch. \u0421\u00a0\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u044d\u0442\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443, \u0447\u0442\u043e\u0431\u044b \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443\u00a0\u0436\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>1. \u041a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u00a0\u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>2. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043b\u044e\u0431\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432\u00a0\u0434\u0430\u043d\u043d\u044b\u0445 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432\u043d\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u043c\u043e\u0433\u0443\u0442\u00a0\u0431\u044b\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c <strong>\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e<\/strong> \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430\u00a0\u0447\u0442\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit.<\/p>\n<p>\u0418 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0438\u043c \u043c\u044b \u0438 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435!<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h2>\n<p>\u0412\u00a0\u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0436\u043d\u044b\u0445 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 HealthKit.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0434\u043b\u044f\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 HealthKit<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c HealthKit, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b HealthKit \u0432\u00a0\u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>Watch <\/strong>\u0432\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0430\u0440\u0433\u0435\u0442\u0430!<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a37\/f70\/c41\/a37f70c41a629fb7b2a022409ad9e319.png\" width=\"400\" height=\"123\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a37\/f70\/c41\/a37f70c41a629fb7b2a022409ad9e319.png\"\/><\/figure>\n<p>\u0412\u00a0\u0440\u0430\u0437\u0434\u0435\u043b\u0435 <strong>Signing &amp; Capabilities<\/strong> \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 <strong>+ Capability<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e8e\/299\/3ca\/e8e2993caa503735dd08de406a068fa2.png\" width=\"875\" height=\"73\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e8e\/299\/3ca\/e8e2993caa503735dd08de406a068fa2.png\"\/><\/figure>\n<p>\u041d\u0430\u0439\u0434\u0438\u0442\u0435 HealthKit \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0435\u0433\u043e \u043a\u00a0\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0442\u0430\u0440\u0433\u0435\u0442\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b82\/61e\/7e5\/b8261e7e5f06cd46681ac3b180b13847.png\" width=\"875\" height=\"344\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b82\/61e\/7e5\/b8261e7e5f06cd46681ac3b180b13847.png\"\/><\/figure>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u0430 \u0444\u043b\u0430\u0436\u043a\u0430 \u043f\u0443\u0441\u0442\u044b\u043c\u0438, \u043a\u0430\u043a\u00a0\u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430\u00a0\u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u043d\u0438\u0436\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/df5\/6d4\/809\/df56d480981ad243c43f2ac8cdf975e9.png\" width=\"875\" height=\"146\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/df5\/6d4\/809\/df56d480981ad243c43f2ac8cdf975e9.png\"\/><\/figure>\n<p>\u0414\u0430, \u043d\u0430\u043c <strong>\u041d\u0415<\/strong> \u043d\u0443\u0436\u043d\u0430 <strong>HealthKit Background Delivery<\/strong>.<\/p>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f\u00a0\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/reading-data-from-healthkit#Long-running-queries\"><strong>\u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/strong><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit.<\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430<\/h3>\n<p>\u0414\u043b\u044f\u00a0\u0442\u043e\u0433\u043e\u00a0\u0436\u0435 \u0442\u0430\u0440\u0433\u0435\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b <strong>Background Modes<\/strong> \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u043f\u0446\u0438\u044e <strong>Workout processing<\/strong>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b22\/732\/ab4\/b22732ab4ba7673de8437ba067462b71.png\" width=\"875\" height=\"157\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b22\/732\/ab4\/b22732ab4ba7673de8437ba067462b71.png\"\/><\/figure>\n<p>\u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a\u00a0\u0441\u043e\u0436\u0436\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u043b\u043e\u0440\u0438\u0438 \u0438 \u0447\u0430\u0441\u0442\u043e\u0442\u0430 \u0441\u0435\u0440\u0434\u0435\u0447\u043d\u044b\u0445 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0439, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u043a\u00a0\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442\u0430\u043a \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u0445 \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043a\u043b\u044e\u0447\u0430 \u0432\u00a0<code>Info.plist<\/code> \u043d\u0430\u0448\u0435\u0433\u043e <strong>\u0442\u0430\u0440\u0433\u0435\u0442\u0430<\/strong>!<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/bundleresources\/information-property-list\/nshealthshareusagedescription\">NSHealthShareUsageDescription<\/a>\u00a0\u2014 \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u00a0\u0447\u0442\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u0432 \u0438\u0437\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 HealthKit.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/bundleresources\/information-property-list\/nshealthupdateusagedescription\">NSHealthUpdateUsageDescription<\/a>\u00a0\u2014 \u0434\u043b\u044f\u00a0\u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f, \u0437\u0430\u0447\u0435\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u00a0\u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0e7\/4ca\/784\/0e74ca7844dcd46a31d841a568f30dbd.png\" width=\"875\" height=\"58\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0e7\/4ca\/784\/0e74ca7844dcd46a31d841a568f30dbd.png\"\/><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043c\u0435\u0434\u0438\u0446\u0438\u043d\u0441\u043a\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u0431\u043e\u043b\u0435\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b, \u0447\u0435\u043c \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432\u00a0\u0440\u0430\u0437\u0434\u0435\u043b\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/HealthKit\/accessing-a-user-s-clinical-records\"><strong>Accessing a User\u00bbs Clinical Records<\/strong><\/a>.<\/p>\n<h2>WorkoutManager<\/h2>\n<p>\u041a\u0430\u043a\u00a0\u0432\u0441\u0435\u0433\u0434\u0430, \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u0441\u00a0\u043a\u043b\u0430\u0441\u0441\u0430 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430. \u042f \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u00a0\u0432\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u00a0\u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440.<\/p>\n<h3>\u041a\u043e\u0434<\/h3>\n<pre><code class=\"swift\">\/\/ \/\/  WorkoutManager.swift \/\/  ItsukiWorkoutApp \/\/ \/\/  Created by Itsuki on 2025\/03\/02. \/\/   import SwiftUI import HealthKit   @MainActor @Observable class WorkoutManager: NSObject {       let supportedWorkoutTypes: Set&lt;HKWorkoutActivityType&gt; = [         .walking,         .running,         .cycling,         .swimming,         .swimBikeRun,         .highIntensityIntervalTraining,     ]          private let typesToShare: Set&lt;HKSampleType&gt; = [HKQuantityType.workoutType()]      private let typesToRead: Set&lt;HKObjectType&gt; = [         HKQuantityType(.heartRate),         HKQuantityType(.activeEnergyBurned),                  HKQuantityType(.stepCount),         HKQuantityType(.swimmingStrokeCount),         HKQuantityType(.walkingSpeed),         HKQuantityType(.cyclingSpeed),         HKQuantityType(.runningSpeed),          HKQuantityType(.distanceWalkingRunning),         HKQuantityType(.distanceCycling),         HKQuantityType(.distanceSwimming),          HKObjectType.activitySummaryType()     ]           var error: WorkoutError? {         didSet {             if let error {                 print(\"error: \\(error.message)\")             }         }     }          \/\/ \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0441\u0435\u0430\u043d\u0441\u0430     var showResult: Bool = false {         didSet {             if !showResult {                 reset()                 return             }         }     }     var workoutResult: HKWorkout? {         didSet {             if workoutResult != nil {                 self.showResult = true             }         }     }          \/\/ \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0435\u0430\u043d\u0441\u0430     var sessionRunning: Bool = false     var workoutMetrics: WorkoutMetrics?     func getElapseTime(at date: Date) -&gt; TimeInterval {         return self.builder?.elapsedTime(at: date) ?? 0     }          private var healthStore: HKHealthStore?          private var session: HKWorkoutSession?     private var builder: HKLiveWorkoutBuilder?     \/\/ \u0434\u043b\u044f iOS: \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 HKWorkoutBuilder \/\/    var builder: HKWorkoutBuilder?      override init() {         super.init()         if HKHealthStore.isHealthDataAvailable() {             self.healthStore = HKHealthStore()             Task {                 await self.requestAuthorization()             }         } else {             self.error = .unavailable         }     }  }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u041a\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f\u043c\u0438  extension WorkoutManager {     private func checkAvailability() async -&gt; Bool {         if !HKHealthStore.isHealthDataAvailable() {             self.error = .unavailable             return false         }                  do {             let status = try await healthStore?.statusForAuthorizationRequest(toShare: typesToShare, read: typesToRead)             if status == .unnecessary {                 return true             }                          if status == .shouldRequest {                 await self.requestAuthorization()                 return true             }                          self.error = .permissionDenied             return false                      } catch(let error) {             self.error = .requestPermissionError(error)             return false         }     }          private func requestAuthorization() async  {         do {             try await healthStore?.requestAuthorization(toShare: typesToShare, read: typesToRead)         } catch (let error) {             self.error = .requestPermissionError(error)         }     }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0430\u043d\u0441\u043e\u043c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \/ \u0431\u0438\u043b\u0434\u0435\u0440\u043e\u043c extension WorkoutManager {          func startWorkout(with configuration: HKWorkoutConfiguration) async {         let result = await self.checkAvailability()         if !result {             return         }         guard let healthStore else {             self.error = .unavailable             return         }          if !self.supportedWorkoutTypes.contains(configuration.activityType) {             self.error = .workoutTypeNotSupported             return         }                           do {             session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)             builder = session?.associatedWorkoutBuilder()         } catch(let error) {             self.error = .startWorkoutFailed(error)             return         }         builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration) \/\/        print(\"types to collect: \", builder?.dataSource?.typesToCollect as Any)                  \/\/ \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: respiratoryRate         \/\/ builder?.dataSource?.enableCollection(for: HKQuantityType(.respiratoryRate), predicate: nil)          \/\/ \u0414\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u0435\u0430\u043d\u0441\u0430 \u0438 \u0431\u0438\u043b\u0434\u0435\u0440\u0430         session?.delegate = self         builder?.delegate = self                  \/\/ \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u043a\u0442\u0438\u0432\u0438\u0442\u0438         let date = Date()          session?.startActivity(with: date)                  do {             try await builder?.beginCollection(at: date)             self.workoutMetrics = .init(workoutConfiguration: configuration)         } catch(let error) {             self.error = .startWorkoutFailed(error)             reset()         }     }          func resumeSession() {         session?.resume()     }          func pauseSession() {         session?.pause()     }          func endSession() {         session?.end()     }          private func reset() {         self.session = nil         self.builder = nil         self.workoutResult = nil         self.workoutMetrics = nil     }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438  extension WorkoutManager {     nonisolated private func setError(_ error: WorkoutError) {         DispatchQueue.main.async {             self.error = error         }     }          nonisolated private func updateMetrics(_ statistics: HKStatistics?) {         guard let statistics else { return }  \/\/        print(\"update metrics for \\(statistics.quantityType.identifier)\")         DispatchQueue.main.async {             switch statistics.quantityType {                              case HKQuantityType(.heartRate):                 self.workoutMetrics?.heartRate = statistics.heartRate                 self.workoutMetrics?.averageHeartRate = statistics.averageHeartRate                              case HKQuantityType(.activeEnergyBurned):                 self.workoutMetrics?.energyBurned = statistics.activeEnergyBurned             case HKQuantityType(.distanceWalkingRunning),                 HKQuantityType(.distanceCycling),                 HKQuantityType(.distanceSwimming):                 self.workoutMetrics?.distance = statistics.totalDistance                              case HKQuantityType(.walkingSpeed),                 HKQuantityType(.cyclingSpeed),                 HKQuantityType(.runningSpeed):                 self.workoutMetrics?.speed = statistics.speed                 self.workoutMetrics?.averageSpeed = statistics.averageSpeed                               case HKQuantityType(.swimmingStrokeCount):                 self.workoutMetrics?.stepStrokeCount = statistics.strokeCount                         case HKQuantityType(.stepCount):                 self.workoutMetrics?.stepStrokeCount = statistics.stepCount              default:                 return             }         }     } }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - HKWorkoutSessionDelegate  extension WorkoutManager: HKWorkoutSessionDelegate {     nonisolated func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {                  DispatchQueue.main.async {             self.sessionRunning = (toState == .running)         }         \/\/ \u0414\u043e\u0436\u0434\u0438\u0442\u0435\u0441\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0441\u0435\u0430\u043d\u0441\u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0431\u0438\u043b\u0434\u0435\u0440\u0430.         if toState == .ended {             Task {                 do {                     try await builder?.endCollection(at: date)                     let workout = try await builder?.finishWorkout()                     DispatchQueue.main.async {                         self.workoutResult = workout                     }                 } catch(let error) {                     self.setError(.endWorkFailed(error))                     return                 }                              }         }     }               \/\/ \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u0435\u0430\u043d\u0441 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.     \/\/ \u043a\u043e\u0433\u0434\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u0437-\u0437\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438, \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0432\u0441\u0435\u0433\u0434\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0434 workoutSession:didChangeToState:fromState:date:.     nonisolated func workoutSession(_ workoutSession: HKWorkoutSession, didFailWithError error: any Error) {         setError(.sessionStoppedWithError(error))         DispatchQueue.main.async(execute: {             self.endSession()             self.reset()         })     }               \/\/ \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u0441\u0435\u0430\u043d\u0441\u0430 \u043d\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0430\u043a\u0442\u0438\u0432\u0442\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0442\u0440\u0438\u0430\u0442\u043b\u043e\u043d\u0430 \u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e\u0431\u043e\u0440\u044c\u044f     nonisolated func workoutSession(_ workoutSession: HKWorkoutSession, didBeginActivityWith workoutConfiguration: HKWorkoutConfiguration, date: Date) {         print(\"did begin activity: \\(workoutConfiguration)\")              }          nonisolated func workoutSession(_ workoutSession: HKWorkoutSession, didEndActivityWith workoutConfiguration: HKWorkoutConfiguration, date: Date) {         print(\"did end activity: \\(workoutConfiguration)\")     }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - HKLiveWorkoutBuilderDelegate  extension WorkoutManager: HKLiveWorkoutBuilderDelegate {     nonisolated func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set&lt;HKSampleType&gt;) {         for type in collectedTypes {             guard let quantityType = type as? HKQuantityType else {                 return             }             let statistics = workoutBuilder.statistics(for: quantityType)             updateMetrics(statistics)         }      }          nonisolated func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {         print(\"did collect event: last new event: \\(String(describing: workoutBuilder.workoutEvents.last))\")         if let event = workoutBuilder.workoutEvents.last {             DispatchQueue.main.async(execute: {                 switch event.type {                 case .pauseOrResumeRequest:                     print(\"pauseOrResumeRequest received.\")                     self.sessionRunning ? self.pauseSession() : self.resumeSession()                     break                 default:                     break                 }             })         }     }          nonisolated func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didBegin workoutActivity: HKWorkoutActivity) {         print(\"did begin activity: \\(workoutActivity)\")     }          nonisolated func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didEnd workoutActivity: HKWorkoutActivity) {         print(\"did end activity: \\(workoutActivity)\")      }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u0422\u0438\u043f\u044b  extension WorkoutManager {     enum WorkoutError: Error {         case unavailable         case permissionDenied         case requestPermissionError(Error)         case workoutTypeNotSupported         case startWorkoutFailed(Error)         case endWorkFailed(Error)         case sessionStoppedWithError(Error)         case queryError(Error?)                  var message: String {             switch self {             case .unavailable:                 return \"Workout unavailable.\"             case .permissionDenied:                 return \"Permission denied.\"             case .requestPermissionError(let error):                 return \"Request permission: \\(error.localizedDescription)\"             case .workoutTypeNotSupported:                 return \"Workout type not supported.\"             case .startWorkoutFailed(let error):                 return \"startWorkoutFailed: \\(error.localizedDescription)\"             case .endWorkFailed(let error):                 return \"endWorkFailed: \\(error.localizedDescription)\"             case .sessionStoppedWithError(let error):                 return \"sessionStoppedWithError: \\(error.localizedDescription)\"             case .queryError(let error):                 return \"queryError: \\(error?.localizedDescription ?? \"unknown\")\"              }         }     }          struct WorkoutMetrics: Hashable, Identifiable, Equatable {         var id: UUID = UUID()                  var workoutConfiguration: HKWorkoutConfiguration                  var averageHeartRate: Double = 0         var heartRate: Double = 0         var energyBurned: Double = 0                  var distance: Double = 0         var speed: Double = 0         var averageSpeed: Double = 0                  var stepStrokeCount: Double = 0          static func == (lhs: Self, rhs: Self) -&gt; Bool {             return lhs.workoutConfiguration == rhs.workoutConfiguration         }                  func hash(into hasher: inout Hasher) {             hasher.combine(id)         }     } }   extension HKStatistics {     static var heartRateUnit: HKUnit {         HKUnit.count().unitDivided(by: HKUnit.minute())     }          static var energyUnit: HKUnit {         HKUnit.kilocalorie()     }          static var distanceUnit: HKUnit {         HKUnit.meter()     }          static var speedUnit: HKUnit {         HKUnit.meter().unitDivided(by: HKUnit.second())     }          static  var countUnit: HKUnit {         HKUnit.count()     }      var heartRate: Double {         if self.quantityType == HKQuantityType(.heartRate) {             return self.mostRecentQuantity()?.doubleValue(for: Self.heartRateUnit) ?? 0         }         return 0     }          var averageHeartRate: Double {         if self.quantityType == HKQuantityType(.heartRate) {             return self.averageQuantity()?.doubleValue(for: Self.heartRateUnit) ?? 0         }         return 0     }          var activeEnergyBurned: Double {         if self.quantityType == HKQuantityType(.activeEnergyBurned) {             return self.sumQuantity()?.doubleValue(for: Self.energyUnit) ?? 0         }         return 0     }          var totalDistance: Double {         if self.quantityType == HKQuantityType(.distanceWalkingRunning) ||             self.quantityType == HKQuantityType(.distanceCycling) ||             self.quantityType == HKQuantityType(.distanceSwimming) {             return self.sumQuantity()?.doubleValue(for: Self.distanceUnit) ?? 0         }         return 0     }          var speed: Double {         if self.quantityType == HKQuantityType(.walkingSpeed) ||             self.quantityType == HKQuantityType(.runningSpeed) ||             self.quantityType == HKQuantityType(.cyclingSpeed) {             return self.mostRecentQuantity()?.doubleValue(for: Self.speedUnit) ?? 0         }         return 0     }          var averageSpeed: Double {         if self.quantityType == HKQuantityType(.walkingSpeed) ||             self.quantityType == HKQuantityType(.runningSpeed) ||             self.quantityType == HKQuantityType(.cyclingSpeed) {             return self.averageQuantity()?.doubleValue(for: Self.speedUnit) ?? 0         }         return 0     }          var stepCount: Double {         if self.quantityType == HKQuantityType(.stepCount) {             return self.sumQuantity()?.doubleValue(for: Self.countUnit) ?? 0         }         return 0     }          var strokeCount: Double {         if self.quantityType == HKQuantityType(.swimmingStrokeCount) {             return self.sumQuantity()?.doubleValue(for: Self.countUnit) ?? 0         }         return 0     } }<\/code><\/pre>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkhealthstore\">HKHealthStore<\/a>\u00a0\u2014 \u0442\u043e\u0447\u043a\u0443 \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a\u043e \u0432\u0441\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u043c, \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u043c HealthKit,\u00a0\u2014 \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e\u00a0HealthKit \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430\u00a0\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0414\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkhealthstore\/ishealthdataavailable()\">isHealthDataAvailable()<\/a>.<\/p>\n<p>\u0415\u0441\u043b\u0438 HealthKit \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u00a0\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438 \u0447\u0442\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0441 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445, \u0432\u044b\u0437\u0432\u0430\u0432 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkhealthstore\/requestauthorization(toshare:read:)\">requestAuthorization(toShare:read:)<\/a>.<\/p>\n<pre><code class=\"swift\">override init() {     super.init()     if HKHealthStore.isHealthDataAvailable() {         self.healthStore = HKHealthStore()         Task {             await self.requestAuthorization()         }     } else {         self.error = .unavailable     } }  private func requestAuthorization() async  {     do {         try await healthStore?.requestAuthorization(toShare: typesToShare, read: typesToRead)     } catch (let error) {         self.error = .requestPermissionError(error)     } }<\/code><\/pre>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>typesToShare<\/code> \u0437\u0434\u0435\u0441\u044c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u00a0\u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hksampletype\">HKSampleType<\/a>, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytype\">HKQuantityType<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkcategorytype\">HKCategoryType<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkouttype\">HKWorkoutType<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkcorrelationtype\">HKCorrelationType<\/a>.<\/p>\n<p>\u0412\u00a0\u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkouttype\">HKWorkoutType<\/a>. \u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0432\u0441\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443, \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u0443\u044e \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044e, \u0441\u043e\u0436\u0436\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u043b\u043e\u0440\u0438\u0438 \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0432\u0430\u0436\u043d\u044b\u0435 \u0434\u0435\u0442\u0430\u043b\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430\u043c \u043d\u0435\u00a0\u043d\u0443\u0436\u043d\u044b \u0434\u0440\u0443\u0433\u0438\u0435 HKQuantityTypes \u043f\u043e\u00a0\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p><code>typesToRead<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e, \u0432\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u044b \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0445\u043e\u0442\u0438\u043c \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c. \u042d\u0442\u043e \u043c\u043e\u0436\u0435\u0442\u00a0\u0431\u044b\u0442\u044c \u043b\u044e\u0431\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u043f\u043e\u0434\u043a\u043b\u0430\u0441\u0441 \u043a\u043b\u0430\u0441\u0441\u0430 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkobjecttype\">HKObjectType<\/a>, \u0442\u0430\u043a\u043e\u0439 \u043a\u0430\u043a <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkcharacteristictype\">HKCharacteristicType<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytype\">HKQuantityType<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkcategorytype\">HKCategoryType<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkouttype\">HKWorkoutType<\/a> \u0438\u043b\u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkcorrelationtype\">HKCorrelationType<\/a>.<\/p>\n<p>\u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u0441\u044e\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytype\">HKQuantityType<\/a>`\u043e\u0432 \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkactivitysummarytype\">HKActivitySummaryType<\/a>. \u041d\u0435\u00a0\u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0442\u0438\u043f\u043e\u0432 \u0432\u00a0\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u00a0\u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u0438\u0435 \u0432\u0438\u0434\u044b \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u043a \u0432\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442\u0435\u0441\u044c \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0430\u0442\u044c.<\/p>\n<p>\u041f\u0440\u0438\u00a0\u043f\u0435\u0440\u0432\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435 \u043f\u0440\u0438\u0433\u043b\u0430\u0448\u0435\u043d\u0438\u0435 \u0441\u00a0\u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u0430:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9df\/3b9\/2ef\/9df3b92ef77114957dec65310caa756d.png\" width=\"500\" height=\"298\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9df\/3b9\/2ef\/9df3b92ef77114957dec65310caa756d.png\"\/><\/figure>\n<p>\u0412\u00a0\u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u00a0\u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u00a0\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0441\u0442\u0430\u0442\u0443\u0441 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u0435\u0440\u0435\u0434 \u043d\u0430\u0447\u0430\u043b\u043e\u043c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438:<\/p>\n<pre><code class=\"swift\">private func checkAvailability() async -&gt; Bool {     if !HKHealthStore.isHealthDataAvailable() {         self.error = .unavailable         return false     }          do {         let status = try await healthStore?.statusForAuthorizationRequest(toShare: typesToShare, read: typesToRead)         if status == .unnecessary {             return true         }                  if status == .shouldRequest {             await self.requestAuthorization()             return true         }                  self.error = .permissionDenied         return false              } catch(let error) {         self.error = .requestPermissionError(error)         return false     } } <\/code><\/pre>\n<h3>\u041d\u0430\u0447\u0430\u043b\u043e \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0443\u00a0\u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0443, \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438:<\/p>\n<ol>\n<li>\n<p>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\">HKWorkoutSession<\/a><\/p>\n<\/li>\n<li>\n<p>\u0418\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\">HKLiveWorkoutBuilder<\/a> \u0438\u0437\u00a0\u0441\u0435\u0430\u043d\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutdatasource\">HKLiveWorkoutDataSource<\/a> \u0431\u0438\u043b\u0434\u0435\u0440\u0443 <\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\">HKWorkoutSessionDelegate<\/a> \u0434\u043b\u044f\u00a0\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\">HKLiveWorkoutBuilderDelegate<\/a> \u0434\u043b\u044f\u00a0\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0431\u0438\u043b\u0434\u0435\u0440\u0430<\/p>\n<\/li>\n<li>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0435\u0430\u043d\u0441\u0430 \u0438 \u043d\u0430\u0447\u0430\u043b\u043e \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"swift\">func startWorkout(with configuration: HKWorkoutConfiguration) async {     let result = await self.checkAvailability()     if !result {         return     }     guard let healthStore else {         self.error = .unavailable         return     }      if !self.supportedWorkoutTypes.contains(configuration.activityType) {         self.error = .workoutTypeNotSupported         return     }           do {         session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)         builder = session?.associatedWorkoutBuilder()     } catch(let error) {         self.error = .startWorkoutFailed(error)         return     }     builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration) \/\/        print(\"types to collect: \", builder?.dataSource?.typesToCollect as Any)          \/\/ \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: respiratoryRate     \/\/ builder?.dataSource?.enableCollection(for: HKQuantityType(.respiratoryRate), predicate: nil)      \/\/ \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u0435\u0430\u043d\u0441\u0430 \u0438 \u0431\u0438\u043b\u0434\u0435\u0440\u0430     session?.delegate = self     builder?.delegate = self          \/\/ \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u043a\u0442\u0438\u0432\u0438\u0442\u0438     let date = Date()     session?.startActivity(with: date)          do {         try await builder?.beginCollection(at: date)         self.workoutMetrics = .init(workoutConfiguration: configuration)     } catch(let error) {         self.error = .startWorkoutFailed(error)         reset()     } }<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043c\u043d\u043e\u0433\u043e \u0432\u0441\u0435\u0433\u043e \u0432 \u043e\u0434\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438!  <\/p>\n<p>\u0427\u0435\u0440\u0435\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u043a\u0443\u043d\u0434 \u043c\u044b \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u2011\u0434\u0435\u043b\u0435\u0433\u0430\u0442\u044b, \u043d\u043e\u00a0\u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c\u0441\u044f \u043d\u0430\u00a0\u0434\u0440\u0443\u0433\u0438\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445.<\/p>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\">HKWorkoutSession<\/a>, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u044b \u0434\u0432\u0435 \u0432\u0435\u0449\u0438: \u043d\u0430\u0448 HKHealthStore \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\">HKWorkoutConfiguration<\/a>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0438\u0437\u00a0\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u0441\u043e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f\u00a0\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0435\u0433\u043e \u0434\u043b\u044f\u00a0\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0438\u043f\u0430 \u0430\u043a\u0442\u0438\u0432\u0438\u0442\u0438 \u0438 \u043c\u0435\u0441\u0442\u0430 \u0434\u043b\u044f\u00a0\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u0447\u0442\u043e\u0431\u044b Apple Watch \u043c\u043e\u0433\u043b\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u043a\u0430\u043b\u043e\u0440\u0438\u0439 \u0432\u00a0\u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441\u00a0\u043d\u0430\u0448\u0435\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0435\u0439.<\/p>\n<pre><code class=\"swift\">let configuration = HKWorkoutConfiguration() configuration.activityType = .running configuration.locationType = .outdoor<\/code><\/pre>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/activitytype\">activityType<\/a> \u0437\u0430\u0434\u0430\u0435\u0442 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutactivitytype\">HKWorkoutActivityType<\/a> \u0441\u0435\u0430\u043d\u0441\u0430.<\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c, \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u0432\u0438\u0441\u0435\u0442\u044c \u043e\u0442\u00a0\u0442\u0438\u043f\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f\u00a0\u043f\u043b\u0430\u0432\u0430\u043d\u0438\u044f (<a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutactivitytype\/swimming\">swimming<\/a>) \u0432\u043c\u0435\u0441\u0442\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/locationtype\">LocationType<\/a> \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/swimminglocationtype\">swimmingLocationType<\/a>. \u0418 \u0435\u0441\u043b\u0438 \u0434\u043b\u044f <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/swimminglocationtype\">swimmingLocationType<\/a> \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutswimminglocationtype\/pool\">pool<\/a>, \u043d\u0430\u043c \u0442\u0430\u043a\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/laplength\">lapLength<\/a>.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043d\u0430\u0448\u0435\u0439 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\">HKWorkoutSession<\/a>, \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\">HKLiveWorkoutBuilder<\/a> \u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\/datasource\">dataSource<\/a>.<\/p>\n<p>\u0412\u0430\u0436\u043d\u043e \u043e\u0442\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e\u00a0Apple Watch \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u00a0\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u00a0\u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutconfiguration\/activitytype\">activityType<\/a>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0441\u0435\u0430\u043d\u0441\u0430 \u0431\u0435\u0433\u0430 \u043d\u0430\u00a0\u0441\u0432\u0435\u0436\u0435\u043c \u0432\u043e\u0437\u0434\u0443\u0445\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u0444\u0438\u043a\u0441\u0438\u0440\u0443\u0435\u0442 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytypeidentifier\/activeenergyburned\">activeEnergyBurned<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytypeidentifier\/basalenergyburned\">basalEnergyBurned<\/a>, <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytypeidentifier\/heartrate\">heartRate<\/a>, \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytypeidentifier\/distancewalkingrunning\">distanceWalkingRunning<\/a>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0443\u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0432\u00a0\u043a\u0430\u043a\u043e\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u00a0\u0431\u0438\u043b\u0434\u0435\u0440, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutdatasource\/typestocollect\">builder.dataSource.typesToCollect<\/a>.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f\u00a0\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0431\u043e\u0440\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0435\u0442\u043e\u0434 <code>enableCollection(for:predicate:)<\/code> \u0438 \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0441\u0431\u043e\u0440 \u0441\u00a0\u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 <code>disableCollection(for:)<\/code>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u00a0\u0447\u0430\u0441\u0442\u043e\u0442\u0435 \u0434\u044b\u0445\u0430\u043d\u0438\u044f <code>respiratoryRate<\/code>, \u043d\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445:<\/p>\n<pre><code class=\"swift\">builder?.dataSource?.enableCollection(for: HKQuantityType(.respiratoryRate), predicate: nil)<\/code><\/pre>\n<p>\u0412\u0441\u043a\u043e\u0440\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u0432, \u043d\u043e\u00a0\u043f\u043e\u043a\u0430 \u0447\u0442\u043e\u00a0\u043f\u043e\u00a0\u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0441\u0435\u0430\u043d\u0441 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442 \u0432\u0441\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0432\u00a0\u0431\u0438\u043b\u0434\u0435\u0440. \u042d\u0442\u043e \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e\u00a0\u043e\u0431\u0430 \u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0430 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442\u00a0\u0436\u0435 \u043d\u0430\u0431\u043e\u0440 \u0441\u043e\u0431\u044b\u0442\u0438\u0439. \u041e\u0434\u043d\u0430\u043a\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\/shouldcollectworkoutevents\">shouldCollectWorkoutEvents<\/a> \u0431\u0438\u043b\u0434\u0435\u0440\u0430 \u0432 <a href=\"https:\/\/developer.apple.com\/documentation\/swift\/false\">false<\/a>, \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0435 \u0432\u00a0\u043d\u0435\u0433\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043c\u044b \u043d\u0430\u043a\u043e\u043d\u0435\u0446\u2011\u0442\u043e \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\/3017314-startactivity\">startActivity(with:)<\/a> \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/2962913-begincollection\">beginCollection(at:)<\/a>, \u0447\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0430\u043a\u0442\u0438\u0432\u0438\u0442\u0438 \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u0431\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<p>\u041d\u0430\u0448\u0430 <code>workoutMetrics<\/code>\u00a0\u2014 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0443\u044e \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u043d\u0430\u00a0\u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0433\u043e \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<h3>\u041f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0438 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0430\u043d\u0441\u0430<\/h3>\n<p>\u0414\u043b\u044f\u00a0\u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u043a\u043e\u0434\u0430!<\/p>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u0437\u043e\u0432\u0438\u0442\u0435 \u043c\u0435\u0442\u043e\u0434\u044b <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\/2962934-pause\">pause()<\/a> \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\/2962935-resume\">resume()<\/a> <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\">HKWorkoutSession<\/a>.<\/p>\n<pre><code class=\"swift\">func resumeSession() {     session?.resume() }  func pauseSession() {     session?.pause() }<\/code><\/pre>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043e\u0431\u043b\u0430\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u043d\u0435\u00a0\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0448\u0438\u043c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c view. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0433\u0434\u0435 \u0435\u0449\u0435 \u0438\u0445 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<h3>\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 (\u0428\u0430\u0433 1)<\/h3>\n<p>\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043c\u043d\u043e\u0433\u043e\u044d\u0442\u0430\u043f\u043d\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441. <\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e, \u0432\u00a0\u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442\u00a0\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u0435\u0430\u043d\u0441\u0430, \u044d\u0442\u0438 \u0448\u0430\u0433\u0438 \u043d\u0435\u00a0\u043c\u043e\u0433\u0443\u0442\u00a0\u0431\u044b\u0442\u044c \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u044b \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0442\u043e \u0435\u0441\u0442\u044c \u0432\u00a0\u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438. \u041f\u0435\u0440\u0432\u044b\u0439 \u0448\u0430\u0433\u00a0\u2014 \u0432\u044b\u0437\u043e\u0432 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\/2962932-end\">end()<\/a> \u0434\u043b\u044f\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsession\">HKWorkoutSession<\/a>.<\/p>\n<pre><code class=\"swift\">func endSession() {     session?.end() }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043c \u0431\u0438\u043b\u0434\u0435\u0440 \u0438 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0443, \u0443\u0431\u0435\u0434\u0438\u0432\u0448\u0438\u0441\u044c, \u0447\u0442\u043e\u00a0\u0441\u0435\u0441\u0441\u0438\u044f \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0430 \u0432\u00a0\u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0430\u0448\u0438\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439\u2011\u0434\u0435\u043b\u0435\u0433\u0430\u0442\u043e\u0432.<\/p>\n<h3>HKWorkoutSessionDelegate<\/h3>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\">HKWorkoutSessionDelegate<\/a> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u0438\u00a0\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0435\u0430\u043d\u0441\u0430.<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438\u00a0\u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0412\u00a0\u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0441\u0435\u0430\u043d\u0441\u0430 \u0441\u00a0\u043e\u0448\u0438\u0431\u043a\u043e\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u041e\u043d \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f\u00a0\u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f HKWorkoutSession, \u0438\u0437\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u0435\u0440\u0432\u044b\u0435 \u0434\u0432\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\/workoutsession(_:didchangeto:from:date:)\">workoutSession(_:didChangeTo:from:date:)<\/a> \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438\u00a0\u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0441\u0435\u0430\u043d\u0441\u0430<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\/workoutsession(_:didfailwitherror:)\">workoutSession(_:didFailWithError:)<\/a> \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u044f\u0435\u0442 \u043d\u0430\u0441, \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u0448 \u0441\u0435\u0430\u043d\u0441\u00a0\u0431\u044b\u043b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0441\u00a0\u043e\u0448\u0438\u0431\u043a\u043e\u0439<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\/workoutsession(_:didgenerate:)\">workoutSession(_:didGenerate:)<\/a> \u043a\u043e\u0433\u0434\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\/workoutsession(_:didbeginactivitywith:date:)\">workoutSession(_:didBeginActivityWith:date:)<\/a> \u043f\u0440\u0438\u00a0\u043d\u0430\u0447\u0430\u043b\u0435 \u043d\u043e\u0432\u043e\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessiondelegate\/workoutsession(_:didendactivitywith:date:)\">workoutSession(_:didEndActivityWith:date:)<\/a> \u043f\u0440\u0438\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0412\u00a0\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0433\u043b\u0430\u0432\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430\u00a0\u043f\u0435\u0440\u0432\u043e\u043c \u0438\u0437\u00a0\u043d\u0438\u0445. \u0412\u00a0\u044d\u0442\u043e\u043c \u043c\u0435\u0442\u043e\u0434\u0435 \u043c\u044b:<\/p>\n<ol>\n<li>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>sessionRunning<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f\u00a0\u043b\u0438 \u0441\u0435\u0430\u043d\u0441 \u0432\u00a0\u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessionstate\">HKWorkoutSessionState<\/a> \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutsessionstate\/ended\">ended<\/a>, \u0447\u0442\u043e\u00a0\u0441\u0432\u0438\u0434\u0435\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u043c\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u044b \u0431\u0438\u043b\u0434\u0435\u0440\u0430 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/endcollection(withend:completion:)\">endCollection(withEnd:)<\/a> \u0438 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/finishworkout(completion:)\">finishWorkout()<\/a> \u0434\u043b\u044f\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"swift\">nonisolated func workoutSession(_ workoutSession: HKWorkoutSession, didChangeTo toState: HKWorkoutSessionState, from fromState: HKWorkoutSessionState, date: Date) {          DispatchQueue.main.async {         self.sessionRunning = (toState == .running)     }     \/\/ \u0414\u043e\u0436\u0434\u0438\u0442\u0435\u0441\u044c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0441\u0435\u0430\u043d\u0441\u0430 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0443 \u0431\u0438\u043b\u0434\u0435\u0440\u0430.     if toState == .ended {         Task {             do {                 try await builder?.endCollection(at: date)                 let workout = try await builder?.finishWorkout()                 DispatchQueue.main.async {                     self.workoutResult = workout                 }             } catch(let error) {                 self.setError(.endWorkFailed(error))                 return             }                      }     } }<\/code><\/pre>\n<p>\u041c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/finishworkout(completion:)\">finishWorkout()<\/a> \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043a\u0442 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkout\">HKWorkout<\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u00a0\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0435. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u044d\u0442\u043e\u0442 \u0432\u043e\u043f\u0440\u043e\u0441, \u043a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a\u00a0\u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043d\u0430\u0448\u0435\u0433\u043e view.<\/p>\n<h3>HKLiveWorkoutBuilderDelegate<\/h3>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\">HKLiveWorkoutBuilderDelegate<\/a> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f\u00a0\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0437\u0430\u043f\u0443\u0449\u0435\u043d\u043d\u044b\u0445 \u0431\u0438\u043b\u0434\u0435\u0440\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 (\u0432\u044b\u0431\u043e\u0440\u043e\u043a) \u0438\u043b\u0438\u00a0\u0434\u043b\u044f\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0439 \u043e\u00a0\u043d\u043e\u0432\u043e\u043c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutevent\">HKWorkoutEvent<\/a>.<\/p>\n<p>\u0412\u00a0\u043d\u0430\u0448\u0435\u043c \u0440\u0430\u0441\u043f\u043e\u0440\u044f\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u043e\u0434\u043e\u0432 \u0434\u0435\u043b\u0435\u0433\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0438\u0437\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0432\u044b\u0435 \u0434\u0432\u0430:<\/p>\n<ul>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilder(_:didcollectdataof:)\">workoutBuilder(_:didCollectDataOf:)<\/a> \u0434\u043b\u044f\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilderdidcollectevent(_:)\">workoutBuilderDidCollectEvent(_:)<\/a> \u043a\u043e\u0433\u0434\u0430 \u0432\u00a0\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u043d\u043e\u0432\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilder(_:didbegin:)\">workoutBuilder(_:didBegin:)<\/a> \u0437\u0430\u043f\u0443\u0441\u043a \u043d\u043e\u0432\u043e\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilder(_:didend:)\">workoutBuilder(_:didEnd:)<\/a> \u043f\u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilder(_:didcollectdataof:)\">workoutBuilder(_:didCollectDataOf:)<\/a> \u0438 \u0432\u044b\u044f\u0441\u043d\u0438\u043c, \u043a\u0430\u043a\u00a0\u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c HKSampleType.<\/p>\n<p>\u042f \u043f\u043e\u043b\u0430\u0433\u0430\u044e, \u0447\u0442\u043e\u00a0\u044d\u0442\u043e\u0442 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u043d\u0438\u043a\u0430\u043b\u0435\u043d \u0434\u043b\u044f\u00a0HealthKit, \u0438 \u0432\u00a0\u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u043c\u044b \u0442\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0438 HKWorkout\u2011\u0434\u0430\u043d\u043d\u044b\u0435 (\u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435) \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<pre><code class=\"swift\">nonisolated func workoutBuilder(_ workoutBuilder: HKLiveWorkoutBuilder, didCollectDataOf collectedTypes: Set&lt;HKSampleType&gt;) {     for type in collectedTypes {         guard let quantityType = type as? HKQuantityType else {             return         }         let statistics = workoutBuilder.statistics(for: quantityType)         updateMetrics(statistics)     }  }<\/code><\/pre>\n<p>\u0412\u00a0\u043d\u0430\u0448\u0435\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u2011\u0434\u0435\u043b\u0435\u0433\u0430\u0442\u0435 \u043c\u044b \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f\u00a0\u043b\u0438 \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u044b\u0439 \u0442\u0438\u043f \u043a\u00a0<code>HKQuantityType<\/code>. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e \u0442\u0430\u043a, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0434\u043b\u044f\u00a0\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0435\u0442\u043e\u0434 \u0431\u0438\u043b\u0434\u0435\u0440\u0430 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/statistics(for:)\">statistics(for:)<\/a>.<\/p>\n<p>\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0430\u044f \u0432\u00a0\u0444\u043e\u0440\u043c\u0430\u0442\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkstatistics\">HKStatistics<\/a>, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e, \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0433\u043e, \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u043b\u0438\u00a0\u0441\u0443\u043c\u043c\u044b \u043f\u043e\u00a0\u043d\u0430\u0431\u043e\u0440\u0443 \u0432\u044b\u0431\u043e\u0440\u043e\u043a \u0438\u0437\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 HealthKit.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u044c \u044d\u0442\u0443 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0434\u043b\u044f\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkstatistics\/quantitytype\">quantityType<\/a> \u0432\u044b\u0431\u043e\u0440\u043e\u043a, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0434\u043b\u044f\u00a0\u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantity\">HKQuantity<\/a> \u0432\u00a0\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442\u00a0\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0437\u0432\u043b\u0435\u0447\u044c <code>Double<\/code>\u2011\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437\u00a0\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e <code>HKQuantity<\/code>, \u0443\u043a\u0430\u0437\u0430\u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkunit\">HKUnit<\/a>.<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"swift\">extension HKStatistics {     static var heartRateUnit: HKUnit {         HKUnit.count().unitDivided(by: HKUnit.minute())     }          static var energyUnit: HKUnit {         HKUnit.kilocalorie()     }          static var distanceUnit: HKUnit {         HKUnit.meter()     }          static var speedUnit: HKUnit {         HKUnit.meter().unitDivided(by: HKUnit.second())     }          static  var countUnit: HKUnit {         HKUnit.count()     }      var heartRate: Double {         if self.quantityType == HKQuantityType(.heartRate) {             return self.mostRecentQuantity()?.doubleValue(for: Self.heartRateUnit) ?? 0         }         return 0     }          var averageHeartRate: Double {         if self.quantityType == HKQuantityType(.heartRate) {             return self.averageQuantity()?.doubleValue(for: Self.heartRateUnit) ?? 0         }         return 0     }          var activeEnergyBurned: Double {         if self.quantityType == HKQuantityType(.activeEnergyBurned) {             return self.sumQuantity()?.doubleValue(for: Self.energyUnit) ?? 0         }         return 0     }          var totalDistance: Double {         if self.quantityType == HKQuantityType(.distanceWalkingRunning) ||             self.quantityType == HKQuantityType(.distanceCycling) ||             self.quantityType == HKQuantityType(.distanceSwimming) {             return self.sumQuantity()?.doubleValue(for: Self.distanceUnit) ?? 0         }         return 0     }          var speed: Double {         if self.quantityType == HKQuantityType(.walkingSpeed) ||             self.quantityType == HKQuantityType(.runningSpeed) ||             self.quantityType == HKQuantityType(.cyclingSpeed) {             return self.mostRecentQuantity()?.doubleValue(for: Self.speedUnit) ?? 0         }         return 0     }          var averageSpeed: Double {         if self.quantityType == HKQuantityType(.walkingSpeed) ||             self.quantityType == HKQuantityType(.runningSpeed) ||             self.quantityType == HKQuantityType(.cyclingSpeed) {             return self.averageQuantity()?.doubleValue(for: Self.speedUnit) ?? 0         }         return 0     }          var stepCount: Double {         if self.quantityType == HKQuantityType(.stepCount) {             return self.sumQuantity()?.doubleValue(for: Self.countUnit) ?? 0         }         return 0     }          var strokeCount: Double {         if self.quantityType == HKQuantityType(.swimmingStrokeCount) {             return self.sumQuantity()?.doubleValue(for: Self.countUnit) ?? 0         }         return 0     } }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 <code>extension<\/code> \u0434\u043b\u044f\u00a0\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0430\u0448\u0438\u0445 <code>workoutMetrics <\/code>\u0432\u043e\u00a0\u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>updateMetrics<\/code>.<\/p>\n<p><strong>\u0414\u0432\u0438\u0436\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u0435\u0435!<\/strong><\/p>\n<p>\u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435, \u043d\u043e\u00a0\u043d\u0435\u00a0\u043c\u0435\u043d\u0435\u0435 \u0432\u0430\u0436\u043d\u043e\u0435: \u043d\u0430\u0448 \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilderdidcollectevent(_:)\">workoutBuilderDidCollectEvent(_:)<\/a>!<\/p>\n<p>\u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043f\u043e\u0442\u0440\u044f\u0441\u0430\u044e\u0449\u0438\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044f\u043c watchOS, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f\u00a0\u043d\u0430\u0441 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0432\u0438\u0434\u0436\u0435\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u0435 \u0432\u0440\u0435\u043c\u044f (\u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u043e\u0435 \u0441\u00a0\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b) \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0434\u043b\u044f\u00a0\u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a7e\/99f\/64c\/a7e99f64c25ba231df5334a091304214.gif\" width=\"250\" height=\"298\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a7e\/99f\/64c\/a7e99f64c25ba231df5334a091304214.gif\"\/><\/figure>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u044d\u0442\u0430 \u043a\u043d\u043e\u043f\u043a\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u041d\u0415\u00a0\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u0438 \u043d\u0435\u00a0\u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u0435\u0430\u043d\u0441. (\u041e\u0447\u0435\u0432\u0438\u0434\u043d\u043e\u2026 \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e\u00a0\u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043f\u043e\u043d\u044f\u0442\u0438\u044f \u043d\u0435\u00a0\u0438\u043c\u0435\u0435\u0442 \u043e\u00a0\u0442\u043e\u043c, \u043a\u0430\u043a\u00a0\u043c\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u044d\u0442\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0432\u00a0\u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438!)<\/p>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 HKWorkoutEvent \u0432\u00a0\u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u00a0\u0442\u0438\u043f\u043e\u043c \u0441\u043e\u0431\u044b\u0442\u0438\u044f (<a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkouteventtype\">HKWorkoutEventType<\/a>) <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkouteventtype\/pauseorresumerequest\">pauseOrResumeRequest<\/a>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0432\u044f\u0437\u0430\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u00a0\u043d\u0430\u0448\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0438\u043b\u0438\u00a0\u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0435\u0430\u043d\u0441, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u044d\u0442\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0432\u00a0\u043d\u0430\u0448\u0435\u043c <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilderdelegate\/workoutbuilderdidcollectevent(_:)\">\u043c\u0435\u0442\u043e\u0434\u0435 workoutBuilderDidCollectEvent(_:)<\/a>.<\/p>\n<pre><code class=\"swift\">nonisolated func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {     if let event = workoutBuilder.workoutEvents.last {         DispatchQueue.main.async(execute: {             switch event.type {             case .pauseOrResumeRequest:                 self.sessionRunning ? self.pauseSession() : self.resumeSession()                 break             default:                 break             }         })     } }<\/code><\/pre>\n<h3>\u0417\u0430\u0442\u0440\u0430\u0447\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f<\/h3>\n<p>\u0412\u044b\u0448\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0435\u0430\u043d\u0441\u0430 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u00a0\u043d\u0438\u043c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0445!<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u0435\u0441\u0442\u044c \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u0432\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u043d\u0430\u00a0\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u044f \u0445\u043e\u0442\u0435\u043b\u00a0\u0431\u044b \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0430\u0448\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435! \u041d\u0430\u0448\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>getElapseTime<\/code>.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u0443\u00a0\u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430:<\/p>\n<ol>\n<li>\n<p>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\/elapsedtime\">elapsedTime<\/a>, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0435 \u0432 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\">HKLiveWorkoutBuilde<\/a>.<\/p>\n<\/li>\n<li>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/2962916-elapsedtime\">elapsedTime(at:)<\/a> \u0438\u0437 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkliveworkoutbuilder\">HKLiveWorkoutBuilde<\/a>.<\/p>\n<\/li>\n<\/ol>\n<p>\u041a\u043b\u044e\u0447\u0435\u0432\u043e\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0438\u0435 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432\u00a0\u0442\u043e\u043c, \u0447\u0442\u043e\u00a0\u043f\u0435\u0440\u0432\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0431\u0449\u0443\u044e \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 <strong>\u0441\u00a0\u0443\u0447\u0435\u0442\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043f\u043e\u0442\u0440\u0430\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043d\u0430\u00a0\u043f\u0430\u0443\u0437\u044b<\/strong>. \u0422\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u00a0\u0432\u0442\u043e\u0440\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u0430\u0441\u0442 \u043d\u0430\u043c \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c <strong>\u0431\u0435\u0437\u00a0\u0443\u0447\u0435\u0442\u0430 \u044d\u0442\u0438\u0445 \u043f\u0435\u0440\u0438\u043e\u0434\u043e\u0432<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u044b \u043c\u0435\u0436\u0434\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044f\u043c\u0438 \u043f\u0430\u0443\u0437\u044b \u0438 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f.<\/p>\n<h2>View<\/h2>\n<p>\u041d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u0437\u044f\u0442\u044c\u0441\u044f \u0437\u0430\u00a0view!<\/p>\n<pre><code class=\"swift\">import SwiftUI import HealthKit  struct NewWorkoutView: View {     @Environment(WorkoutManager.self) private var workoutManager     @State private var selectedWorkoutType: HKWorkoutActivityType? = nil     @State private var showConfigurationSheet: Bool = false          @State private var swimLocation: HKWorkoutSwimmingLocationType = .pool     @State private var lapLength: Int = 400     @State private var activityLocation: HKWorkoutSessionLocationType = .outdoor      var body: some View {         @Bindable var workoutManager = workoutManager         let supportedWorkoutTypes = Array(workoutManager.supportedWorkoutTypes)         List {             if let error = workoutManager.error {                 Text(error.message)                     .foregroundStyle(.red)             }                          ForEach(0..&lt;supportedWorkoutTypes.count, id: \\.self) { index in                 let workoutType = supportedWorkoutTypes[index]                 Button(action: {                     selectedWorkoutType = workoutType                     showConfigurationSheet = true                 }, label: {                     Text(workoutType.string)                 })             }         }         .scrollIndicators(.hidden)         .sheet(isPresented: $showConfigurationSheet, content:  {              VStack(alignment: .leading, spacing: 8) {                 if let selectedWorkoutType {                     if selectedWorkoutType == .swimming {                         List {                             Picker(selection: $swimLocation, content: {                                 Text(\"Open water\")                                     .tag(HKWorkoutSwimmingLocationType.openWater)                                 Text(\"Pool\")                                     .tag(HKWorkoutSwimmingLocationType.pool)                              }, label: {                                 Text(\"Swim Location\")                             })                          }                         .frame(height: 56)                         .scrollIndicators(.hidden)                         .scrollDisabled(true)                                                   HStack {                             Text(\"Lap Length(m)\")                                 .padding(.leading, 4)                                 .lineLimit(1)                                 .minimumScaleFactor(0.7)                             TextField(\"\", value: $lapLength, format: .number)                         }                               } else {                         Form {                             Picker(selection: $activityLocation, content: {                                 Text(\"Indoor\")                                     .tag(HKWorkoutSessionLocationType.indoor)                                 Text(\"Outdoor\")                                     .tag(HKWorkoutSessionLocationType.outdoor)                                                              }, label: {                                 Text(\"Activity Location\")                             })                                                      }                     }                                          if let error = workoutManager.error {                         Text(error.message)                             .foregroundStyle(.red)                             .padding(.leading, 4)                             .lineLimit(1)                             .minimumScaleFactor(0.8)                     }                                          HStack(spacing: 8) {                         Button(action: {                             showConfigurationSheet = false                         }, label: {                             Text(\"Cancel\")                                 .foregroundStyle(.red)                                 .padding(.all, 4)                                 .contentShape(Rectangle())                          })                                                  Button(action: {                             Task {                                 let configuration = HKWorkoutConfiguration()                                 configuration.activityType = selectedWorkoutType                                 if selectedWorkoutType == .swimming {                                     configuration.swimmingLocationType = swimLocation                                     configuration.lapLength = HKQuantity(unit: HKUnit.meter(), doubleValue: Double(lapLength))                                 } else {                                     configuration.locationType = activityLocation                                 }                                 await workoutManager.startWorkout(with: configuration)                                 showConfigurationSheet = false                             }                          }, label: {                             Text(\"Start\")                                 .foregroundStyle(.blue)                                 .padding(.all, 4)                                 .contentShape(Rectangle())                         })                                              }                     .padding(.trailing, 4)                     .fontWeight(.semibold)                     .buttonStyle(.plain)                     .frame(maxWidth: .infinity, alignment: .trailing)                  }             }             .font(.system(size: 12))             .frame(maxHeight: .infinity, alignment: .top)             .toolbarVisibility(.hidden, for: .navigationBar)             .interactiveDismissDisabled()         })         .onChange(of: showConfigurationSheet, {             if !showConfigurationSheet {                 selectedWorkoutType = nil             }         })         .navigationTitle(\"New Workout\")         .navigationDestination(item: $workoutManager.workoutMetrics, destination: { _ in                 WorkoutProgressView()                     .environment(workoutManager)         })         .sheet(isPresented: $workoutManager.showResult) {             WorkoutResultView()                 .environment(workoutManager)                 .toolbarVisibility(.hidden, for: .navigationBar)         }     } }  struct WorkoutProgressView: View {     @Environment(WorkoutManager.self) private var workoutManager     @State private var currentDate: Date = Date()     private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()      @State private var showControl: Bool = false     @State private var showProgressView: Bool = false      var body: some View {          ZStack {              if showProgressView {                 ProgressView()                     .controlSize(.extraLarge)                     .frame(maxWidth: .infinity, maxHeight: .infinity)                     .contentShape(Rectangle())             }                          if let metrics = workoutManager.workoutMetrics {                 VStack(alignment: .leading) {                     HStack {                         Text(workoutManager.getElapseTime(at: currentDate).hourMinuteSecond)                             .font(.title2)                             .fontWeight(.semibold)                         Spacer()                                                                           Button(action: {                             showControl.toggle()                         }, label: {                             Image(systemName: \"ellipsis\")                                 .rotationEffect(.degrees(showControl ? 90 : 0))                                 .frame(width: 32, height: 32)                                 .background(Circle().fill(.gray))                         })                         .overlay(alignment: .top, content: {                             if showControl {                                 let sessionRunning = workoutManager.sessionRunning                                 VStack(spacing: 8) {                                     Button(action: {                                         sessionRunning ? workoutManager.pauseSession() : workoutManager.resumeSession()                                     }, label: {                                         Image(systemName: sessionRunning ? \"pause.fill\" : \"arrow.clockwise\")                                             .frame(width: 32, height: 32)                                             .background(Circle().fill(.gray))                                     })                                                                          Button(action: {                                         workoutManager.endSession()                                         self.showProgressView = true                                     }, label: {                                         Image(systemName: \"stop.fill\")                                             .frame(width: 32, height: 32)                                             .background(Circle().fill(.gray))                                     })                                  }                                 .padding(.top, 40)                             }                         })                         .buttonStyle(.plain)                     }                      Text(metrics.distance.formatted(.number.precision(.fractionLength(0))) + \" \\(HKStatistics.distanceUnit.unitString)\")                     Text(metrics.energyBurned.formatted(.number.precision(.fractionLength(0))) + \" \\(HKStatistics.energyUnit.unitString)\")                     Text(metrics.heartRate.formatted(.number.precision(.fractionLength(0))) + \" bpm\")                     if metrics.workoutConfiguration.activityType == .swimming {                         Text(metrics.stepStrokeCount.formatted(.number.precision(.fractionLength(0))) + \" strokes\")                     }                     if metrics.workoutConfiguration.activityType == .walking || metrics.workoutConfiguration.activityType == .running || metrics.workoutConfiguration.activityType == .highIntensityIntervalTraining {                         Text(metrics.stepStrokeCount.formatted(.number.precision(.fractionLength(0))) + \" steps\")                     }                 }                 .onReceive(timer) { input in                     currentDate = input                 }                 .disabled(showProgressView)                 .navigationTitle(\"\\(metrics.workoutConfiguration.activityType.string)\")                 .navigationBarTitleDisplayMode(.inline)             }         }         .navigationBarBackButtonHidden(true)         .onTapGesture {             self.showControl = false         }     } }  struct WorkoutResultView: View {     @Environment(WorkoutManager.self) private var workoutManager      var body: some View {                  if let result = workoutManager.workoutResult {             ScrollView {                  HKWorkoutView(workout: result)                                  Spacer()                     .frame(height: 8)                                  Button(action: {                     workoutManager.showResult = false                 }, label: {                    Text(\"Done\")                 })              }         }     } }   struct HKWorkoutView: View {     var workout: HKWorkout          var body: some View {         VStack(alignment: .leading, spacing: 8) {             Text(\"\\(workout.workoutActivityType.string) Summary\")                 .font(.title3)                 .fontWeight(.bold)              Text(\"**Duration:** \\(workout.duration.hourMinuteSecond)\" )                           let distanceStatistics = switch workout.workoutActivityType {             case .cycling:                 workout.statistics(for: HKQuantityType(.distanceCycling))             case .swimming:                 workout.statistics(for: HKQuantityType(.distanceSwimming))             default:                 workout.statistics(for: HKQuantityType(.distanceWalkingRunning))             }             if let distanceStatistics {                 Text(\"**Total Distance:** \\(distanceStatistics.totalDistance.formatted(.number.precision(.fractionLength(0)))) \\(HKStatistics.distanceUnit.unitString)\" )             }                          if let energyStatistics = workout.statistics(for: HKQuantityType(.activeEnergyBurned)) {                 Text(\"**Energy Burnt:** \\(energyStatistics.activeEnergyBurned.formatted(.number.precision(.fractionLength(0)))) \\(HKStatistics.energyUnit.unitString)\" )             }                          if let heartRateStatistics = workout.statistics(for: HKQuantityType(.heartRate)) {                 Text(\"**Avg. Heart Rate:** \\(heartRateStatistics.averageHeartRate.formatted(.number.precision(.fractionLength(0)))) bpm\" )             }                          if let stepCountStatistics = workout.statistics(for: HKQuantityType(.stepCount)) {                 Text(\"**Steps:** \\(stepCountStatistics.stepCount.formatted(.number.precision(.fractionLength(0))))\" )              }                          if let strokeCountStatistics = workout.statistics(for: HKQuantityType(.swimmingStrokeCount)) {                 Text(\"**Strokes:** \\(strokeCountStatistics.strokeCount.formatted(.number.precision(.fractionLength(0))))\" )             }         }         .frame(maxWidth: .infinity, alignment: .leading)      } }  extension TimeInterval {     var hourMinuteSecond: String {         let interval = Int(self)         let seconds = interval % 60         let minutes = (interval \/ 60) % 60         let hours = (interval \/ (60*60)) % 60         return String(format: \"%02d:%02d:%02d\", hours, minutes, seconds)     } }  extension HKWorkoutActivityType {      var string: String {         switch self {         case .walking:             return \"Walking\"         case .running:             return \"Running\"         case .cycling:             return \"Cycling\"         case .swimming:             return \"Swimming\"         case .swimBikeRun:             return \"Triathlon\"         case .highIntensityIntervalTraining:             return \"Interval Training\"         default:             return \"(not supported)\"         }     } }<\/code><\/pre>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435 (\u0438 \u043d\u0430\u0448\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0\u0441\u0435\u0433\u043e\u0434\u043d\u044f)! \u0425\u043e\u0447\u0443 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u0430\u0448\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430\u00a0\u0442\u043e, \u043a\u0430\u043a\u00a0\u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c <code>HKStatistics <\/code>\u0438\u0437\u00a0<code>HKWorkout<\/code>!<\/p>\n<p>\u041f\u043e\u0434\u043e\u0431\u043d\u043e \u0442\u043e\u043c\u0443, \u043a\u0430\u043a\u00a0\u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkoutbuilder\/statistics(for:)\">statistics(for:)<\/a> \u0432\u00a0\u0431\u0438\u043b\u0434\u0435\u0440\u0435, \u0432\u00a0<code>HKWorkout <\/code>\u0442\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkworkout\/3929754-statistics\">statistics(for:)<\/a>. \u041c\u044b \u043f\u0440\u043e\u0441\u0442\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0439 \u043d\u0430\u0441 <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/hkquantitytype\">HKQuantityType<\/a> \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430\u0448\u0443 <code>HKStatistics<\/code>!<\/p>\n<p>\u0421\u00a0\u044d\u0442\u043e\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0442\u043e\u0447\u043d\u043e \u0442\u0430\u043a\u00a0\u0436\u0435, \u043a\u0430\u043a\u00a0\u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0440\u0430\u043d\u0435\u0435.<\/p>\n<p>\u0412\u043e\u0442 \u0438 \u0432\u0441\u0451!<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0434\u0435\u0442\u044c \u0447\u0430\u0441\u044b \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043d\u0430\u00a0\u043f\u0440\u043e\u0431\u0435\u0436\u043a\u0443!<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/889\/ffb\/a2b\/889ffba2b248aeebaf24ef7f12d38440.gif\" width=\"250\" height=\"298\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/889\/ffb\/a2b\/889ffba2b248aeebaf24ef7f12d38440.gif\"\/><\/figure>\n<p>\u0412\u0443\u0430\u043b\u044f! \u042f \u043f\u0440\u043e\u0435\u0445\u0430\u043b 7\u00a0\u0441\u0435\u043a\u0443\u043d\u0434 (\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0433\u043e\u0432\u043e\u0440\u044f, \u043c\u043e\u0436\u0435\u0442\u00a0\u0431\u044b\u0442\u044c, \u0432\u0441\u0435\u0433\u043e 6?) \u043d\u0430\u00a0\u0432\u0435\u043b\u043e\u0441\u0438\u043f\u0435\u0434\u0435!<\/p>\n<p>\u042d\u0442\u043e\u00a0\u0431\u044b\u043b\u043e \u0432\u0441\u0435, \u0447\u0442\u043e\u00a0\u044f \u0445\u043e\u0442\u0435\u043b \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0430\u043c \u0432\u00a0\u043f\u0435\u0440\u0432\u043e\u0439 \u0447\u0430\u0441\u0442\u0438.<\/p>\n<p>\u041e\u043f\u044f\u0442\u044c\u00a0\u0436\u0435, \u043d\u0435\u00a0\u0441\u0442\u0435\u0441\u043d\u044f\u0439\u0442\u0435\u0441\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e \u043d\u0430\u00a0\u043c\u043e\u0435\u043c <a href=\"https:\/\/github.com\/0Itsuki0\/SwiftUI_SimpleWorkoutApp\"><strong>GitHub<\/strong><\/a><strong>!<\/strong><\/p>\n<p>\u0412\u0441\u0435 \u0432\u044b\u0448\u0435\u0441\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0435\u00a0\u2014 \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u043d\u043e\u00a0\u0440\u0430\u0437\u0432\u0435 \u043d\u0435\u00a0\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u0437\u043d\u0430\u0442\u044c, \u043a\u0430\u043a\u00a0\u043c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u0434\u0435\u043d\u044c? \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438? \u0421\u043a\u043e\u043b\u044c\u043a\u043e \u044d\u043d\u0435\u0440\u0433\u0438\u0438 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u043b\u0438?<\/p>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u043c\u044b \u043f\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c \u0432\u043e\u00a0\u0432\u0442\u043e\u0440\u043e\u0439 \u0447\u0430\u0441\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043a\u043e\u0440\u043e \u0432\u044b\u0439\u0434\u0435\u0442. \u0421\u043b\u0435\u0434\u0438\u0442\u0435 \u0437\u0430\u00a0\u043d\u043e\u0432\u043e\u0441\u0442\u044f\u043c\u0438, \u0435\u0441\u043b\u0438 \u0432\u0430\u043c\u00a0\u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e.<\/p>\n<p>\u0425\u043e\u0440\u043e\u0448\u0435\u0439 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438!<\/p>\n<hr\/>\n<p>\u0412\u043f\u0435\u0440\u0435\u0434\u0438 \u0435\u0449\u0435 \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e! \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043c\u044b \u0438\u0437\u0443\u0447\u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 HealthKit, \u043f\u043e\u0440\u0430 \u0440\u0430\u0441\u0448\u0438\u0440\u0438\u0442\u044c \u043d\u0430\u0448\u0438 \u0437\u043d\u0430\u043d\u0438\u044f. \u041d\u0430\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0443\u0440\u043e\u043a\u0435 \u0432\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435, \u043a\u0430\u043a\u00a0\u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434\u00a0SwiftUI, \u043a\u0430\u043a\u0438\u0435 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c, \u0438 \u043a\u0430\u043a\u00a0\u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e. \u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0439\u0442\u0435\u0441\u044c 22\u00a0\u0430\u043f\u0440\u0435\u043b\u044f \u043a\u00a0\u0443\u0440\u043e\u043a\u0443 <strong>\u00abSwiftUI + Network: \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442\u00bb<\/strong> <a href=\"https:\/\/otus.pw\/JGS3\/\">\u0417\u0430\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f<\/a><\/p>\n<p>\u0411\u043e\u043b\u044c\u0448\u0435 \u0443\u0440\u043e\u043a\u043e\u0432 \u043f\u043e Swift-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 \u0438 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 <a href=\"https:\/\/otus.pw\/22VU\/\">\u0432 \u043a\u0430\u043b\u0435\u043d\u0434\u0430\u0440\u0435 \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0439<\/a>.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/898762\/\"> https:\/\/habr.com\/ru\/articles\/898762\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"\"><\/figure>\n<p><strong>\u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 <\/strong><a href=\"https:\/\/github.com\/0Itsuki0\/SwiftUI_SimpleWorkoutApp\"><strong>GitHub<\/strong><\/a><strong>!<\/strong><\/p>\n<p>**************<\/p>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\"><strong>HealthKit<\/strong><\/a>\u00a0\u2014 \u044d\u0442\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0441\u043f\u043e\u0441\u043e\u0431\u043d\u044b\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u0434\u0430\u043d\u043d\u044b\u043c, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435\u043c \u0438 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u043e\u0439, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0438\u043c\u0438, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u0438\u00a0\u044d\u0442\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<p>\u0412\u00a0\u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e\u0437\u0434\u0430\u0442\u044c <strong>\u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f\u00a0\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u043a<\/strong>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0432\u0430\u043c \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441\u00a0\u043e\u0441\u043d\u043e\u0432\u0430\u043c\u0438 \u044d\u0442\u043e\u0433\u043e \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f\u00a0watchOS, \u0442\u0430\u043a \u043a\u0430\u043a\u00a0\u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0430, \u043d\u0430\u00a0\u043c\u043e\u0439 \u0432\u0437\u0433\u043b\u044f\u0434, \u043d\u0430\u0438\u043b\u0443\u0447\u0448\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0442\u0435\u043d\u0446\u0438\u0430\u043b HealthKit.<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u043c\u0441\u044f \u043d\u0430\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0430\u0441\u043f\u0435\u043a\u0442\u0430\u0445:<\/p>\n<ul>\n<li>\n<p>\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0440\u043e\u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0438\u043c\u0438<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a, \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430, \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438, \u0430\u00a0\u0442\u0430\u043a\u0436\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0435\u0435 \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438 \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u0435\u043b\u0435\u0439 \u043f\u043e\u00a0\u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044e \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438<\/p>\n<\/li>\n<\/ul>\n<p>\u0418 \u044d\u0442\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0430\u043b\u043e!<\/p>\n<p>\u0427\u0442\u043e\u00a0\u0436\u0435 \u043d\u0430\u0441 \u0436\u0434\u0435\u0442 \u0432\u00a0\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0439 \u0447\u0430\u0441\u0442\u0438? \u0412\u044b \u0443\u0437\u043d\u0430\u0435\u0442\u0435 \u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u0432\u00a0\u043a\u043e\u043d\u0446\u0435 \u0441\u0442\u0430\u0442\u044c\u0438!<\/p>\n<h2>\u041e\u0431\u0437\u043e\u0440<\/h2>\n<p>HealthKit\u00a0\u2014 \u044d\u0442\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043b\u0443\u0436\u0438\u0442 \u0446\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u044b\u043c \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u00a0\u0437\u0434\u043e\u0440\u043e\u0432\u044c\u0435 \u0438 \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u043d\u0430\u00a0iPhone \u0438 Apple Watch. \u0421\u00a0\u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u044d\u0442\u043e\u043c\u0443 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443, \u0447\u0442\u043e\u0431\u044b \u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u044d\u0442\u0438\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438.<\/p>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0440\u0430\u0437\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0438\u043c\u0435\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043e\u0434\u043d\u043e\u043c\u0443 \u0438 \u0442\u043e\u043c\u0443\u00a0\u0436\u0435 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>1. \u041a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u0435\u043b\u0438\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u00a0\u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<li>\n<p>2. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043b\u044e\u0431\u044b\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432\u00a0\u0434\u0430\u043d\u043d\u044b\u0445 \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0442\u0438 \u0432\u043d\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043d\u043d\u044b\u0435 \u043e\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u0437\u0434\u043e\u0440\u043e\u0432\u044c\u044f \u043c\u043e\u0433\u0443\u0442\u00a0\u0431\u044b\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0434\u0435\u043d\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c\u0438, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0430\u043c <strong>\u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e<\/strong> \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430\u00a0\u0447\u0442\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit.<\/p>\n<p>\u0418 \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0438\u043c \u043c\u044b \u0438 \u0437\u0430\u0439\u043c\u0435\u043c\u0441\u044f \u0434\u0430\u043b\u044c\u0448\u0435!<\/p>\n<h2>\u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430<\/h2>\n<p>\u0412\u00a0\u044d\u0442\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043c\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0430\u0436\u043d\u044b\u0445 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432:<\/p>\n<ol>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u0430 HealthKit.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430 \u0434\u043b\u044f\u00a0\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u043a.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.<\/p>\n<\/li>\n<\/ol>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 HealthKit<\/h3>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c HealthKit, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b HealthKit \u0432\u00a0\u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<p>\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 <strong>Watch <\/strong>\u0432\u00a0\u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0430\u0440\u0433\u0435\u0442\u0430!<\/p>\n<figure class=\"\"><\/figure>\n<p>\u0412\u00a0\u0440\u0430\u0437\u0434\u0435\u043b\u0435 <strong>Signing &amp; Capabilities<\/strong> \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043d\u0430 <strong>+ Capability<\/strong>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041d\u0430\u0439\u0434\u0438\u0442\u0435 HealthKit \u0438 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0435\u0433\u043e \u043a\u00a0\u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0442\u0430\u0440\u0433\u0435\u0442\u0443.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u0431\u0430 \u0444\u043b\u0430\u0436\u043a\u0430 \u043f\u0443\u0441\u0442\u044b\u043c\u0438, \u043a\u0430\u043a\u00a0\u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e \u043d\u0430\u00a0\u0441\u043a\u0440\u0438\u043d\u0448\u043e\u0442\u0435 \u043d\u0438\u0436\u0435.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0414\u0430, \u043d\u0430\u043c <strong>\u041d\u0415<\/strong> \u043d\u0443\u0436\u043d\u0430 <strong>HealthKit Background Delivery<\/strong>.<\/p>\n<p>\u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f\u00a0\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f <a href=\"https:\/\/developer.apple.com\/documentation\/healthkit\/reading-data-from-healthkit#Long-running-queries\"><strong>\u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/strong><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u0441\u044f\u043a\u0438\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit.<\/p>\n<h3>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0444\u043e\u043d\u043e\u0432\u043e\u0433\u043e \u0440\u0435\u0436\u0438\u043c\u0430<\/h3>\n<p>\u0414\u043b\u044f\u00a0\u0442\u043e\u0433\u043e\u00a0\u0436\u0435 \u0442\u0430\u0440\u0433\u0435\u0442\u0430 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b <strong>Background Modes<\/strong> \u0438 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043e\u043f\u0446\u0438\u044e <strong>Workout processing<\/strong>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u0448\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0444\u043e\u043d\u043e\u0432\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a\u00a0\u0441\u043e\u0436\u0436\u0435\u043d\u043d\u044b\u0435 \u043a\u0430\u043b\u043e\u0440\u0438\u0438 \u0438 \u0447\u0430\u0441\u0442\u043e\u0442\u0430 \u0441\u0435\u0440\u0434\u0435\u0447\u043d\u044b\u0445 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u0439, \u0432\u043e\u00a0\u0432\u0440\u0435\u043c\u044f \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438.<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f<\/h3>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u043a\u00a0\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u00a0\u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0442\u0430\u043a \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0438\u0445 \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043a\u043b\u044e\u0447\u0430 \u0432\u00a0<code>Info.plist<\/code> \u043d\u0430\u0448\u0435\u0433\u043e <strong>\u0442\u0430\u0440\u0433\u0435\u0442\u0430<\/strong>!<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/bundleresources\/information-property-list\/nshealthshareusagedescription\">NSHealthShareUsageDescription<\/a>\u00a0\u2014 \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u0442\u044c, \u043f\u043e\u0447\u0435\u043c\u0443 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u00a0\u0447\u0442\u0435\u043d\u0438\u0435 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u0432 \u0438\u0437\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0430 HealthKit.<\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/developer.apple.com\/documentation\/bundleresources\/information-property-list\/nshealthupdateusagedescription\">NSHealthUpdateUsageDescription<\/a>\u00a0\u2014 \u0434\u043b\u044f\u00a0\u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f, \u0437\u0430\u0447\u0435\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430\u00a0\u0437\u0430\u043f\u0438\u0441\u044c \u0432\u00a0\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435 HealthKit<\/p>\n<\/li>\n<\/ol>\n<figure class=\"full-width\"><\/figure>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u043a\u00a0\u043c\u0435\u0434\u0438\u0446\u0438\u043d\u0441\u043a\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u0438 \u0431\u043e\u043b\u0435\u0435 \u0447\u0443\u0432\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b, \u0447\u0435\u043c \u0434\u0440\u0443\u0433\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0431\u00a0\u044d\u0442\u043e\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0439\u0442\u0438 \u0432\u00a0\u0440\u0430\u0437\u0434\u0435\u043b\u0435 <a href=\"https:\/\/developer.apple.com\/documentation\/HealthKit\/accessing-a-user-s-clinical-records\"><strong>Accessing a User\u00bbs Clinical Records<\/strong><\/a>.<\/p>\n<h2>WorkoutManager<\/h2>\n<p>\u041a\u0430\u043a\u00a0\u0432\u0441\u0435\u0433\u0434\u0430, \u043c\u044b \u043d\u0430\u0447\u043d\u0435\u043c \u0441\u00a0\u043a\u043b\u0430\u0441\u0441\u0430 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440\u0430. \u042f \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u0441\u00a0\u0432\u0430\u043c\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0442\u043e\u0433\u043e, \u043a\u0430\u043a\u00a0\u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0435\u043d\u0435\u0434\u0436\u0435\u0440.<\/p>\n<h3>\u041a\u043e\u0434<\/h3>\n<pre><code class=\"swift\">\/\/ \/\/  WorkoutManager.swift \/\/  ItsukiWorkoutApp \/\/ \/\/  Created by Itsuki on 2025\/03\/02. \/\/   import SwiftUI import HealthKit   @MainActor @Observable class WorkoutManager: NSObject {       let supportedWorkoutTypes: Set&lt;HKWorkoutActivityType&gt; = [         .walking,         .running,         .cycling,         .swimming,         .swimBikeRun,         .highIntensityIntervalTraining,     ]          private let typesToShare: Set&lt;HKSampleType&gt; = [HKQuantityType.workoutType()]      private let typesToRead: Set&lt;HKObjectType&gt; = [         HKQuantityType(.heartRate),         HKQuantityType(.activeEnergyBurned),                  HKQuantityType(.stepCount),         HKQuantityType(.swimmingStrokeCount),         HKQuantityType(.walkingSpeed),         HKQuantityType(.cyclingSpeed),         HKQuantityType(.runningSpeed),          HKQuantityType(.distanceWalkingRunning),         HKQuantityType(.distanceCycling),         HKQuantityType(.distanceSwimming),          HKObjectType.activitySummaryType()     ]           var error: WorkoutError? {         didSet {             if let error {                 print(\"error: \\(error.message)\")             }         }     }          \/\/ \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0441\u0435\u0430\u043d\u0441\u0430     var showResult: Bool = false {         didSet {             if !showResult {                 reset()                 return             }         }     }     var workoutResult: HKWorkout? {         didSet {             if workoutResult != nil {                 self.showResult = true             }         }     }          \/\/ \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0435\u0430\u043d\u0441\u0430     var sessionRunning: Bool = false     var workoutMetrics: WorkoutMetrics?     func getElapseTime(at date: Date) -&gt; TimeInterval {         return self.builder?.elapsedTime(at: date) ?? 0     }          private var healthStore: HKHealthStore?          private var session: HKWorkoutSession?     private var builder: HKLiveWorkoutBuilder?     \/\/ \u0434\u043b\u044f iOS: \u0432\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 HKWorkoutBuilder \/\/    var builder: HKWorkoutBuilder?      override init() {         super.init()         if HKHealthStore.isHealthDataAvailable() {             self.healthStore = HKHealthStore()             Task {                 await self.requestAuthorization()             }         } else {             self.error = .unavailable         }     }  }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u041a\u043e\u0434, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0439 \u0441 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f\u043c\u0438  extension WorkoutManager {     private func checkAvailability() async -&gt; Bool {         if !HKHealthStore.isHealthDataAvailable() {             self.error = .unavailable             return false         }                  do {             let status = try await healthStore?.statusForAuthorizationRequest(toShare: typesToShare, read: typesToRead)             if status == .unnecessary {                 return true             }                          if status == .shouldRequest {                 await self.requestAuthorization()                 return true             }                          self.error = .permissionDenied             return false                      } catch(let error) {             self.error = .requestPermissionError(error)             return false         }     }          private func requestAuthorization() async  {         do {             try await healthStore?.requestAuthorization(toShare: typesToShare, read: typesToRead)         } catch (let error) {             self.error = .requestPermissionError(error)         }     }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0435\u0430\u043d\u0441\u043e\u043c \u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043a\u0438 \/ \u0431\u0438\u043b\u0434\u0435\u0440\u043e\u043c extension WorkoutManager {          func startWorkout(with configuration: HKWorkoutConfiguration) async {         let result = await self.checkAvailability()         if !result {             return         }         guard let healthStore else {             self.error = .unavailable             return         }          if !self.supportedWorkoutTypes.contains(configuration.activityType) {             self.error = .workoutTypeNotSupported             return         }                           do {             session = try HKWorkoutSession(healthStore: healthStore, configuration: configuration)             builder = session?.associatedWorkoutBuilder()         } catch(let error) {             self.error = .startWorkoutFailed(error)             return         }         builder?.dataSource = HKLiveWorkoutDataSource(healthStore: healthStore, workoutConfiguration: configuration) \/\/        print(\"types to collect: \", builder?.dataSource?.typesToCollect as Any)                  \/\/ \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440: respiratoryRate         \/\/ builder?.dataSource?.enableCollection(for: HKQuantityType(.respiratoryRate), predicate: nil)          \/\/ \u0414\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u0441\u0435\u0430\u043d\u0441\u0430 \u0438 \u0431\u0438\u043b\u0434\u0435\u0440\u0430         session?.delegate = self         builder?.delegate = self                  \/\/ \u0437\u0430\u043f\u0443\u0441\u043a \u0430\u043a\u0442\u0438\u0432\u0438\u0442\u0438         let date = Date()          session?.startActivity(with: date)                  do {             try await builder?.beginCollection(at: date)             self.workoutMetrics = .init(workoutConfiguration: configuration)         } catch(let error) {             self.error = .startWorkoutFailed(error)             reset()         }     }          func resumeSession() {         session?.resume()     }          func pauseSession() {         session?.pause()     }          func endSession() {         session?.end()     }          private func reset() {         self.session = nil         self.builder = nil         self.workoutResult = nil         self.workoutMetrics = nil     }      }   \/\/ \u041f\u041e\u041c\u0415\u0422\u041a\u0410: - \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438  extension WorkoutManager {     nonisolated private func setError(_ error: WorkoutError) {         DispatchQueue.main.async {             self.error = error         }     }          nonisolated private func updateMetrics(_ statistics: HKStatistics?) {         guard let statistics else { return }  \/\/        print(\"update metrics for \\(statistics.quantityType.identifier)\")         DispatchQueue.main.async {             switch statistics.quantityType {                              case HKQuantityType(.heartRate):                 self.workoutMetrics?.heartRate = statistics.heartRate<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-455170","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/455170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=455170"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/455170\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=455170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=455170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=455170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}