{"id":352559,"date":"2024-05-20T22:11:00","date_gmt":"2024-05-20T22:11:00","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=352559"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=352559","title":{"rendered":"<span>\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 Rocket Launch c GraphQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430\u043c\u0438 \u0447\u0435\u0440\u0435\u0437 Apollo<\/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<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0443\u0447\u0435\u0431\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f iOS \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u043d\u0430 GraphQL  \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Apollo \u2014 \u043e\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0434\u0432\u0443\u0445\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u043d\u0430\u0441 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0435 \u0438 \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u0440\u0430\u0431\u043b\u0435\u0439 SpaceX. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Rocket Launch \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u0438\u0441\u0441\u0438\u044f\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u044f. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Rocket Launch \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c UIKit \u0431\u0435\u0437 \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434\u043e\u0432. \u0412 \u044d\u0442\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 \u044f \u0434\u0430\u043c \u043a\u043e\u0434 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0441 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u043d\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u0441\u044b\u043b\u043a\u0443 <a href=\"https:\/\/github.com\/Bazilier\/rocket-launches\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441\u043e \u0441\u0432\u043e\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c<\/a>.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/caa\/f7b\/dc6\/caaf7bdc6430370f84e89e9612870e2b.png\" width=\"2000\" height=\"1078\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/caa\/f7b\/dc6\/caaf7bdc6430370f84e89e9612870e2b.png\"\/><\/figure>\n<p>\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0440\u0430\u043a\u0435\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0438 \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u044d\u0442\u043e\u0439 \u0440\u0430\u043a\u0435\u0442\u044b.<\/p>\n<p>\u041d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u0442\u0430 \u0438 \u0442\u0438\u043f \u043c\u0438\u0441\u0441\u0438\u0438.<\/p>\n<h3>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e GraphQL, Apollo \u0438 \u043d\u0430\u0448\u0435\u043c API SpaceX<\/h3>\n<p><strong>GraphQL<\/strong> \u2014 \u044d\u0442\u043e \u044f\u0437\u044b\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON. GraphQL \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0442\u043e\u0447\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u044b, \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u042d\u0442\u043e \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 REST API \u0438 \u0443\u043b\u0443\u0447\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 <a href=\"https:\/\/graphql.org\/\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 \u0441\u0430\u0439\u0442\u0435 GraphQL<\/a>.<\/p>\n<p><strong>Apollo<\/strong> \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 GraphQL \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u041e\u043d\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Apollo \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0441 iOS, \u0438\u043c\u0435\u043d\u043d\u043e \u0435\u0451 \u043c\u044b \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0442\u0430\u043a\u0436\u0435 <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435<\/a> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p><strong>SpaceXAPI<\/strong> \u2014 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u044b\u0439 API<\/a>. \u0422\u0430\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c URL, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043d\u0443\u0436\u043d\u0443\u044e \u043d\u0430\u043c GraphQL-\u0441\u0445\u0435\u043c\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Explorer. \u0412 \u043d\u0451\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0441\u0440\u0430\u0436\u0443 \u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445 \u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/204\/7f4\/85c\/2047f485cdc48a7ba4d8559e6c275284.png\" width=\"2000\" height=\"1404\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/204\/7f4\/85c\/2047f485cdc48a7ba4d8559e6c275284.png\"\/><\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 Xcode. \u042f \u043d\u0430\u0437\u0432\u0430\u043b \u0435\u0433\u043e rocket-launch-programmatically, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043a\u043e\u0434\u0435 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Storyboard. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Storyboard \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u044f\u0437\u044b\u043a Swift.<\/p>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Apollo \u0447\u0435\u0440\u0435\u0437 Package Manager<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c Apollo. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0435\u0440\u0435\u0437 CocoaPods \u0438\u043b\u0438 Package Manager. \u042f \u0432\u044b\u0431\u0435\u0440\u0443 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442. \u0412 \u043f\u043e\u0438\u0441\u043a\u0435 \u0432\u0432\u043e\u0434\u0438\u043c apollo-ios \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u041d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 Package Product \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u2014 Apollo.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bb1\/bfe\/6e0\/bb1bfe6e02833219bf26a878e95b2ec0.png\" width=\"2000\" height=\"632\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bb1\/bfe\/6e0\/bb1bfe6e02833219bf26a878e95b2ec0.png\"\/><\/figure>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 CLI<\/h3>\n<p>CLI (Command Line Interface) \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c Swift-\u043a\u043e\u0434 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u0445\u0435\u043c\u044b GraphQL.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435 \u043c\u0435\u043d\u044e \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u0441\u0434\u0435\u043b\u0430\u0432 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u043b\u0438\u043a \u0432 \u043b\u0435\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 Xcode \u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c Install CLI, \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c Run \u0438 \u0434\u0430\u0451\u043c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d75\/d75\/d32\/d75d75d32063e65aa4061c77007231e9.png\" width=\"2000\" height=\"1531\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d75\/d75\/d32\/d75d75d32063e65aa4061c77007231e9.png\"\/><\/figure>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f GraphQL-\u043c\u043e\u0434\u0443\u043b\u044f<\/h3>\n<p>\u0417\u0430\u0439\u0434\u0451\u043c \u0432 Terminal \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0432 \u043f\u0430\u043f\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043b\u0435\u0436\u0438\u0442 \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0414\u0435\u0441\u043a\u0442\u043e\u043f\u0435.<\/p>\n<p><code>cd Desktop\/rocket-launches-programmatically<\/code><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430.<\/p>\n<p>\u0412 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 init \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 schema-name (\u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0451\u043d \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432) \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430  module-type \u2014 swiftPackageManager. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0432\u0441\u0435 \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 SPM.<\/p>\n<p><code>.\/apollo-ios-cli init --schema-name SpaceXAPI --module-type swiftPackageManager<\/code><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.<\/p>\n<h3>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u0430 \u0441\u0445\u0435\u043c\u044b<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u0441\u0445\u0435\u043c\u044b, \u0433\u0434\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0442\u0438\u043f\u044b \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u0441 \u043d\u0430\u0448\u0438\u043c SpaceXAPI. \u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0432 \u043b\u0435\u0432\u043e\u043c \u043c\u0435\u043d\u044e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u0442 Schema, \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 SDL. <a href=\"https:\/\/studio.apollographql.com\/public\/SpaceX-pxxbxen\/variant\/current\/schema\/sdl\" rel=\"noopener noreferrer nofollow\">\u0412\u043e\u0442 \u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430<\/a> \u043d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b Raw \u0432 \u043f\u0440\u0430\u0432\u043e\u0439 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b99\/378\/c60\/b99378c6053df43ca86f4694974eec2b.png\" width=\"2000\" height=\"613\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b99\/378\/c60\/b99378c6053df43ca86f4694974eec2b.png\"\/><\/figure>\n<p><em>NB \u041b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0438 .graphql. \u041e\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f query, \u043c\u0443\u0442\u0430\u0446\u0438\u0439 \u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0445\u0435\u043c\u044b, \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043d\u0430 .graphqls (s \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 schema). \u0421\u0430\u043c\u043e \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u0432 schema, \u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0444\u0430\u0439\u043b schema.graphqls.<\/em><\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 GraphQL \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u043d\u0430\u0448\u0443 \u0441\u0445\u0435\u043c\u0443 \u0442\u0443\u0434\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9e8\/777\/076\/9e8777076c13829b018085dbb433dc53.png\" width=\"2000\" height=\"830\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9e8\/777\/076\/9e8777076c13829b018085dbb433dc53.png\"\/><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u043d\u0435\u0441\u0451\u043c \u043f\u0430\u043f\u043a\u0443 \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442, \u0441\u0434\u0435\u043b\u0430\u0432 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u043b\u0438\u043a \u0432 Navigator area \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0430\u043f\u043a\u0443 GraphQL.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/798\/062\/300\/7980623004ab934161f43c2f92f7cd51.png\" width=\"2000\" height=\"1551\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/798\/062\/300\/7980623004ab934161f43c2f92f7cd51.png\"\/><\/figure>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9a3\/36c\/868\/9a336c86894371063d27a7ba28841718.png\" width=\"2000\" height=\"1078\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9a3\/36c\/868\/9a336c86894371063d27a7ba28841718.png\"\/><\/figure>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 SpaceX. \u041c\u044b \u0441\u043d\u043e\u0432\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0441\u0430\u0439\u0442 SpaceX API \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b Explorer. \u0422\u0430\u043c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c query, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442.<\/p>\n<ul>\n<li>\n<p>\u0412 \u043b\u0435\u0432\u043e\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044e rockets (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 Rocket, \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043c\u0430\u0441\u0441\u0438\u0432). \u041d\u0430\u0436\u0430\u0432 \u043d\u0430 \u043d\u0435\u0451, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e query \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0439\u0434\u0451\u043c \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440\u0435 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0432\u044b\u0431\u0435\u0440\u0435\u043c \u043f\u043e\u043b\u044f id, name, heigh (\u043e\u0442\u043c\u0435\u0442\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u0440\u044b) \u0438 \u043c\u0430\u0441\u0441\u0443 (\u043e\u0442\u043c\u0435\u0442\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u044b).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u044f\u043c\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u043a\u043e\u0434\u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e Rockets \u0432 RocketsQuery.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u043d\u0430\u0436\u043c\u0451\u043c \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a, \u0442\u043e \u0432 \u0438\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u0443\u0432\u0438\u0434\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0430\u043a\u0435\u0442\u0430\u0445.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/cc4\/9fb\/350\/cc49fb3505a28930beae94129614a333.png\" width=\"2000\" height=\"990\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/cc4\/9fb\/350\/cc49fb3505a28930beae94129614a333.png\"\/><\/figure>\n<\/li>\n<\/ul>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 Xcode<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 GraphQL \u0432 Xcode \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b rocketsQuery \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .graphql. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0438\u043f\u0430 \u0444\u0430\u0439\u043b\u0430 \u0431\u0435\u0440\u0435\u043c \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442 Empty. \u041f\u0440\u044f\u043c\u043e \u0432 \u043d\u0435\u0433\u043e \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e query.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7a1\/86a\/c75\/7a186ac7590c22ed7985db7b7d0632c0.png\" width=\"2000\" height=\"897\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7a1\/86a\/c75\/7a186ac7590c22ed7985db7b7d0632c0.png\"\/><\/figure>\n<h3>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Swift-\u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0412\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 \u0432\u044b\u0448\u0435 CLI. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043d\u043e\u0432\u0430 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 Terminal \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 generate. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0438 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445. \u0412\u043e\u0442 \u0435\u0451 \u043a\u043e\u0434 \u0434\u043b\u044f \u0422\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430:<\/p>\n<p><code>.\/apollo-ios-cli generate<\/code><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 SpaceXAPI \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b RocketsQuery.graphql \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .swift.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/064\/70b\/05b\/06470b05b77fb1e0887b77c6632916a1.png\" width=\"2000\" height=\"1099\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/064\/70b\/05b\/06470b05b77fb1e0887b77c6632916a1.png\"\/><\/figure>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 SpaceXAPI<\/h3>\n<p>\u041c\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 graphql-\u043c\u043e\u0434\u0443\u043b\u044c, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 SpaceXAPI. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c Package Manager \u0438 \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 Add Local\u2026 \u0432 \u043d\u0438\u0436\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/fb2\/16d\/899\/fb216d899dec1f84c9d67b6fbf962f60.png\" width=\"2000\" height=\"1111\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/fb2\/16d\/899\/fb216d899dec1f84c9d67b6fbf962f60.png\"\/><\/figure>\n<p>\u0422\u0430\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u0430\u043f\u043a\u0443 SpaceXAPI \u0438 \u043d\u0430\u0436\u0430\u0442\u044c Add Package.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bf8\/219\/780\/bf8219780b4d90850d07ba9e0e968277.png\" width=\"2000\" height=\"842\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bf8\/219\/780\/bf8219780b4d90850d07ba9e0e968277.png\"\/><\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c SpaceXAPI \u0432 \u0440\u0430\u0437\u0434\u0435\u043b Frameworks \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0442\u0430\u0440\u0433\u0435\u0442\u0430.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bc6\/e55\/f76\/bc6e55f761ebcbefa50cab2ac2db4c21.png\" width=\"2000\" height=\"1309\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bc6\/e55\/f76\/bc6e55f761ebcbefa50cab2ac2db4c21.png\"\/><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0444\u0430\u0439\u043b \u0447\u0435\u0440\u0435\u0437 <code>import SpaceXAPI<\/code><\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c NetworkService. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 swift-\u0444\u0430\u0439\u043b \u0441 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u043e\u043c. \u0423 \u043d\u0435\u0433\u043e \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e Apollo, \u0438 \u043a \u043d\u0435\u043c\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e.<\/p>\n<p>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e Apollo \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u0438\u043c-\u043b\u0438\u0431\u043e end point, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u041c\u044b \u0432\u043e\u0437\u044c\u043c\u0451\u043c URL \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 SpaceXAPI.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e NetworkService:<\/p>\n<pre><code class=\"swift\">import Apollo import Foundation final class NetworkService { static let shared = NetworkService()  private(set) var apollo = ApolloClient(url: URL(string: \"https:\/\/spacex-production.up.railway.app\/)\")!)  private init() { }  } <\/code><\/pre>\n<h3>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0432\u0451\u0440\u0441\u0442\u043a\u0435 RocketsViewController<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434, \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e scene \u0432 SceneDelegate \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430\u0448\u0438\u043c \u0440\u0443\u0442\u043e\u0432\u044b\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c RocketsViewController, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0432\u0441\u043a\u043e\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 AppDelegate, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u0430\u0439\u043b Main \u0438 \u0432\u0441\u0451, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441\u043e \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434\u043e\u043c.<\/p>\n<pre><code class=\"swift\">import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return }     let window = UIWindow(windowScene: windowScene)     let rocketsVC = RocketsViewController()     let navController = UINavigationController(rootViewController: rocketsVC)     window.rootViewController = navController     self.window = window     window.makeKeyAndVisible() } \/\/ \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 SceneDelegate } <\/code><\/pre>\n<p>\u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0432\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 UITableView. \u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0432\u044b \u0441 \u043d\u0438\u043c \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0431\u0443\u0434\u0443 \u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0441\u0447\u0435\u0440\u043f\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u044f\u0447\u0435\u0435\u043a, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u043e\u0434 \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 RocketsViewController \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0434\u043d\u043e\u0438\u043c\u0451\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<p>\u0412 TableView \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u044f\u0447\u0435\u0439\u043a\u0430 RocketCell, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<p>\u0414\u043b\u044f \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043a\u043b\u043e\u0436\u0443\u0440\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 setupViews() \u0434\u043b\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e \u0438 setupConstraints() \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043b\u0435\u0439\u0430\u0443\u0442\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 SnapKit \u2014 \u044f \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 SPM.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 RocketsViewController<\/h4>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0442\u043e\u043c\u0443, \u0440\u0430\u0434\u0438 \u0447\u0435\u0433\u043e \u043c\u044b \u0442\u0443\u0442 \u0441\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b Swift \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c RocketsViewController. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 SpaceXAPI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 SnapKit \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u0430\u043c\u0438.<\/p>\n<pre><code class=\"swift\">import UIKit import SpaceXAPI import SnapKit <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 RocketsViewController:<\/p>\n<pre><code class=\"swift\">\/\/ \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 RocketsViewController final class RocketsViewController: UIViewController { \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 rockets, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445, \u0441\u044e\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043a\u043b\u0434\u044b\u0432\u0430\u0442\u044c \u0440\u0430\u043a\u0435\u0442\u044b, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 Apollo private var rockets: [RocketsQuery.Data.Rocket] = [] \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0430\u0437\u043e\u0432\u0451\u043c \u044f\u0447\u0435\u0439\u043a\u0443 RocketCell \u2014 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0451 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 private lazy var tableView: UITableView = { let tv = UITableView(frame: .zero, style: .plain) tv.dataSource = self tv.delegate = self tv.register(RocketCell.self, forCellReuseIdentifier: \"RocketCell\") return tv }() \/\/ \u041f\u0440\u043e\u043a\u0438\u043d\u0435\u043c \u0432\u043e \u0432\u044c\u044e\u0434\u0438\u0434\u043b\u043e\u0430\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0438\u043d\u0442\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445 override func viewDidLoad() { super.viewDidLoad() \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b setupViews() setupConstraints() \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0438\u0436\u0435 fetchRockets() } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e private func setupViews() { view.addSubview(tableView) } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0438\u043d\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SnapKit private func setupConstraints() { tableView.snp.makeConstraints { make in make.edges.equalToSuperview() } } } <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c delegate \u0438 dataSource \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<pre><code class=\"swift\">extension RocketsViewController: UITableViewDelegate, UITableViewDataSource { \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u043a\u0446\u0438\u0439 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 (\u043a\u0430\u043a \u0438 \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u0442\u0430\u043a \u0447\u0442\u043e \u0431\u0435\u0437 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u043e\u0439\u0442\u0438\u0441\u044c) func numberOfSections(in tableView: UITableView) -> Int {     return 1 } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044f\u0447\u0435\u0435\u043a \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { \/\/ \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 rockets return rockets.count } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043b\u044f \u0441\u0435\u043a\u0446\u0438\u0438 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return \"Rockets\" } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u044f\u0447\u0435\u0439\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: \"RocketCell\", for: indexPath) as! RocketCell let rocket = rockets[indexPath.row] cell.configureWith(rocket) return cell  } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f didSelectRowAt, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u044f\u0447\u0435\u0439\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041e\u043d\u0430 \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430\u043c \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442\u044c \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f LaunchesViewController. \u041f\u043e\u043a\u0430 \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0435\u0451 \u0437\u0430\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439. \u0412 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0439 \u0436\u0438\u0437\u043d\u0438 \u043c\u044b \u0431\u044b \u043f\u0438\u0441\u0430\u043b\u0438 \u0435\u0451 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u043e\u0433\u043e \u0432\u044c\u044e-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043d\u043e \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0432\u0430\u0441, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0435\u0451 \u0441\u0440\u0430\u0437\u0443. \/\/func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { \/\/    let vc = LaunchesViewController() \/\/    vc.rocket = rockets[indexPath.row] \/\/    let navController = UINavigationController(rootViewController: vc) \/\/    navController.modalPresentationStyle = .pageSheet \/\/    self.present(navController, animated: true, completion: nil) } } <\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445:<\/p>\n<pre><code class=\"swift\">private extension RocketsViewController {     \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445     func fetchRockets() { \/\/ \u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0437\u0430\u043f\u0440\u043e\u0441 \u0438\u0437 \u043d\u0430\u0448\u0435\u0433\u043e graphql-\u0444\u0430\u0439\u043b\u0430         let query = RocketsQuery() \/\/ \u041e\u0431\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u043a \u043d\u0430\u0448\u0435\u043c\u0443 Network Service, Apollo \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u0432\u0438\u0444\u0442\u043e\u0432\u044b\u0439 result, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 switch case         NetworkService.shared.apollo.fetch(query: query) { [weak self] result in             switch result {             case .success(let value):                 \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445 \u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b                 self?.rockets = value.data?.rockets?.compactMap { $0 } ?? []                 DispatchQueue.main.async {                     self?.tableView.reloadData()                 }             case .failure(let error):                 \/\/ \u0412\u044b\u0432\u043e\u0434 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c                 debugPrint(error.localizedDescription)             }         }     } } <\/code><\/pre>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u044f\u0447\u0435\u0439\u043a\u0443 \u0442\u0430\u0431\u043b\u0438\u0446\u044b<\/h4>\n<p>\u0412 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u044f\u0447\u0435\u0439\u043a\u0443 RocketCell<\/p>\n<pre><code class=\"swift\">import UIKit import SpaceXAPI import SnapKit \/\/ \u041a\u043b\u0430\u0441\u0441 RocketCell, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 UITableViewCell class RocketCell: UITableViewCell { \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043b\u0435\u0439\u0431\u043b\u044b \u0434\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0438 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 private let nameLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 16, weight: .bold) label.numberOfLines = 0 return label }() private let detailLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 14, weight: .regular) label.numberOfLines = 0 return label }() \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044f\u0447\u0435\u0439\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u044c\u044e override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupViews() setupConstraints() } required init?(coder: NSCoder) { fatalError(\"init(coder:) has not been implemented\") } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f configureWith \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u0440\u0430\u043a\u0435\u0442\u044b \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u044f\u0447\u0435\u0439\u043a\u0443 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 func configureWith(_ rocket: RocketsQuery.Data.Rocket) { \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u044f\u0447\u0435\u0439\u043a\u0438 \u0440\u0430\u0432\u043d\u043e\u0439 \u0438\u043c\u0435\u043d\u0438 \u0440\u0430\u043a\u0435\u0442\u044b nameLabel.text = rocket.name \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u044f\u0447\u0435\u0439\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u0438 \u043c\u0430\u0441\u0441\u0443 \u0440\u0430\u043a\u0435\u0442\u044b \u0432 \u043c\u0435\u0442\u0440\u0430\u0445 \u0438 \u043a\u0433 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e 0 detailLabel.text = \"\\\\(rocket.height?.meters ?? 0) meters \/ \\\\(rocket.mass?.kg ?? 0) kg\" } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 private func setupViews() { contentView.addSubview(nameLabel) contentView.addSubview(detailLabel) } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SnapKit private func setupConstraints() { nameLabel.snp.makeConstraints { make in make.top.left.equalToSuperview().offset(15) make.right.lessThanOrEqualToSuperview().offset(-15) } detailLabel.snp.makeConstraints { make in     make.top.equalTo(nameLabel.snp.bottom).offset(5)     make.left.right.equalTo(nameLabel)     make.bottom.lessThanOrEqualToSuperview().offset(-15) } }  } <\/code><\/pre>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u043e\u0432\u0443\u044e GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 LaunchesViewController<\/h4>\n<p>\u0412 \u043c\u043d\u043e\u0433\u043e\u043c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u0440\u0430\u043a\u0435\u0442\u044b \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u0435\u043d \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u043c\u044b \u0443\u0436\u0435 \u0441\u043e\u0431\u0440\u0430\u043b\u0438, \u043d\u043e \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043d\u044e\u0430\u043d\u0441\u0430\u043c\u0438.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e64\/ad9\/672\/e64ad9672150e87c4406a5e7ac1f15d2.png\" width=\"2000\" height=\"927\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e64\/ad9\/672\/e64ad9672150e87c4406a5e7ac1f15d2.png\"\/><\/figure>\n<p>\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u043d\u0430 \u0441\u0430\u0439\u0442 \u043d\u0430\u0448\u0435\u0433\u043e SpaceXAPI \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u0440\u0438\u043d\u043e\u0441\u0438\u0442\u044c \u043d\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0441\u043e\u0432\u0435\u0440\u0448\u0451\u043d\u043d\u044b\u0445 \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0440\u0430\u043a\u0435\u0442. \u0422\u0443\u0442 \u0441\u0442\u043e\u0438\u0442 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0435\u0449\u0451 \u043e\u0434\u043d\u0443 \u0443\u0434\u043e\u0431\u043d\u0443\u044e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c GraphQL: \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0434\u0432\u0435 \u0440\u0430\u0437\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043e\u0434\u043d\u043e\u0439 \u043e\u0431\u0449\u0435\u0439. \u0421\u0435\u0439\u0447\u0430\u0441 \u043c\u044b \u0432 \u044d\u0442\u043e\u043c \u0443\u0431\u0435\u0434\u0438\u043c\u0441\u044f \u2014 \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u0434\u0432\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u043e\u0434\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u043f\u0440\u043e\u0448\u043b\u044b\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445, \u0432\u0442\u043e\u0440\u0430\u044f \u2014 \u043e \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0445. \u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u043a\u043e\u0434:<\/p>\n<pre><code class=\"swift\">query LaunchesQuery($upcomingFind: LaunchFind, $pastFind: LaunchFind) {   launchesUpcoming(find: $upcomingFind) {     id     mission_name     launch_date_utc    }   launchesPast(find: $pastFind) {     id     mission_name     launch_date_utc   } } <\/code><\/pre>\n<p>\u0412 \u044d\u043a\u0441\u043f\u043b\u043e\u0440\u0435\u0440\u0435 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 API \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u0443\u044e \u0432\u043a\u043b\u0430\u0434\u043a\u0443, \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440\u0435 \u0441\u043b\u0435\u0432\u0430 \u0432\u044b\u0431\u0435\u0440\u0435\u043c launchesUpcoming, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u0432 \u043e\u0442\u043a\u0440\u044b\u0432\u0448\u0435\u043c\u0441\u044f \u043c\u0435\u043d\u044e \u0432\u044b\u0431\u0435\u0440\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f id, mission_name \u0438 launch_date_utc.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0436\u043c\u0451\u043c \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0443 \u043d\u0430\u0437\u0430\u0434 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432. \u0412\u044b\u0431\u0435\u0440\u0435\u043c \u043f\u043e\u043b\u0435 launchesPast \u0438 \u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0442\u0443\u0434\u0430 \u0442\u0435 \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f d, mission_name \u0438 launch_date_utc.<\/p>\n<p>\u041f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u043e\u0431\u0449\u0443\u044e \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e (\u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u043d\u0430 \u043d\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f LaunchesUpcoming) \u0432 LauchesQuery. \u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0437\u0430\u043f\u0443\u0441\u043a\u0438 \u043f\u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0440\u0430\u043a\u0435\u0442\u0435, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 query. \u042d\u0442\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 find, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c id \u0440\u0430\u043a\u0435\u0442\u044b.<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0440\u043d\u0451\u043c\u0441\u044f \u0432 Xcode \u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0442\u0438\u043f\u0430 Empty \u0432 \u043d\u0430\u0448\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 GraphQL. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u043d\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f launchesQuery.graphql. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043d\u0430\u0448 GraphQL-\u043a\u043e\u0434 \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438. \u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/874\/352\/b3c\/874352b3c86fbad346c17709c6ce2343.png\" width=\"2000\" height=\"691\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/874\/352\/b3c\/874352b3c86fbad346c17709c6ce2343.png\"\/><\/figure>\n<p>\u041f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0435\u043f\u0435\u0440\u044c? \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c swift-\u0444\u0430\u0439\u043b. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u0441\u044f \u0432 Terminal \u0438 \u0441\u043d\u043e\u0432\u0430 \u0432\u0432\u043e\u0434\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443:<\/p>\n<p><code>.\/apollo-ios-cli generate<\/code><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u043d\u0430\u0448\u0435\u0439 \u043f\u0430\u043f\u043a\u0435 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .swift, \u0432\u0441\u0451 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043d\u043e\u0432\u044b\u0439 \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 LaunchesViewController<\/h4>\n<p>\u041d\u043e\u0432\u044b\u0439 \u0432\u044c\u044e-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 LaunchesViewController \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0447\u0435\u0440\u0435\u0437 present \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043d\u0430 \u043e\u0434\u043d\u0443 \u0438\u0437 \u044f\u0447\u0435\u0435\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b (\u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0430\u044f \u0440\u0430\u043a\u0435\u0442\u0430) \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u043f\u0435\u0440\u0432\u043e\u043c \u0432\u044c\u044e-\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435. \u0418\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 \u043a\u043e\u043d\u0446\u0435 \u0442\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u043c\u044b \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e didSelectRowAt \u2014 <code>func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)<\/code> (\u0441\u0435\u0439\u0447\u0430\u0441 \u043e\u043d\u0430 \u0437\u0430\u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0430).<\/p>\n<p>\u0418\u0442\u0430\u043a, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 Swift-\u0444\u0430\u0439\u043b \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c LaunchesViewController, \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u0442\u0443\u0434\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<pre><code class=\"swift\">import SpaceXAPI import UIKit import SnapKit<\/code><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 \u043a\u043b\u0430\u0441\u0441\u0430 LaunchesViewController.<\/p>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u043b \u0440\u0430\u043d\u0435\u0435, \u043d\u0435 \u0431\u0443\u0434\u0443 \u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044f\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f UITableView.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u043e\u0434 \u0441\u0430\u043c\u043e\u0433\u043e \u0432\u044c\u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430:<\/p>\n<pre><code class=\"swift\">\/\/ \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 LaunchesViewController final class LaunchesViewController: UIViewController {          \/\/ \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0435     var rocket: RocketsQuery.Data.Rocket!          \/\/ \u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0435\u0440\u043e\u0432 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0438 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u0434\u0430\u0442     private let inDateFormatter: DateFormatter = {         let dateFormatter = DateFormatter()         dateFormatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"         return dateFormatter     }()           private let outDateFormatter: DateFormatter = {         let dateFormatter = DateFormatter()         dateFormatter.dateFormat = \"dd-MM-yyyy HH:mm:ss\"         return dateFormatter     }()          \/\/ \u041c\u0430\u0441\u0441\u0438\u0432\u044b \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u0438 \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432     private var launchesUpcoming: [LaunchesQuery.Data.LaunchesUpcoming] = []     private var launchesPast: [LaunchesQuery.Data.LaunchesPast] = []          \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0441 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u0435\u043c     private lazy var tableView: UITableView = {         let tv = UITableView(frame: .zero, style: .plain)         tv.dataSource = self         tv.delegate = self         tv.register(LaunchCell.self, forCellReuseIdentifier: \"LaunchCell\")         return tv     }()          \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u0430\u044f \u043f\u043e\u0441\u043b\u0435 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430     override func viewDidLoad() {         super.viewDidLoad()         navigationItem.title = rocket.name                  \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0445         setupViews()         setupConstraints()         fetchLaunches()     }          \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439     private func setupViews() {         view.addSubview(tableView)     }          \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SnapKit     private func setupConstraints() {         tableView.snp.makeConstraints { make in             make.edges.equalToSuperview()         }     } }<\/code><\/pre>\n<p>\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044f\u0447\u0435\u0439\u043a\u043e\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u0430\u043b\u0435\u0435:<\/p>\n<pre><code class=\"swift\">extension LaunchesViewController: UITableViewDelegate, UITableViewDataSource { \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u043a\u0446\u0438\u0439 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435 func numberOfSections(in tableView: UITableView) -> Int {     return 2 } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044f\u0447\u0435\u0435\u043a \u0432 \u0441\u0435\u043a\u0446\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch section { case 0: return launchesUpcoming.count case 1: return launchesPast.count default: return 0 } } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u044f\u0447\u0435\u0439\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: \"LaunchCell\", for: indexPath) as! LaunchCell let cellText: String let cellSecondaryText: String \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u044f\u0447\u0435\u0435\u043a \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0435\u043a\u0446\u0438\u0438, \u0434\u043b\u044f \u0432\u044b\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0434\u0430\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0430\u0448\u0438\u0445 DateFormatter switch indexPath.section { case 0:     let launchUpcoming = launchesUpcoming[indexPath.row]     cellText = launchUpcoming.mission_name ?? \"\"     let launchDate = inDateFormatter.date(from: launchUpcoming.launch_date_utc ?? \"\") ?? .now     cellSecondaryText = outDateFormatter.string(from: launchDate)  case 1:     let launchPast = launchesPast[indexPath.row]     cellText = launchPast.mission_name ?? \"\"     let launchDate = inDateFormatter.date(from: launchPast.launch_date_utc ?? \"\") ?? .now     cellSecondaryText = outDateFormatter.string(from: launchDate)  default:     cellText = \"\"     cellSecondaryText = \"\" }  \/\/ \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u044f\u0447\u0435\u0439\u043a\u0438 cell.configureWith(text: cellText, secondaryText: cellSecondaryText) return cell  } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0430\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043b\u044f \u0441\u0435\u043a\u0446\u0438\u0438 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch section { case 0: return \"Upcoming launches\" case 1: return \"Past launches\" default: return nil } } } <\/code><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0435\u0449\u0451 \u043e\u0434\u043d\u043e \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0434\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044e \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0447\u0435\u0440\u0435\u0437 Apollo.<\/p>\n<pre><code class=\"swift\">private extension LaunchesViewController {     func fetchLaunches() { \/\/ \u0422\u0430\u043a \u043a\u0430\u043a \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441 id \u0440\u0430\u043a\u0435\u0442\u044b, \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c LaunchFind \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c rocket.id         let launchFind = LaunchFind(rocket_id: rocket.id ?? .none) \/\/ \u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0440\u0443\u0435\u043c \u0441\u0430\u043c\u0443 query \u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0434\u0438\u043c \u0442\u0443\u0434\u0430 launchFind \u0434\u043b\u044f \u043e\u0431\u043e\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432         let query = LaunchesQuery(upcomingFind: .some(launchFind), pastFind: .some(launchFind)) \/\/ \u0417\u0430\u0442\u0435\u043c \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 NetworkService \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u0441\u0430\u043c\u0443 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e, \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0432 result \u0432 \u0431\u043b\u043e\u043a\u0435 completion          NetworkService.shared.apollo.fetch(query: query) { [weak self] result in             switch result {             case .success(let value): \/\/ \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0443\u0441\u043f\u0435\u0445\u0430 \u043f\u043e\u043b\u043e\u0436\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0434\u0432\u0430 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 launchesUpcoming \u0438 launchesPast, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 \u043d\u0430\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435                 self?.launchesUpcoming = value.data?.launchesUpcoming?.compactMap { $0 } ?? []                 self?.launchesPast = value.data?.launchesPast?.compactMap { $0 } ?? [] \/\/ \u041e\u0431\u043d\u043e\u0432\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b                 DispatchQueue.main.async {                     self?.tableView.reloadData()                 }         case .failure(let error):             \/\/ \u0412\u044b\u0432\u043e\u0434 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c             debugPrint(error.localizedDescription)         }     } }  } <\/code><\/pre>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 Swift-\u0444\u0430\u0439\u043b \u0434\u043b\u044f \u044f\u0447\u0435\u0439\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c LaunchCell.<\/p>\n<pre><code class=\"swift\">import UIKit import SnapKit \/\/ \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 LaunchCell, \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u044b\u0439 \u043e\u0442 UITableViewCell final class LaunchCell: UITableViewCell { \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u043b\u0435\u0439\u0431\u043b\u044b \u0434\u043b\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0438 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 private let mainTextLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 16, weight: .bold) label.numberOfLines = 0 return label }() private let secondaryTextLabel: UILabel = { let label = UILabel() label.font = .systemFont(ofSize: 14, weight: .regular) label.numberOfLines = 0 return label }() \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u044f\u0447\u0435\u0439\u043a\u0438 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) setupViews() setupConstraints() } required init?(coder: NSCoder) { fatalError(\"init(coder:) has not been implemented\") } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f configureWith \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0442\u0435\u043a\u0441\u0442 \u0438 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, \u0438 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u0442 \u044f\u0447\u0435\u0439\u043a\u0443 \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 func configureWith(text: String, secondaryText: String) { \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u044f\u0447\u0435\u0439\u043a\u0438, \u0440\u0430\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0442\u0435\u043a\u0441\u0442\u0443 mainTextLabel.text = text \/\/ \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u044f\u0447\u0435\u0439\u043a\u0438, \u0440\u0430\u0432\u043d\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0432\u0442\u043e\u0440\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u043c\u0443 \u0442\u0435\u043a\u0441\u0442\u0443 secondaryTextLabel.text = secondaryText } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 private func setupViews() { contentView.addSubview(mainTextLabel) contentView.addSubview(secondaryTextLabel) } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SnapKit private func setupConstraints() { mainTextLabel.snp.makeConstraints { make in make.top.left.equalToSuperview().offset(15) make.right.lessThanOrEqualToSuperview().offset(-15) } secondaryTextLabel.snp.makeConstraints { make in     make.top.equalTo(mainTextLabel.snp.bottom).offset(5)     make.left.right.equalTo(mainTextLabel)     make.bottom.lessThanOrEqualToSuperview().offset(-15) } }  } <\/code><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u044d\u0442\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c.<\/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\/755542\/\"> https:\/\/habr.com\/ru\/articles\/755542\/<\/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<p>\u0412\u0441\u0435\u043c \u043f\u0440\u0438\u0432\u0435\u0442!<\/p>\n<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0443\u0447\u0435\u0431\u043d\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f iOS \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u044d\u043a\u0435\u043d\u0434\u0430 \u043d\u0430 GraphQL  \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Apollo \u2014 \u043e\u043d\u043e \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0434\u0432\u0443\u0445\u044d\u043a\u0440\u0430\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u0432\u043b\u0435\u043a\u0430\u0442\u044c \u043d\u0430\u0441 \u043e\u0442 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0435 \u0438 \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0443\u0441\u043a\u0438 \u0440\u0430\u0437\u043d\u044b\u0445 \u043a\u043e\u0440\u0430\u0431\u043b\u0435\u0439 SpaceX. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Rocket Launch \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043c\u0438\u0441\u0441\u0438\u044f\u0445, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u044f. \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Rocket Launch \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c UIKit \u0431\u0435\u0437 \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434\u043e\u0432. \u0412 \u044d\u0442\u043e\u043c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0435 \u044f \u0434\u0430\u043c \u043a\u043e\u0434 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0441 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u043d\u043e \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e \u0441\u0441\u044b\u043b\u043a\u0443 <a href=\"https:\/\/github.com\/Bazilier\/rocket-launches\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441\u043e \u0441\u0432\u043e\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c<\/a>.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041d\u0430 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0440\u0430\u043a\u0435\u0442\u044b \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0438 \u0433\u0440\u044f\u0434\u0443\u0449\u0438\u0445 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u044d\u0442\u043e\u0439 \u0440\u0430\u043a\u0435\u0442\u044b.<\/p>\n<p>\u041d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u0432 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u0442\u0430 \u0438 \u0442\u0438\u043f \u043c\u0438\u0441\u0441\u0438\u0438.<\/p>\n<h3>\u041a\u043e\u0440\u043e\u0442\u043a\u043e \u043e GraphQL, Apollo \u0438 \u043d\u0430\u0448\u0435\u043c API SpaceX<\/h3>\n<p><strong>GraphQL<\/strong> \u2014 \u044d\u0442\u043e \u044f\u0437\u044b\u043a \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 API, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u043e\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0438\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 JSON. GraphQL \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0442\u043e\u0447\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0443\u0436\u043d\u044b, \u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435. \u042d\u0442\u043e \u0441\u043d\u0438\u0436\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044e \u0441 REST API \u0438 \u0443\u043b\u0443\u0447\u0448\u0430\u0435\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0420\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439 <a href=\"https:\/\/graphql.org\/\" rel=\"noopener noreferrer nofollow\">\u043d\u0430 \u0441\u0430\u0439\u0442\u0435 GraphQL<\/a>.<\/p>\n<p><strong>Apollo<\/strong> \u2014 \u044d\u0442\u043e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 GraphQL \u0432 \u043a\u043b\u0438\u0435\u043d\u0442\u0441\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u041e\u043d\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043c\u0443\u0442\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0411\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Apollo \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0441 iOS, \u0438\u043c\u0435\u043d\u043d\u043e \u0435\u0451 \u043c\u044b \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0442\u0430\u043a\u0436\u0435 <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435<\/a> \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438.<\/p>\n<p><strong>SpaceXAPI<\/strong> \u2014 \u0445\u043e\u0440\u043e\u0448\u0438\u0439 <a href=\"https:\/\/www.apollographql.com\/docs\/ios\/\" rel=\"noopener noreferrer nofollow\">\u0442\u0440\u0435\u043d\u0438\u0440\u043e\u0432\u043e\u0447\u043d\u044b\u0439 API<\/a>. \u0422\u0430\u043c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c URL, \u043f\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u043d\u0443\u0436\u043d\u0443\u044e \u043d\u0430\u043c GraphQL-\u0441\u0445\u0435\u043c\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Explorer. \u0412 \u043d\u0451\u043c \u043c\u044b \u0441\u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043d\u0430\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438, \u0441\u0440\u0430\u0436\u0443 \u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445 \u0438 \u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0447\u0442\u043e \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0432 \u043e\u0442\u0432\u0435\u0442\u0435.<\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/h3>\n<figure class=\"full-width\"><\/figure>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 Xcode. \u042f \u043d\u0430\u0437\u0432\u0430\u043b \u0435\u0433\u043e rocket-launch-programmatically, \u0442\u0430\u043a \u043a\u0430\u043a \u0441\u043e\u0431\u0438\u0440\u0430\u044e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043a\u043e\u0434\u0435 \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f Storyboard. \u0412\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 Storyboard \u0438 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u044f\u0437\u044b\u043a Swift.<\/p>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Apollo \u0447\u0435\u0440\u0435\u0437 Package Manager<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c Apollo. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0447\u0435\u0440\u0435\u0437 CocoaPods \u0438\u043b\u0438 Package Manager. \u042f \u0432\u044b\u0431\u0435\u0440\u0443 \u0432\u0442\u043e\u0440\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442. \u0412 \u043f\u043e\u0438\u0441\u043a\u0435 \u0432\u0432\u043e\u0434\u0438\u043c apollo-ios \u0438 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a. \u041d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 Package Product \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u2014 Apollo.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 CLI<\/h3>\n<p>CLI (Command Line Interface) \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c Swift-\u043a\u043e\u0434 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u0445\u0435\u043c\u044b GraphQL.<\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435 \u043c\u0435\u043d\u044e \u043d\u0430 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435, \u0441\u0434\u0435\u043b\u0430\u0432 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u043b\u0438\u043a \u0432 \u043b\u0435\u0432\u043e\u043c \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u0443\u0433\u043b\u0443 Xcode \u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c Install CLI, \u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u0436\u0438\u043c\u0430\u0435\u043c Run \u0438 \u0434\u0430\u0451\u043c \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043d\u0430 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f GraphQL-\u043c\u043e\u0434\u0443\u043b\u044f<\/h3>\n<p>\u0417\u0430\u0439\u0434\u0451\u043c \u0432 Terminal \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u0432 \u043f\u0430\u043f\u043a\u0443 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u0412 \u043c\u043e\u0451\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043d \u043b\u0435\u0436\u0438\u0442 \u043f\u0440\u044f\u043c\u043e \u043d\u0430 \u0414\u0435\u0441\u043a\u0442\u043e\u043f\u0435.<\/p>\n<p><code>cd Desktop\/rocket-launches-programmatically<\/code><\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438. \u042d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u0434\u0430.<\/p>\n<p>\u0412 \u043a\u043e\u043c\u0430\u043d\u0434\u0443 init \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430 schema-name (\u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438\u043c\u0451\u043d \u0434\u043b\u044f \u0431\u0443\u0434\u0443\u0449\u0438\u0445 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432) \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0430  module-type \u2014 swiftPackageManager. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u0432\u0441\u0435 \u0431\u0443\u0434\u0443\u0449\u0438\u0435 \u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c \u0447\u0435\u0440\u0435\u0437 SPM.<\/p>\n<p><code>.\/apollo-ios-cli init --schema-name SpaceXAPI --module-type swiftPackageManager<\/code><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d \u0444\u0430\u0439\u043b \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.<\/p>\n<h3>\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0444\u0430\u0439\u043b\u0430 \u0441\u0445\u0435\u043c\u044b<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b \u0441\u0445\u0435\u043c\u044b, \u0433\u0434\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b, \u0442\u0438\u043f\u044b \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u0432\u043a\u043b\u0430\u0434\u043a\u0443 \u0441 \u043d\u0430\u0448\u0438\u043c SpaceXAPI. \u041d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u0432 \u043b\u0435\u0432\u043e\u043c \u043c\u0435\u043d\u044e \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0440\u0430\u0437\u0434\u0435\u0442 Schema, \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u0432 SDL. <a href=\"https:\/\/studio.apollographql.com\/public\/SpaceX-pxxbxen\/variant\/current\/schema\/sdl\" rel=\"noopener noreferrer nofollow\">\u0412\u043e\u0442 \u043f\u0440\u044f\u043c\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430<\/a> \u043d\u0430 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437\u0434\u0435\u043b. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0444\u0430\u0439\u043b Raw \u0432 \u043f\u0440\u0430\u0432\u043e\u0439 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p><em>NB \u041b\u044e\u0431\u043e\u043f\u044b\u0442\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442, \u0447\u0442\u043e \u0444\u0430\u0439\u043b \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0438 .graphql. \u041e\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f query, \u043c\u0443\u0442\u0430\u0446\u0438\u0439 \u0438 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u0432. \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0445\u0435\u043c\u044b, \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043d\u0430 .graphqls (s \u0432 \u043a\u043e\u043d\u0446\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 schema). \u0421\u0430\u043c\u043e \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u0432 schema, \u0442\u043e \u0435\u0441\u0442\u044c \u0432 \u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0444\u0430\u0439\u043b schema.graphqls.<\/em><\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u0430\u043f\u043a\u0443 GraphQL \u0438 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u043d\u0430\u0448\u0443 \u0441\u0445\u0435\u043c\u0443 \u0442\u0443\u0434\u0430.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u043d\u0435\u0441\u0451\u043c \u043f\u0430\u043f\u043a\u0443 \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442, \u0441\u0434\u0435\u043b\u0430\u0432 \u043f\u0440\u0430\u0432\u044b\u0439 \u043a\u043b\u0438\u043a \u0432 Navigator area \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0430\u043f\u043a\u0443 GraphQL.<\/p>\n<figure class=\"full-width\"><\/figure>\n<figure class=\"full-width\"><\/figure>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u043e\u043c \u044d\u043a\u0440\u0430\u043d\u0435 \u043d\u0430\u0448\u0435\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 SpaceX. \u041c\u044b \u0441\u043d\u043e\u0432\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u043c\u0441\u044f \u043d\u0430 \u0441\u0430\u0439\u0442 SpaceX API \u0438 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u0432 \u0440\u0430\u0437\u0434\u0435\u043b Explorer. \u0422\u0430\u043c \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c query, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0438 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u043a\u0435\u0442.<\/p>\n<ul>\n<li>\n<p>\u0412 \u043b\u0435\u0432\u043e\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0430\u0439\u0442\u0438 \u043f\u043e\u0437\u0438\u0446\u0438\u044e rockets (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 Rocket, \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043c\u0430\u0441\u0441\u0438\u0432). \u041d\u0430\u0436\u0430\u0432 \u043d\u0430 \u043d\u0435\u0451, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e query \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0439\u0434\u0451\u043c \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0442\u043e\u0440\u0435 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441\u0435. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u0432\u044b\u0431\u0435\u0440\u0435\u043c \u043f\u043e\u043b\u044f id, name, heigh (\u043e\u0442\u043c\u0435\u0442\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0442\u0440\u044b) \u0438 \u043c\u0430\u0441\u0441\u0443 (\u043e\u0442\u043c\u0435\u0442\u0438\u043c \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0438\u043b\u043e\u0433\u0440\u0430\u043c\u043c\u044b).<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u044f\u043c\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u043a\u043e\u0434\u0430 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u043c \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e Rockets \u0432 RocketsQuery.<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043c\u044b \u043d\u0430\u0436\u043c\u0451\u043c \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a, \u0442\u043e \u0432 \u0438\u043d\u0441\u043f\u0435\u043a\u0442\u043e\u0440\u0435 \u0441\u043f\u0440\u0430\u0432\u0430 \u0443\u0432\u0438\u0434\u0438\u043c \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0440\u0430\u043a\u0435\u0442\u0430\u0445.<\/p>\n<figure class=\"full-width\"><\/figure>\n<\/li>\n<\/ul>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 Xcode<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u044f\u043c\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 GraphQL \u0432 Xcode \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b rocketsQuery \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .graphql. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0438\u043f\u0430 \u0444\u0430\u0439\u043b\u0430 \u0431\u0435\u0440\u0435\u043c \u0442\u0435\u043c\u043f\u043b\u0435\u0439\u0442 Empty. \u041f\u0440\u044f\u043c\u043e \u0432 \u043d\u0435\u0433\u043e \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043d\u0430\u0448\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e query.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f Swift-\u043a\u043e\u0434\u0430 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0412\u043e\u0442 \u0437\u0434\u0435\u0441\u044c \u043d\u0430\u043c \u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0443\u043f\u043e\u043c\u044f\u043d\u0443\u0442\u044b\u0439 \u0432\u044b\u0448\u0435 CLI. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043d\u043e\u0432\u0430 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 Terminal \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 generate. \u042d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u0445 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0438 \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445. \u0412\u043e\u0442 \u0435\u0451 \u043a\u043e\u0434 \u0434\u043b\u044f \u0422\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0430:<\/p>\n<p><code>.\/apollo-ios-cli generate<\/code><\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0432 \u043f\u0430\u043f\u043a\u0435 SpaceXAPI \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0444\u0430\u0439\u043b RocketsQuery.graphql \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c .swift.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0430\u043a\u0435\u0442\u0430 SpaceXAPI<\/h3>\n<p>\u041c\u044b \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043b\u0438 graphql-\u043c\u043e\u0434\u0443\u043b\u044c, \u0438 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 SpaceXAPI. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c Package Manager \u0438 \u043d\u0430\u0436\u0430\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 Add Local\u2026 \u0432 \u043d\u0438\u0436\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0430\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u0430\u043f\u043a\u0443 SpaceXAPI \u0438 \u043d\u0430\u0436\u0430\u0442\u044c Add Package.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u0438\u043c SpaceXAPI \u0432 \u0440\u0430\u0437\u0434\u0435\u043b Frameworks \u043d\u0430\u0448\u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0442\u0430\u0440\u0433\u0435\u0442\u0430.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442 \u0432 \u043b\u044e\u0431\u043e\u0439 \u0444\u0430\u0439\u043b \u0447\u0435\u0440\u0435\u0437 <code>import SpaceXAPI<\/code><\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0441\u0435\u0442\u044c\u044e<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c NetworkService. \u042d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 swift-\u0444\u0430\u0439\u043b \u0441 \u0441\u0438\u043d\u0433\u043b\u0442\u043e\u043d\u043e\u043c. \u0423 \u043d\u0435\u0433\u043e \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u043e \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e Apollo, \u0438 \u043a \u043d\u0435\u043c\u0443 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u0432\u0441\u0435\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u0445\u043e\u0442\u0438\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u0443\u044e-\u0442\u043e GraphQL-\u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e.<\/p>\n<p>\u0421\u0432\u043e\u0439\u0441\u0442\u0432\u043e Apollo \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441 \u043a\u0430\u043a\u0438\u043c-\u043b\u0438\u0431\u043e end point, \u043a\u0443\u0434\u0430 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u044b. \u041c\u044b \u0432\u043e\u0437\u044c\u043c\u0451\u043c URL \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 SpaceXAPI.<\/p>\n<p>\u0412\u043e\u0442 \u043a\u043e\u0434 \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e NetworkService:<\/p>\n<pre><code class=\"swift\">import Apollo import Foundation final class NetworkService { static let shared = NetworkService()  private(set) var apollo = ApolloClient(url: URL(string: \"https:\/\/spacex-production.up.railway.app\/)\")!)  private init() { }  } <\/code><\/pre>\n<h3>\u041f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0432\u0451\u0440\u0441\u0442\u043a\u0435 RocketsViewController<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434, \u0434\u043e\u043f\u0438\u0448\u0435\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e scene \u0432 SceneDelegate \u0438 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u043d\u0430\u0448\u0438\u043c \u0440\u0443\u0442\u043e\u0432\u044b\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c RocketsViewController, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0432\u0441\u043a\u043e\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0447\u0435\u0440\u0435\u0437 AppDelegate, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0444\u0430\u0439\u043b Main \u0438 \u0432\u0441\u0451, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441\u043e \u0421\u0442\u043e\u0440\u0438\u0431\u043e\u0440\u0434\u043e\u043c.<\/p>\n<pre><code class=\"swift\">import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return }     let window = UIWindow(windowScene: windowScene)     let rocketsVC = RocketsViewController()     let navController = UINavigationController(rootViewController: rocketsVC)     window.rootViewController = navController     self.window = window     window.makeKeyAndVisible() } \/\/ \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 SceneDelegate } <\/code><\/pre>\n<p>\u042f \u043d\u0435 \u0431\u0443\u0434\u0443 \u0432\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 UITableView. \u0421\u043a\u043e\u0440\u0435\u0435 \u0432\u0441\u0435\u0433\u043e, \u0432\u044b \u0441 \u043d\u0438\u043c \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0431\u0443\u0434\u0443 \u0434\u0430\u0432\u0430\u0442\u044c \u0438\u0441\u0447\u0435\u0440\u043f\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u0439 \u043f\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u044f\u0447\u0435\u0435\u043a, \u0430 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043a\u0430\u0436\u0443 \u043a\u043e\u0434 \u0441 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 RocketsViewController \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043e\u0434\u043d\u043e\u0438\u043c\u0451\u043d\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<p>\u0412 TableView \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u043a\u0438\u0434\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u044f\u0447\u0435\u0439\u043a\u0430 RocketCell, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b.<\/p>\n<p>\u0414\u043b\u044f \u0447\u0438\u0442\u0430\u0435\u043c\u043e\u0441\u0442\u0438 \u043a\u043e\u0434\u0430 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e \u043a\u043b\u043e\u0436\u0443\u0440\u043d\u0443\u044e \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 setupViews() \u0434\u043b\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e \u0438 setupConstraints() \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043b\u0435\u0439\u0430\u0443\u0442\u0430 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 SnapKit \u2014 \u044f \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u043b \u0435\u0433\u043e \u0447\u0435\u0440\u0435\u0437 SPM.<\/p>\n<h4>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440 RocketsViewController<\/h4>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043a \u0442\u043e\u043c\u0443, \u0440\u0430\u0434\u0438 \u0447\u0435\u0433\u043e \u043c\u044b \u0442\u0443\u0442 \u0441\u043e\u0431\u0440\u0430\u043b\u0438\u0441\u044c.<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b Swift \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c RocketsViewController. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u043a\u0435\u0442 SpaceXAPI, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 SnapKit \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u0430\u043c\u0438.<\/p>\n<pre><code class=\"swift\">import UIKit import SpaceXAPI import SnapKit <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043b\u0430\u0441\u0441 \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0432\u044c\u044e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0435 RocketsViewController:<\/p>\n<pre><code class=\"swift\">\/\/ \u0424\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 RocketsViewController final class RocketsViewController: UIViewController { \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 rockets, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445, \u0441\u044e\u0434\u0430 \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0441\u043a\u043b\u0434\u044b\u0432\u0430\u0442\u044c \u0440\u0430\u043a\u0435\u0442\u044b, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043d\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 Apollo private var rockets: [RocketsQuery.Data.Rocket] = [] \/\/ \u041f\u0440\u0438\u0432\u0430\u0442\u043d\u0430\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u043d\u0430\u0437\u043e\u0432\u0451\u043c \u044f\u0447\u0435\u0439\u043a\u0443 RocketCell \u2014 \u043c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0435\u0451 \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 private lazy var tableView: UITableView = { let tv = UITableView(frame: .zero, style: .plain) tv.dataSource = self tv.delegate = self tv.register(RocketCell.self, forCellReuseIdentifier: \"RocketCell\") return tv }() \/\/ \u041f\u0440\u043e\u043a\u0438\u043d\u0435\u043c \u0432\u043e \u0432\u044c\u044e\u0434\u0438\u0434\u043b\u043e\u0430\u0434 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e, \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0438\u043d\u0442\u043e\u0432 \u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445 override func viewDidLoad() { super.viewDidLoad() \/\/ \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u044b setupViews() setupConstraints() \/\/ \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043e \u0440\u0430\u043a\u0435\u0442\u0430\u0445, \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0438\u0436\u0435 fetchRockets() } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438\u0435\u0440\u0430\u0440\u0445\u0438\u0438 \u0432\u044c\u044e private func setupViews() { view.addSubview(tableView) } \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0438\u043d\u0442\u043e\u0432 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c SnapKit private func setupConstraints() { tableView.snp.makeConstraints { make in make.edges.equalToSuperview() } } } <\/code><\/pre>\n<p>\u0414\u0430\u043b\u0435\u0435 \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043c delegate \u0438 dataSource \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<pre><code class=\"swift\">extension RocketsViewController: UITableViewDelegate, UITableViewDataSource { \/\/ \u0424\u0443\u043d\u043a\u0446\u0438\u044f<\/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-352559","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/352559","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=352559"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/352559\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=352559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=352559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=352559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}