{"id":299583,"date":"2020-03-03T09:00:20","date_gmt":"2020-03-03T09:00:20","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=299583"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=299583","title":{"rendered":"\u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f HTTP \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432 Swift 5 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Combine \u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0438\u0445 \u0432 SwiftUI. \u0427\u0430\u0441\u0442\u044c 2. Hacker News"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/490486\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yp\/go\/he\/ypgohe5omouinjf-e93ilcegdvs.png\"><\/p>\n<p>  <a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0447\u0435\u0439 <code>API<\/code> \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0430\u0439\u0442\u043e\u043c, \u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430\u0445 \u0438 \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0435. \u0415\u0441\u043b\u0438 \u0432\u044b \u0441 \u043d\u0438\u043c \u0435\u0449\u0451 \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b, \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/en\/tc\/m1\/entcm1vprul86isvrkmtx3slaeq.png\"><\/p>\n<p>  \u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445\u00a0\u00a0\u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/modern-networking-in-swift-5-with-urlsession-combine-and-codable\/\" rel=\"nofollow\">\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432<\/a>\u00a0<a href=\"https:\/\/developers.themoviedb.org\/3\/getting-started\/introduction\" rel=\"nofollow\">TMDb<\/a>\u00a0\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/488442\/\">\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0NewsAPI.org<\/a>\u00a0\u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u00a0<code>Combine <\/code>\u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <code>HTTP<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\u00a0\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0445 \u0432\u043e\u00a0<code>View Model<\/code>\u00a0\u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<code> UI<\/code>, \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>SwiftUI<\/code>.\u00a0\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043c \u0442\u0443 \u0436\u0435 \u0441\u0430\u043c\u0443\u044e \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u043e\u043c \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u00ab\u0432\u043d\u0435\u0448\u043d\u0438\u043c\u00bb \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u043c\u00a0<code>Timer<\/code> \u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p>  \u041d\u0430\u0434\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u0435\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0434\u0440\u0443\u0433\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u0447\u0435\u043c \u0432 \u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u043c \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0435\u00a0<a href=\"https:\/\/newsapi.org\/\" rel=\"nofollow\">NewsAPI.org<\/a>, \u043d\u043e \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>HTTP<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>Combine<\/code>, \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438.\u00a0\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a> \u043e\u0447\u0435\u043d\u044c \u0447\u0430\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>Timer<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0435 \u043d\u0430 \u0441\u0430\u0439\u0442 \u043d\u043e\u0432\u044b\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (<code>Story<\/code>), \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0438\u0445 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u044d\u0442\u043e\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0435.<\/p>\n<p>  <code>API<\/code>\u00a0\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. \u042d\u0442\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u043a\u043e\u0434\u043e\u043c \u0431\u0435\u0437 \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u043a\u0430\u043a \u043c\u044b \u0434\u0435\u043b\u0430\u043b\u0438 \u044d\u0442\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 <code>public APIs<\/code>. <br \/>  <a name=\"habracut\"><\/a><br \/>  \u041d\u0430\u0448\u0430 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Combine<\/code> \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb\u00a0<code>Publisher\u00a0<\/code>\u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0437\u0430\u0442\u0435\u043c \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f\u00bb \u0432<code>\u00a0ObservableObject<\/code> \u043a\u043b\u0430\u0441\u0441\u0430\u0445 \u0441\u00a0<code>@Published\u00a0<\/code>\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438, \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445\u00a0<code>SwiftUI<\/code> \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u0442 \u0438 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u00ab\u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u00bb \u0441\u0432\u043e\u0438\u00a0<code>View<\/code>.<\/p>\n<p>  \u0412 \u044d\u0442\u0438\u00a0<code>ObservableObject <\/code>\u043a\u043b\u0430\u0441\u0441\u044b \u043c\u044b \u0437\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0442\u0435\u043c, \u0447\u0442\u043e \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u044d\u0442\u0438\u0445\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043c\u043e\u0433\u0443\u0442 \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043b\u0438\u0431\u043e \u0442\u0430\u043a\u0438\u043c\u0438 \u00ab\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438\u00bb \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (<code>U<\/code>I) \u043a\u0430\u043a \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f <code>TextField<\/code>, <code>Picker<\/code>, <code>Steppe<\/code>r, <code>Toggle<\/code>, \u043b\u0438\u0431\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb \u0442\u0438\u043f\u0430\u00a0<code>Timer<\/code>, \u0430 \u0434\u0440\u0443\u0433\u0438\u0435\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u00ab\u043f\u0430\u0441\u0441\u0438\u0432\u043d\u044b\u043c\u0438\u00bb, \u044f\u0432\u043b\u044f\u044f\u0441\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u043c \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u0438\/ \u0438\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0439 \u00ab\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445\u00bb\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432, \u043d\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043d\u0438 \u0442\u043e \u043d\u0430\u0441 \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442. <br \/>  \u0417\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c\u00a0\u00ab\u043f\u0430\u0441\u0441\u0438\u0432\u043d\u044b\u0445\u00bb\u00a0\u043e\u0442 \u00ab\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445\u00bb\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Combine<\/code>\u00a0\u0432\u00a0<code>ObservableObject<\/code> \u043a\u043b\u0430\u0441\u0441\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435\u00a0 \u0432\u044b\u0441\u0442\u0443\u043f\u0430\u044e\u0442 \u0432 \u0440\u043e\u043b\u0438\u00a0<code>View Model\u00a0<\/code>\u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f <code>UI<\/code> \u0432 <code>SwiftUI<\/code>.\u00a0<\/p>\n<p>  \u041e\u0442\u043b\u0438\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0435 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u043e, \u0447\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0431\u0435\u0437 \u0443\u0447\u0430\u0441\u0442\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0432\u043d\u0435\u0448\u043d\u0435\u043c\u0443 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044e\u00bb\u00a0<code>Timer.<\/code> \u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0441\u0440\u0435\u0434\u043e\u0442\u043e\u0447\u0438\u0442\u044c\u0441\u044f \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043d\u0430 \u044d\u0442\u043e\u043c, <code>UI<\/code> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0443\u043f\u0440\u043e\u0449\u0435\u043d: \u043e\u043d \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u00ab\u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a\u00bb (<code>images<\/code>), \u043a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0438\u0441\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0439. \u0417\u0430\u0442\u043e \u0432\u0440\u0435\u043c\u044f, \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0435\u0435 \u0441 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f. \u041f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u043d\u043e\u0432\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u0438\u0432\u043d\u043e \u043e\u0442\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u0430 <code>UI<\/code> \u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0437\u0432\u0443\u043a\u043e\u0432\u044b\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/8_\/hm\/ju\/8_hmjudnu5sejwnzqhcnzzqg_z0.png\"><\/p>\n<p>  \u0421\u043f\u0443\u0441\u0442\u044f 4 \u043c\u0438\u043d\u0443\u0442 \u043c\u044b \u0443\u0432\u0438\u0434\u0438\u043c \u0442\u0430\u043a\u043e\u0439 \u044d\u043a\u0440\u0430\u043d:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1b\/0k\/3v\/1b0k3vncxmtxfj0yai29ytveurw.png\"><\/p>\n<p>  \u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/HackerNewsApp\" rel=\"nofollow\">Github<\/a>.<\/p>\n<h2>\u041c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 <code>API<\/code> \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a><\/h2>\n<p>  \u0421\u0435\u0440\u0432\u0438\u0441\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u0430\u043c\u044b\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445, \u0442\u043e\u043f\u043e\u0432\u044b\u0445, \u0441\u0430\u043c\u044b\u0445 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u044f\u0445 <code>[Story]<\/code> \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>Story<\/code>\u00a0\u043f\u043e \u0435\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443<code>\u00a0id<\/code>. \u041d\u0430\u0448\u0430 \u041c\u043e\u0434\u0435\u043b\u044c \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439,\u00a0\u043e\u043d\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0435 <i>Story.swift:<\/i><\/p>\n<pre><code class=\"swift\">import Foundation  struct Story: Codable, Identifiable {   let id: Int   let title: String   let by: String   let time: TimeInterval   let url: String }<\/code><\/pre>\n<p>  \u0418\u0441\u0442\u043e\u0440\u0438\u044f\u00a0<code>Story<\/code>\u00a0\u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 <code>id<\/code>, \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435<code> title<\/code>, \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u00a0<code>description<\/code>, \u0430\u0432\u0442\u043e\u0440\u0430<code> by<\/code>, \u0434\u0430\u0442\u0443 \u043f\u0443\u0431\u043b\u0438\u043a\u0430\u0446\u0438\u0438 <code>time<\/code> \u0438\u00a0<code>URL<\/code>\u00a0\u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>url<\/code>.\u00a0\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code>Story<\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code>Codable<\/code>, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043d\u0430\u043c \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439 \u043a\u043e\u0434\u0430 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c <code>JSON<\/code> \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u041c\u043e\u0434\u0435\u043b\u044c. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u00a0<code>Story<\/code>\u00a0\u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0435\u0449\u0435 \u0438 <code>Identifiable<\/code>, \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0431\u043b\u0435\u0433\u0447\u0438\u0442\u044c \u0441\u0435\u0431\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0439<code>\u00a0[Story]<\/code> \u0432 \u0432\u0438\u0434\u0435 \u0441\u043f\u0438\u0441\u043a\u0430\u00a0<code>List<\/code>\u00a0\u0432 <code>SwiftUI<\/code>. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b <code>Identifiable<\/code> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f <code>Hashable<\/code> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>id<\/code>,\u00a0\u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439 \u043e\u0442 \u043d\u0430\u0441 \u043d\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a\u043e\u0439 \u043d\u0430\u043c \u043d\u0443\u0436\u0435\u043d\u00a0<code>API <\/code>\u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0, \u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0435\u0433\u043e \u0432 \u0444\u0430\u0439\u043b\u0435\u00a0<i>NewsAPI.swift<\/i>. \u0426\u0435\u043d\u0442\u0440\u0430\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043d\u0430\u0448\u0435\u0433\u043e <code>API<\/code>\u00a0\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f\u00a0\u043a\u043b\u0430\u0441\u0441 <code>NewsAPI<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u0434\u0432\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u0437 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0&#8212; \u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>Story<\/code>\u00a0\u0441 \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c\u00a0<code>id<\/code> \u0438 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0445 \u043d\u0430\u0441 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>[Story]<\/code> \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e <code>endpoint<\/code>:<\/p>\n<ul>\n<li><code>story (id: Int) -&gt; AnyPublisher&lt;Story, Never&gt;<\/code> &#8212;\u00a0\u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>Story<\/code>\u00a0\u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c<code>\u00a0id<\/code>,<\/li>\n<li><code>stories (from endpoint: Endpoint)\u00a0-&gt; AnyPublisher&lt;[Story], Never&gt;<\/code> \u2014 \u0432\u044b\u0431\u043e\u0440\u043a\u0430\u00a0\u0438\u0441\u0442\u043e\u0440\u0438\u0439<code> [Story]<\/code>\u00a0\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>endpoint<\/code>.<\/li>\n<\/ul>\n<p>  \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435\u00a0\u043d\u043e\u0432\u043e\u0433\u043e\u00a0 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430\u00a0<code>Combine<\/code> \u044d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u00a0\u0438\u0441\u0442\u043e\u0440\u0438\u044e\u00a0<code>Story<\/code> \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>[Story]<\/code>, \u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb\u00a0<code>Publisher<\/code>.\u00a0\u00a0\u041e\u0431\u0430 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u043d\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442 \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u043e\u0448\u0438\u0431\u043a\u0438 \u2014 <code>Never<\/code>, \u0430 \u0435\u0441\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0438\u043b\u0438 \u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435-\u0442\u0430\u043a\u0438 \u0438\u043c\u0435\u043b\u0430 \u043c\u0435\u0441\u0442\u043e, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u043f\u0443\u0441\u0442\u043e\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>[Story]()\u00a0<\/code>\u0438\u043b\u0438 \u043f\u0443\u0441\u0442\u043e\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u00bb <code>Empty<\/code>\u00a0\u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439, \u043f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0438\u043b\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u043f\u0443\u0441\u0442\u044b\u043c\u0438.\u00a0<\/p>\n<p>  \u0422\u043e, \u043a\u0430\u043a\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0431\u0443\u0434\u0435\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f\u00a0<code>enum Endpoint<\/code>:<\/p>\n<pre><code class=\"swift\">enum Endpoint {   static let baseURL =                   URL(string: &quot;https:\/\/hacker-news.firebaseio.com\/v0\/&quot;)!      case newstories, topstories, beststories   case story(Int)      var url: URL {     switch self {     case .newstories:       return Endpoint.baseURL.appendingPathComponent(&quot;newstories.json&quot;)     case .topstories:       return Endpoint.baseURL.appendingPathComponent(&quot;topstories.json&quot;)     case .beststories:       return Endpoint.baseURL.appendingPathComponent(&quot;beststories.json&quot;)     case .story(let id):       return Endpoint.baseURL.appendingPathComponent(&quot;item\/\\(id).json&quot;)     }   } }<\/code><\/pre>\n<p>  \u042d\u0442\u043e:<\/p>\n<ul>\n<li>\u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438\u00a0<code>.newstories<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 1-2 \u043c\u0438\u043d\u0443\u0442\u044b,<\/li>\n<li>\u0442\u043e\u043f\u043e\u0432\u044b\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438\u00a0\u00a0<code>.topstories<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u0436\u0434\u044b\u0435 1-2 \u0447\u0430\u0441\u0430,<\/li>\n<li>\u0441\u0430\u043c\u044b\u0435 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043d\u043e\u0432\u043e\u0441\u0442\u0438\u00a0<code>.beststories<\/code>\u00a0\u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0432 \u0434\u0435\u043d\u044c,<\/li>\n<li>\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f\u00a0<code>.story(Int)<\/code> \u0441\u00a0\u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c\u00a0<code>id<\/code>\u00a0.<\/li>\n<\/ul>\n<p>  \u0414\u043b\u044f \u043e\u0431\u043b\u0435\u0433\u0447\u0435\u043d\u0438\u044f \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0443\u0436\u043d\u043e\u0439 \u043d\u0430\u043c \u043e\u043f\u0446\u0438\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 <code>Endpoint<\/code> \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 <code>init?<\/code> \u0434\u043b\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0433\u043e \u0440\u043e\u0434\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439:<\/p>\n<pre><code class=\"swift\">init? (index: Int) {            switch index {            case 0: self = .newstories            case 1: self = .topstories            case 2: self = .beststories            default: return nil            }        }<\/code><\/pre>\n<p>  \u0412 \u043a\u043b\u0430\u0441\u0441\u0435 <code>NewsAPI<\/code>\u00a0\u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043f\u0435\u0440\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0<code>story (id: Int) -&gt; AnyPublisher&lt;Story, Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0438\u0441\u0442\u043e\u0440\u0438\u044e\u00a0<code>Story<\/code> \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0435\u0451 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u00a0<code>id<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6h\/jh\/dw\/6hjhdw9ockzppan0n627d0m5yvk.png\"><\/p>\n<ol>\n<li>\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435<code> id<\/code>\u00a0\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c <code>URL Endpoint.story(id).url\u00a0<\/code>\u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0443\u0436\u043d\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>dataTaskPublisher(for:)<\/code>, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0442\u0435\u0436 <code>(data: Data, response: URLResponse)<\/code>, \u0430\u00a0\u043e\u0448\u0438\u0431\u043a\u043e\u0439 <code>\u00a0-\u00a0URLError<\/code>,<\/li>\n<li>\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>map { }<\/code> \u0431\u0435\u0440\u0435\u043c \u0438\u0437 \u043a\u043e\u0440\u0442\u0435\u0436\u0430 <code>(data: Data, response: URLResponse)<\/code> \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0430\u043d\u043d\u044b\u0435\u00a0<code>data<\/code>,\u00a0<\/li>\n<li>\u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u043c <code>JSON <\/code>\u0434\u0430\u043d\u043d\u044b\u0435<code>\u00a0data<\/code> \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u041c\u043e\u0434\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439<code>\u00a0Story<\/code>,\u00a0<\/li>\n<li>\u043f\u0440\u0438 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u043e\u0432\u0435\u043d\u0438\u0438 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u043e\u0448\u0438\u0431\u043e\u043a \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0448\u0430\u0433\u0430\u0445 \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>Empty<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>catch {\u00a0 }<\/code>,<\/li>\n<li>\u00ab\u0441\u0442\u0438\u0440\u0430\u0435\u043c\u00bb \u0422\u0418\u041f \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>eraseToAnyPublisher()<\/code> \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 <code>AnyPublisher<\/code>.<\/li>\n<\/ol>\n<p>  \u0417\u0430\u0434\u0430\u0447\u0430 \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>[Story]<\/code> \u0432\u043e\u0437\u043b\u043e\u0436\u0435\u043d\u0430 \u043d\u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u043c\u0435\u0442\u043e\u0434\u00a0<code>stories (from endpoint: Endpoint)\u00a0-&gt; AnyPublisher&lt;[Story], Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u043c \u043f\u0440\u0435\u0434\u0441\u0442\u043e\u0438\u0442 \u0441\u043e\u0431\u0440\u0430\u0442\u044c \u0438\u0437 \u043a\u0443\u0441\u043e\u0447\u043a\u043e\u0432.<\/p>\n<p>  \u0415\u0441\u043b\u0438 \u043c\u044b \u043f\u043e\u0432\u0442\u043e\u0440\u0438\u043c \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u0443\u044e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u043c\u0435\u0442\u043e\u0434\u0435, \u043d\u043e \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u043e\u0433\u043e <code>URL\u00a0endpoint.url<\/code>,\u2026<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/_o\/d0\/85\/_od085kwbg-ybpgtjqjxvhjxevu.png\"><\/p>\n<p>  \u2026 \u0442\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0446\u0435\u043b\u044b\u0445 \u0447\u0438\u0441\u0435\u043b<code> [Int]<\/code>, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c <code>ids<\/code>\u00a0\u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u043d\u0430\u043f\u043e\u0434\u043e\u0431\u0438\u0435:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/qs\/b_\/_m\/qsb__mfhpfxyy1sb_trunxytify.png\"><\/p>\n<p>  \u041d\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0438\u0445 \u0431\u0443\u0434\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u2014 500.<\/p>\n<p>  \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u044d\u0442\u0438\u00a0 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>ids<\/code> \u0432 \u0441\u0430\u043c\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0438. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>mergedStories (ids:)<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>id<\/code> \u00a0\u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>AnyPublisher&lt;Story, Never&gt;<\/code> \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0442\u044c \u0438\u0445 \u0432\u0441\u0435 \u0432\u043c\u0435\u0441\u0442\u0435:<\/p>\n<pre><code class=\"swift\">func mergedStories(ids storyIDs: [Int])                                      -&gt; AnyPublisher&lt;Story, Never&gt;{ .  .  .  .  .  .  .  .  .  .  .  .  . }<\/code><\/pre>\n<p>  \u041f\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443, \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c <code>story(id:)<\/code> \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u0438\u0437 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 <code>ids<\/code> \u0438 \u0437\u0430\u0442\u0435\u043c \u00ab\u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c\u00bb (<code>flatten<\/code>) \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0435\u0434\u0438\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439.<\/p>\n<p>  \u041f\u0440\u0435\u0436\u0434\u0435 \u0432\u0441\u0435\u0433\u043e, \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0432\u044b\u0435 <code>maxStories ids <\/code>\u0438\u0437 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 <code>ids<\/code>:<\/p>\n<pre><code class=\"swift\">func mergedStories(ids storyIDs: [Int])                                      -&gt; AnyPublisher&lt;Story, Never&gt;{ let storyIDs = Array(storyIDs.prefix(maxStories)) precondition(!storyIDs.isEmpty) .  .  .  .  .  .  .  .  .  .  .  .  . }<\/code><\/pre>\n<p>  \u0421 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>story(id:)<\/code>\u00a0\u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>initialPublisher<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442 \u0438\u0441\u0442\u043e\u0440\u0438\u044e <code>Story<\/code> \u0441 \u043f\u0435\u0440\u0432\u044b\u043c<code> id<\/code> \u0432 \u0441\u043f\u0438\u0441\u043a\u0435<code>\u00a0ids<\/code>:<\/p>\n<pre><code class=\"swift\">func mergedStories(ids storyIDs: [Int])                                      -&gt; AnyPublisher&lt;Story, Never&gt;{   let storyIDs = Array(storyIDs.prefix(maxStories))   precondition(!storyIDs.isEmpty)    let initialPublisher = story(id: storyIDs[0])   let remainder = Array(storyIDs.dropFirst()) .  .  .  .  .  .  .  .  .  .  .  .  . }<\/code><\/pre>\n<p>  \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>reduce(_:_:)<\/code> \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <code>Swift<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u043f\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043d\u0430\u0434 \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u043c\u0438\u0441\u044f <code>ids<\/code>, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0441 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c<code>\u00a0id<\/code> \u043a \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044e\u00bb <code>initialPublisher<\/code>:<\/p>\n<pre><code class=\"swift\">func mergedStories(ids storyIDs: [Int])                                  -&gt; AnyPublisher&lt;Story, Never&gt; {     let storyIDs = Array(storyIDs.prefix(maxStories))     precondition(!storyIDs.isEmpty)      let initialPublisher = story(id: storyIDs[0])     let remainder = Array(storyIDs.dropFirst())          return remainder.reduce(initialPublisher) {                 (combined, id) -&gt; AnyPublisher&lt;Story, Never&gt; in         combined.merge(with: story(id: id))         .eraseToAnyPublisher()     }   }<\/code><\/pre>\n<p>  \u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u2014 \u044d\u0442\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u00ab\u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u0442\u00bb \u043a\u0430\u0436\u0434\u0443\u044e \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u0443\u044e \u0438\u0441\u0442\u043e\u0440\u0438\u044e\u00a0<code>Story<\/code> \u0438 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442 \u043b\u044e\u0431\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0443\u0442\u044c \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043a\u0430\u0436\u0434\u043e\u0439 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u0435\u0440\u043d\u0443\u0442\u044c\u0441\u044f \u043a \u043c\u0435\u0442\u043e\u0434\u0443 \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>stories (from endpoint: Endpoint)\u00a0-&gt; AnyPublisher&lt;[Story], Never&gt;<\/code>. \u041c\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u0435\u043d\u0438\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0434\u043b\u044f\u00a0<code>endpoint.url\u00a0<\/code>\u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043d\u0430\u0441 \u043a \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>ids<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u043e\u0434\u043d\u0443 \u0437\u0430 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>:<\/p>\n<pre><code class=\"swift\">func stories(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Story], Never&gt; {     URLSession.shared.dataTaskPublisher(for: endpoint.url)       .map { $0.0 }       .decode(type: [Int].self, decoder: JSONDecoder())       .catch { _ in Empty() }        .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .       .eraseToAnyPublisher()   }<\/code><\/pre>\n<p>  \u041d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043c\u044b \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u043d\u0435\u0436\u0435\u043b\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430 \u0438 \u0434\u043b\u044f \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>ids<\/code>\u00a0\u0432 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438.<\/p>\n<p>  \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043e\u0442\u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u043f\u0443\u0441\u0442\u043e\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0443 \u043c\u0435\u0442\u043e\u0434\u0430 <code>mergedStories(ids:)<\/code> \u0435\u0441\u0442\u044c \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435 <code>precondition<\/code>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442 \u043d\u0435\u043f\u0443\u0441\u0442\u043e\u0439 \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440:<\/p>\n<pre><code class=\"swift\">func stories(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Story], Never&gt; {     URLSession.shared.dataTaskPublisher(for: endpoint.url)       .map { $0.0 }       .decode(type: [Int].self, decoder: JSONDecoder())       .catch { _ in Empty() }       .filter { !$0.isEmpty }         .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .       .eraseToAnyPublisher()   }<\/code><\/pre>\n<p>  \u041d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>storyIDs <\/code>\u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e<code> flatMap<\/code>:<\/p>\n<pre><code class=\"swift\">func stories(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Story], Never&gt; {     URLSession.shared.dataTaskPublisher(for: endpoint.url)       .map { $0.0 }       .decode(type: [Int].self, decoder: JSONDecoder())       .catch { _ in Empty() }       .filter { !$0.isEmpty }       .flatMap { storyIDs in self.mergedStories(ids: storyIDs)}         .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .       .eraseToAnyPublisher()   }<\/code><\/pre>\n<p>  \u042d\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439 \u043f\u043e\u0442\u043e\u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439<code> Story<\/code>, \u043f\u0440\u0438\u0447\u0435\u043c \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u043e\u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u043c\u0435\u0440\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430. \u041c\u044b \u0436\u0435 \u0445\u043e\u0442\u0438\u043c \u0438\u043c\u0435\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 \u0432\u0438\u0434\u0435 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>[Story]<\/code>, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 <code>View Controller<\/code> \u0438\u043b\u0438 \u0432 <code>SwiftUI View<\/code>.<\/p>\n<p>  \u041f\u0440\u0435\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043f\u043e\u0442\u043e\u043a\u0430 \u0438\u043d\u0434\u0438\u0432\u0438\u0434\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \u0442\u0430\u043a\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0443\u0434\u043e\u0431\u043d\u044b\u043c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c <code>collect<\/code>:<\/p>\n<pre><code class=\"swift\">func stories(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Story], Never&gt; {     URLSession.shared.dataTaskPublisher(for: endpoint.url)       .map { $0.0 }       .decode(type: [Int].self, decoder: JSONDecoder())       .catch { _ in Empty() }       .filter { !$0.isEmpty }       .flatMap { storyIDs in self.mergedStories(ids: storyIDs)}       .collect(maxStories)           .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .       .eraseToAnyPublisher()   }<\/code><\/pre>\n<p>  \u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u043f\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0443\u00a0<code>id<\/code>, \u0430 \u0444\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0445\u0440\u043e\u043d\u043e\u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u00a0<code>sorted()<\/code>. \u042d\u0442\u043e \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u043c \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430 \u0441\u0430\u0439\u0442\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u043f\u043e\u0441\u0442\u0443\u043f\u0438\u043b\u0430 \u043d\u043e\u0432\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u0438 \u043f\u043e\u0440\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c <code>UI<\/code>.<\/p>\n<pre><code class=\"swift\">func stories(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Story], Never&gt; {     URLSession.shared.dataTaskPublisher(for: endpoint.url)       .map { $0.0 }       .decode(type: [Int].self, decoder: JSONDecoder())       .catch { _ in Empty() }       .filter { !$0.isEmpty }       .flatMap { storyIDs in self.mergedStories(ids: storyIDs)}       .collect(maxStories)       .map { stories in  stories.sorted (by: {$0.id &gt; $1.id})}           .eraseToAnyPublisher()   }<\/code><\/pre>\n<p>  \u041a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u043c \u00ab\u0441\u0442\u0438\u0440\u0430\u043d\u0438\u044f \u0422\u0418\u041f\u0410\u00bb <code>eraseToAnyPublisher()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443 \u043d\u0430\u0441 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/qj\/o7\/fs\/qjo7fslsls16sndmazgn0x0ywuq.png\"><\/p>\n<p>  \u0423\u0447\u0438\u0442\u044b\u0432\u0430\u044f, \u0447\u0442\u043e\u00a0\u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>NewAPI<\/code> \u0432\u0441\u0435 \u0442\u0440\u0438 \u043c\u0435\u0442\u043e\u0434\u0430 \u2014 <code>story (id: Int)<\/code>, <code>storyIDs (from endpoint: Endpoint)<\/code> \u0438 <code>stories (from endpoint: Endpoint)<\/code> \u2014 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0441\u0445\u043e\u0436\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u0443\u044e \u043d\u0430\u043c \u043f\u043e <a href=\"https:\/\/habr.com\/ru\/post\/488442\/\">\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e<\/a> \u00a0<code>Generic<\/code> \u0444\u0443\u043d\u043a\u0446\u0438\u044e, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0443\u044e\u00a0\u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>AnyPublisher&lt;T, Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438\u00a0\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e\u00a0<code>url<\/code> \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u00a0<code>JSON<\/code> \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0443\u0435\u0442 \u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 \u0435\u0451 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 <code>Codable<\/code> \u041c\u043e\u0434\u0435\u043b\u0438 <code>T<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/y0\/zb\/di\/y0zbdidyjqkny4xxzoyaximi4si.png\"><\/p>\n<p>  \u042d\u0442\u043e\u0442 \u043a\u043e\u0434 \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>Publisher<\/code>, \u0435\u0441\u043b\u0438 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0434\u043b\u044f <code>url <\/code>\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440,\u00a0<code>Endpoint<\/code> \u00a0\u0434\u043b\u044f \u0441\u0435\u0440\u0432\u0438\u0441\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u041c\u043e\u0434\u0435\u043b\u0438 &#8212;\u00a0 \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0441\u0442\u043e\u0440\u0438\u044e<code>\u00a0Story <\/code>, \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>[Story]<\/code> \u0438\u043b\u0438 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>[Int]<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/jk\/on\/03\/jkon03ci9miutbgajlnjue64rey.png\"><\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0438\u00bb <code>AnyPublisher<\/code> \u0441\u0430\u043c\u0438 \u043f\u043e \u0441\u0435\u0431\u0435 \u00ab\u043d\u0435 \u0432\u0437\u043b\u0435\u0442\u0430\u044e\u0442\u00bb, \u043e\u043d\u0438 \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440, \u043f\u043e\u043a\u0430 \u043d\u0430 \u043d\u0438\u0445 \u043a\u0442\u043e-\u0442\u043e \u043d\u0435 \u00ab\u043f\u043e\u0434\u043f\u0438\u0448\u0435\u0442\u0441\u044f\u00bb. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 <code>UI<\/code>\u00a0\u0432\u00a0<code>SwiftUI<\/code>\u00a0\u0438 \u00ab\u043f\u043e\u0434\u043f\u0438\u0448\u0435\u043c\u0441\u044f\u00bb \u043d\u0430 \u043d\u0438\u0445 \u0432\u00a0<code>ObservableObject<\/code>\u00a0\u043a\u043b\u0430\u0441\u0441\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0421\u0418\u041d\u0425\u0420\u041e\u041d\u0418\u0417\u0418\u0420\u0423\u0415\u0422 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u00a0<code>View<\/code>.<\/p>\n<h2>\u00ab\u0418\u0437\u0434\u0430\u0442\u0435\u043b\u0438\u00bb <code>Publisher<\/code> \u043a\u0430\u043a <code>View Model <\/code>\u0432 <code>SwiftUI<\/code>. \u0421\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439<\/h2>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432 <code>SwiftUI<\/code> \u0434\u043e\u043b\u0436\u043d\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0438\u00bb \u043d\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0430\u043c\u044b\u0445 \u0441\u0432\u0435\u0436\u0438\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0441 \u0441\u0430\u0439\u0442\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yp\/go\/he\/ypgohe5omouinjf-e93ilcegdvs.png\"><\/p>\n<p>  \u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0441 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0432\u0435\u0436\u0438\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>stories<\/code>, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0430\u0439\u0442\u0430\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0434\u043e\u043b\u0436\u0435\u043d \u0432\u0441\u0435 \u0432\u0440\u0435\u043c\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f.<\/p>\n<p>  \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0443\u043c\u0435\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0432\u0438\u0434\u044b \u0438\u0441\u0442\u043e\u0440\u0438\u0439: \u0441\u0432\u0435\u0436\u0438\u0435 (<code>news<\/code>), \u0442\u043e\u043f\u043e\u0432\u044b\u0435 (<code>top<\/code>) \u0438\u043b\u0438 \u0441\u0430\u043c\u044b\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 (<code>best<\/code>):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/c9\/3z\/ig\/c93zigswuytycltp7qs9jepspxe.png\"><\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0447\u0435\u043d\u044c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u043a\u043b\u0430\u0441\u0441\u00a0<code>StoriesViewModel<\/code>, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b <code>ObservableObject<\/code>\u00a0\u0441 \u0442\u0440\u0435\u043c\u044f\u00a0<code>@Published<\/code> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u043c\u0438: \u00a0<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/y4\/sg\/p4\/y4sgp4fimzjdibm0svzl-o-v3ji.png\"><\/p>\n<ol>\n<li>\u043e\u0434\u043d\u043e\u00a0<code>@Published var indexEndpoint: Int<\/code> \u2014 \u044d\u0442\u043e \u0438\u043d\u0434\u0435\u043a\u0441 <code>Endpoint <\/code>(\u0443\u0441\u043b\u043e\u0432\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u00ab\u0432\u0445\u043e\u0434\u043e\u043c\u00bb, \u0442\u0430\u043a \u043a\u0430\u043a \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u043d\u0430 <code>View<\/code>),\u00a0\u00a0<\/li>\n<li>\u0432\u0442\u043e\u0440\u043e\u0435\u00a0<code>@Published var currentDate: Date<\/code> \u2014 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f (\u0443\u0441\u043b\u043e\u0432\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u00ab\u0432\u0445\u043e\u0434\u043e\u043c\u00bb, \u0442\u0430\u043a \u043a\u0430\u043a \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 <code>View<\/code>\u00a0\u0432\u043d\u0435\u0448\u043d\u0438\u043c \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u043c\u00bb <code>Timer<\/code>),\u00a0\u00a0<\/li>\n<li>\u0442\u0440\u0435\u0442\u044c\u0435\u00a0<code>@Published var stories: [Story]\u00a0<\/code> \u2014 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439 (\u0443\u0441\u043b\u043e\u0432\u043d\u043e \u00ab\u0432\u044b\u0445\u043e\u0434\u00bb, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0430\u0439\u0442\u0430 <a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00a0<code>currentDate<\/code>\u00a0\u0438 \u0434\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e<code>\u00a0indexEndpoin<\/code>t).<\/li>\n<\/ol>\n<p>  \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043b\u0438<code>\u00a0@Published<\/code>\u00a0\u043f\u0435\u0440\u0435\u0434 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u043c\u00a0<code>currentDate<\/code>, \u043c\u044b\u00a0\u043c\u043e\u0436\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0438 \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e\u00a0<code>currentDate<\/code>,\u00a0 \u0438 \u043a\u0430\u043a \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>$currentDate<\/code>.<\/p>\n<p>  \u0412 \u043a\u043b\u0430\u0441\u0441\u0435\u00a0<code>StoriesViewModel<\/code>, \u043c\u043e\u0436\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0435\u043a\u043b\u0430\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u043d\u043e \u0438 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0443 \u0438\u0445 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u0421 \u044d\u0442\u043e\u0439 \u0446\u0435\u043b\u044c\u044e \u043f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430\u00a0<code>StoriesViewModel\u00a0<\/code>\u0432 <code>init?<\/code> \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443\u00bb, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0431\u0443\u0434\u0435\u0442 \u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u043f\u0440\u043e\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0433\u043e \u00ab\u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430\u00bb \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430\u00a0<code>StoriesViewModel<\/code>, \u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u00a0\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044c \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u00a0<code>stories<\/code>\u00a0\u043e\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00a0<code>currentDate<\/code>\u00a0\u0438 \u043e\u0442 \u0438\u043d\u0434\u0435\u043a\u0441\u0430 <code>indexEndpoint<\/code>.<\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432<code> Combine<\/code> \u043c\u044b \u043f\u0440\u043e\u0442\u044f\u0433\u0438\u0432\u0430\u0435\u043c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u043e\u0442 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb <code>$currentDate<\/code> \u00a0\u0438\u00a0<code>$indexEndpoint<\/code> \u0434\u043e \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>AnyPublisher&lt;[Story], Never&gt;<\/code>, \u0443 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u2014 \u044d\u0442\u043e \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439. \u0412\u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u0438 \u043c\u044b \u00ab\u043f\u043e\u0434\u043f\u0438\u0448\u0435\u043c\u0441\u044f\u00bb \u043d\u0430 \u043d\u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u00bb\u00a0<code>sink\u00a0<\/code>\u0438 \u0435\u0433\u043e \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f\u00a0<code>receiveValue<\/code> \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>stories <\/code>\u043a\u0430\u043a \u00ab\u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0435\u00bb\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0435\u0435<code> UI<\/code>.<\/p>\n<p>  \u041c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0442\u044f\u043d\u0443\u0442\u044c \u0446\u0435\u043f\u043e\u0447\u043a\u0443 \u041d\u0415 \u043f\u0440\u043e\u0441\u0442\u043e \u043e\u0442 \u0441\u0432\u043e\u0439\u0441\u0442\u0432 <code>currentDate<\/code> \u0438 <code>indexEndpoint<\/code>, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u0442 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb <code>$currentDate<\/code> \u0438 <code>$indexEndpoint<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0435\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 <code>UI<\/code>\u00a0\u0438 \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043c \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>Timer<\/code> \u0438 <code>Picker<\/code>.<\/p>\n<p>  \u041a\u0430\u043a \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u044d\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c?<\/p>\n<p>  \u0412 \u043d\u0430\u0448\u0435\u043c \u0430\u0440\u0441\u0435\u043d\u0430\u043b\u0435 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>stories (from: Endpoint)<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043a\u043b\u0430\u0441\u0441\u0435\u00a0<code>NewsAPI<\/code> \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>AnyPublisher&lt;[Story], Never<\/code>&gt;, \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u00a0<code>Endpoint<\/code>, \u0438 \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a\u0430\u043a\u0438\u043c-\u0442\u043e \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>$indexEndpoint<\/code>, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u0432\u0440\u0430\u0442\u0438\u0442\u044c \u0435\u0433\u043e \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u044d\u0442\u043e\u0439 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<code>endpoint<\/code>, \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0435 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437 \u043f\u0440\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\u00a0<code>$currentDate<\/code>.<\/p>\n<p>  C\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u043c \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb\u00a0<code>$indexEndpoint<\/code>\u00a0\u0438\u00a0<code>$currentDate<\/code>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 <code>Combine<\/code> \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u00a0<code>Publishers.CombineLates<\/code>t:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1p\/jy\/pv\/1pjypvxqfqco1xnodbjanegdvxq.png\"><\/p>\n<p>  \u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u043d\u0443\u0436\u043d\u043e\u043c\u0443\u00a0 \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044e\u00a0<code>stories (from: Endpoint)<\/code>\u00a0\u0432\u00a0<code>Combine<\/code> \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442\u00a0\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u00a0<code>flatMap<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1s\/sy\/rk\/1ssyrkq8pk8g81wxopt89eu5nnw.png\"><\/p>\n<p>  \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 <code>flatMap<\/code> \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043d\u043e\u0432\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u043e\u0442 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb.<\/p>\n<p>  \u0414\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0430 main \u043f\u043e\u0442\u043e\u043a, \u0442\u0430\u043a \u043a\u0430\u043a \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u0435\u043c \u0432 \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438<code> UI<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/bi\/z4\/kx\/biz4kxsampyo8jws7hnkgu91kq8.png\"><\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u043c\u044b \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f\u00bb \u043d\u0430 \u044d\u0442\u043e\u0433\u043e \u0432\u043d\u043e\u0432\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u0447\u0438\u043a\u0430\u00bb\u00a0<code>sink<\/code>\u00a0\u0438 \u0435\u0433\u043e \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f\u00a0<code>receiveValue<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>stories<\/code>, \u043d\u043e \u043c\u044b \u043d\u0435 \u0441\u043f\u0435\u0448\u0438\u043c \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u043e\u0442 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00a0\u043c\u0430\u0441\u0441\u0438\u0432\u0443\u00a0<code>@Published stories<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ai\/wh\/qg\/aiwhqgzmbednl68yd7ubmkcey5g.png\"><\/p>\n<p>  \u041c\u044b \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c<code> id <\/code>\u0441\u0430\u043c\u043e\u0439 \u0441\u0432\u0435\u0436\u0435\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0438\u0437 \u0432\u043d\u043e\u0432\u044c \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>currentIds.first!<\/code>\u00a0\u0438 <code>id<\/code> \u0441\u0430\u043c\u043e\u0439 \u0441\u0432\u0435\u0436\u0435\u0439 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0443\u0436\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u043d\u044b\u0445 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435,<code> oldIds.first!<\/code>. \u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0435 \u0440\u0430\u0432\u043d\u044b, \u0442\u043e \u0435\u0441\u0442\u044c \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f, \u0442\u043e \u043c\u044b \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>stories<\/code>\u00a0\u043d\u0430\u0448\u0435\u043c\u0443 <code>@Published<\/code>\u00a0\u043c\u0430\u0441\u0441\u0438\u0432\u0443\u00a0<code>stories<\/code>, \u043f\u043e\u043f\u0443\u0442\u043d\u043e \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044f \u0435\u0433\u043e \u0432 <code>oldStories<\/code> \u0438 \u043f\u043e\u0434\u0430\u0432\u0430\u044f \u0437\u0432\u0443\u043a\u043e\u0432\u043e\u0439 \u0441\u0438\u0433\u043d\u0430\u043b. \u0415\u0441\u043b\u0438 \u043d\u0435\u0442, \u0442\u043e <code>@Published stories<\/code> \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f.<br \/>  \u041c\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0442\u043e \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 <code>init( )<\/code> \u0410\u0421\u0418\u041d\u0425\u0420\u041e\u041d\u041d\u041e\u0413\u041e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb \u0438 \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u0430\u043b\u0438\u0441\u044c\u00bb \u043d\u0430 \u043d\u0435\u0433\u043e, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0432 <code>AnyCancellable<\/code> \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443\u00bb, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>private\u00a0var subscriptions<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/_l\/0n\/6c\/_l0n6cd5lmgfjxsez7_jjnz8wxc.png\"><\/p>\n<p>  \u00ab\u041f\u043e\u0434\u043f\u0438\u0441\u043a\u0430\u00bb \u043d\u0430 \u0410\u0421\u0418\u041d\u0425\u0420\u041e\u041d\u041d\u041e\u0413\u041e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432 <code>init( )<\/code>, \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u0432\u0441\u0435\u0433\u043e \u201c\u0436\u0438\u0437\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0446\u0438\u043a\u043b\u0430\u201d \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 <code>StoriesViewMode<\/code>l.<\/p>\n<p>  \u0411\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u043e\u0439 \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0435\u00bb \u043f\u0440\u0438 \u043b\u044e\u0431\u043e\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb <code>$currentDate<\/code> \u0438\u00a0<code>$indexEndpoint<\/code> \u0443 \u043d\u0430\u0441 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439\u00a0 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>stories<\/code> \u0431\u0435\u0437 \u043a\u0430\u043a\u0438\u0445-\u043b\u0438\u0431\u043e \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0443\u0441\u0438\u043b\u0438\u0439. \u0422\u0430\u043a\u043e\u0439\u00a0<code>ObservableObject <\/code>\u043a\u043b\u0430\u0441\u0441\u00a0\u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u00a0<code>View Model<\/code>.<\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c <code>View Model<\/code> \u0434\u043b\u044f \u043d\u0430\u0448\u0438\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u043c \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (<code>UI<\/code>). \u0412 <code>SwiftUI<\/code> \u0434\u043b\u044f \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u0438\u0437\u0430\u0446\u0438\u0438 <code>View<\/code> c <code>ObservableObject<\/code>\u00a0\u041c\u043e\u0434\u0435\u043b\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f <code>@ObservedObject<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0430\u044f\u0441\u044f \u043d\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u043a\u043b\u0430\u0441\u0441\u0430 \u044d\u0442\u043e\u0439 \u041c\u043e\u0434\u0435\u043b\u0438. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0430 \u043f\u0430\u0440\u0430 &#8212;\u00a0<code>ObservableObject<\/code>\u00a0\u043a\u043b\u0430\u0441\u0441 \u0438\u00a0<code>@ObservedObject<\/code> \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f, \u0441\u0441\u044b\u043b\u0430\u044e\u0449\u0430\u044f\u0441\u044f \u043d\u0430 \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u2014 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c\u00a0\u00a0\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (<code>UI<\/code>) \u0432\u00a0<code>SwiftUI<\/code>.<\/p>\n<p>  \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0432\u043e \u0432\u043d\u043e\u0432\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443\u00a0<code>StoriesView<\/code>\u00a0\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e <code>var model<\/code>, \u0438\u043c\u0435\u044e\u0449\u0443\u044e \u0422\u0418\u041f\u00a0<code>StoriesViewModel<\/code>, \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u043c <code>Text (&quot;Hello, World!&quot;)<\/code> \u043d\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>List<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0438\u0441\u0442\u043e\u0440\u0438\u0438 <code>model.stories<\/code>, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435\u00a0 \u0438\u0437 \u043d\u0430\u0448\u0435\u0439\u00a0<code>View Model<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/i9\/zd\/hx\/i9zdhxoogfip4hyydw1p5dcfovk.png\"><\/p>\n<p>  \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0442\u0430\u0442\u0435\u0439 \u0434\u043b\u044f \u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 <code>currentDate = Date()<\/code> \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f <code>indexEndpoint = 0<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c \u044d\u0442\u043e \u0441\u043b\u0443\u0447\u0430\u0439 \u0441\u0432\u0435\u0436\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<code>.newstories<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/op\/ch\/sy\/opchsykxk7pwwmuiwjehnxczy8g.png\"><\/p>\n<p>  \u0421 \u0442\u0435\u0447\u0435\u043d\u0438\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u043d\u0438\u0447\u0435\u0433\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0435 \u0431\u0443\u0434\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u043d\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u0439\u00bb <code>$currentDate<\/code>\u00a0\u0438\u00a0<code>$indexEndpoint<\/code> \u0432 \u043d\u0430\u0448\u0435\u0439 <code>model<\/code>.<\/p>\n<p>  \u0414\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f <code>$currentDate<\/code> \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u00bb <code>Timer<\/code> \u0438 \u0440\u0435\u0430\u043a\u0446\u0438\u044e \u043d\u0430 \u043d\u0435\u0433\u043e \u0432 <code>onReceive (timer)<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/qu\/k0\/m0\/quk0m0fhx6rtjjgiq0wgxv-wo_0.png\"><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e \u043b\u043e\u0433\u0438\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0434\u043b\u044f \u043e\u043f\u0446\u0438\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<code>.newstories<\/code>, \u0442\u043e \u0435\u0441\u0442\u044c \u043a\u0430\u0436\u0434\u044b\u0435 1-2 \u043c\u0438\u043d\u0443\u0442\u044b, \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e \u043c\u0435\u0440\u0435 \u043f\u043e\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0447\u0442\u043e \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u0442\u0441\u044f \u0437\u0432\u0443\u043a\u043e\u0432\u044b\u043c \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u043c:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xa\/cr\/xy\/xacrxy5gdhrrhhvta56k68e1aje.png\"><\/p>\n<p>  \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0438 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>$indexEndpoint<\/code>, \u0435\u0441\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c <code>Picker<\/code> \u043d\u0430 \u043d\u0430\u0448 <code>UI<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/4k\/ot\/h5\/4koth5plt72xthydhkjb0ipsmp8.png\"><\/p>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c\u00a0 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0434\u043b\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0445 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439 (<code>news<\/code>), \u043d\u043e \u0438 \u0442\u043e\u043f\u043e\u0432\u044b\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (<code>top<\/code>), \u0438 \u043b\u0443\u0447\u0448\u0438\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (<code>best<\/code>):<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/c9\/3z\/ig\/c93zigswuytycltp7qs9jepspxe.png\"><\/p>\n<p>  \u041f\u0440\u043e\u0441\u0442\u043e \u0438\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0439 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043e\u043f\u0446\u0438\u0439.<br \/>  \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e <code>View<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xv\/-m\/_v\/xv-m_vvykzvsuitst3x7lyg93cy.png\"><\/p>\n<h2>\u041c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f View Model \u0441 \u0446\u0435\u043b\u044c\u044e \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0439 \u043a \u0441\u0435\u0440\u0432\u0438\u0441\u0443\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a><br \/>  <\/h2>\n<p>  \u0425\u043e\u0442\u044f \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439<code> View Model<\/code> \u043c\u044b \u0441\u043b\u0435\u0434\u0438\u043c \u0437\u0430 \u0442\u0435\u043c, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u043c\u044b \u0432\u0441\u0435 \u0440\u0430\u0432\u043d\u043e \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u0430\u0439\u043c\u0435\u0440<code> Timer<\/code>, \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u0441\u0435\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u0443 \u0438\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432. \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0432\u0441\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0432\u043d\u043e\u0432\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u00ab\u0441\u0442\u0430\u0440\u044b\u0445\u00bb\u00a0 \u0438\u0441\u0442\u043e\u0440\u0438\u0439. \u0415\u0441\u043b\u0438 \u0441\u0440\u0435\u0434\u0438 \u043d\u043e\u0432\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0435\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u00ab\u0441\u0432\u0435\u0436\u0438\u0439\u00bb, \u043c\u044b \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>stories<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ap\/1c\/i4\/ap1ci4zxxdkczen8s7iodm8lbhc.png\"><\/p>\n<p>  \u041d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u044d\u0442\u043e\u0442 \u0430\u043d\u0430\u043b\u0438\u0437 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0440\u0430\u043d\u044c\u0448\u0435, \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u0440\u0430\u0437\u0443 \u0436\u0435, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432 <code>currentIds<\/code> \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0443\u0436\u0435 \u043d\u0430 \u044d\u0442\u043e\u043c \u044d\u0442\u0430\u043f\u0435 \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0440\u044b\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b<code>\u00a0oldIds<\/code> \u0441 \u043d\u043e\u0432\u044b\u043c\u0438 <code>currentIds<\/code>, \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043d\u043e\u0432\u044b\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u00a0<code>currentIds <\/code> \u0438\u0441\u0442\u043e\u0440\u0438\u0438.\u00a0<\/p>\n<p>  \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u00bb <code>AnyPublisher&lt;[Int], Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0438\u0441\u0442\u043e\u0440\u0438\u0439. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00a0<code>func storyIDs(from endpoint: Endpoint) -&gt; AnyPublisher&lt;[Int], Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>NewsAPI<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ss\/4m\/la\/ss4mlaotknent2nkv6cyvneacp0.png\"><\/p>\n<p>  \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0432 \u043d\u043e\u0432\u043e\u0439 <code>View Model<\/code>, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043d\u0430\u0437\u043e\u0432\u0451\u043c<code>\u00a0StoriesViewModelID<\/code>\u00a0\u0438 \u0440\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u043c \u0432 \u0444\u0430\u0439\u043b\u0435 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0438\u043c\u0435\u043d\u0435\u043c:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/fe\/ih\/jb\/feihjbdzafvozyvmig6errfxk4k.png\"><\/p>\n<p>  \u0417\u0434\u0435\u0441\u044c \u0442\u0435 \u0436\u0435 \u0441\u0430\u043c\u044b\u0435 \u00ab\u0432\u0445\u043e\u0434\u043d\u044b\u0435\u00bb \u0438 \u00ab\u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0435\u00bb\u00a0<code>@Published<\/code>\u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u0447\u0442\u043e \u0438 \u0432\u00a0<code>View Model<\/code>\u00a0\u0441 \u0438\u043c\u0435\u043d\u0435\u043c\u00a0<code>StoriesViewModel<\/code>,\u00a0\u0438 \u0442\u0435 \u0436\u0435 \u00ab\u0438\u043d\u0438\u0446\u0438\u0430\u0442\u043e\u0440\u044b\u00bb &#8212;\u00a0 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0438\u00bb <code>$currentDate\u00a0<\/code>\u0438\u00a0<code> $indexEndpoint<\/code>, \u043d\u043e \u0441\u0430\u043c\u0430 \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430\u00bb \u0432 <code>init() <\/code>\u0438\u0434\u0435\u0442 \u043f\u043e \u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044e.<\/p>\n<p>  \u041c\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445\u00a0<code>flatMap<\/code>\u00a0\u0438 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u0434\u043d\u043e \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>self.api.storyIDs (from: Endpoint (index: indexEndpoint )! )<\/code> \u0434\u0430\u0451\u0442 \u043d\u0430\u043c \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b <code>currentIds<\/code>\u00a0\u043d\u043e\u0432\u044b\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439.\u00a0\u0417\u0430\u0442\u0435\u043c \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0435 <code>map <\/code>\u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u043c \u043b\u043e\u0433\u0438\u043a\u0443 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f\u00a0\u0441\u0442\u0430\u0440\u044b\u0445 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u0432\u00a0<code>oldIds<\/code> \u0441 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u00a0<code>currentIds<\/code>, \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0432\u044b\u0431\u043e\u0440\u043a\u0435 \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0438 \u0438\u0445 \u043d\u0430<code> UI<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ea\/uq\/um\/eauqumdsfbesmhejfduf68ahewo.png\"><\/p>\n<p>  \u0414\u0430\u043b\u0435\u0435 \u0432 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u0445 \u0443\u0436\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e<code>\u00a0flatMap<\/code>, \u043f\u043e\u043b\u0443\u0447\u0438\u0432 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b <code>storyIDs<\/code> \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u043d\u0430\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438\u00a0<code>Story<\/code> \u0438 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0438\u0445 \u043f\u043e\u0442\u043e\u043a \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>mergedStories<\/code>, \u0437\u0430\u0442\u0435\u043c \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u0445 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 <code>[Story]<\/code> \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>collect<\/code>, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0444\u0438\u043b\u044c\u0442\u0440\u0443\u0435\u043c \u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0439 \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/6p\/wt\/vd\/6pwtvdgxbw-jxuo4fdnseohy3gi.png\"><\/p>\n<p>  \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0448\u0430\u0433\u043e\u043c \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c\u0441\u044f\u00bb \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>sink<\/code> \u0438 \u0435\u0433\u043e \u0437\u0430\u043c\u044b\u043a\u0430\u043d\u0438\u044f\u00a0<code>receiveValue<\/code>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0443\u0436\u043d\u044b\u0439 \u043d\u0430\u043c \u043c\u0430\u0441\u0441\u0438\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439\u00a0<code>stories<\/code> \u0438 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>@Published<\/code> \u00a0\u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0443\u00a0<code>stories<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/uk\/na\/nx\/uknanx_2hydixzhu3v-lybnuaxo.png\"><\/p>\n<p>  \u041d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u0443\u044e \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435\u00a0<code>AnyCancellable<\/code> \u00ab\u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0443\u00bb \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 <code>private\u00a0var subscriptions<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/xc\/09\/dr\/xc09dr72cxvuyhr2tyv0udhftw8.png\"><\/p>\n<p>  \u0418 \u044d\u0442\u043e \u0432\u0441\u0451. \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u043e\u0432\u0430\u044f\u00a0<code>View Model<\/code> &#8212;\u00a0<code>\u00a0StoriesViewModelID<\/code>,\u00a0\u0438 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0435\u0451 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043d\u0430\u0448\u0435\u0433\u043e<code> UI<\/code>, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0432\u00a0<code>StoriesView<\/code> \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0435 \u0431\u0443\u043a\u0432\u044b:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/he\/_l\/my\/he_lmyxqegmsrn_lw5cwy4-flei.png\"><\/p>\n<p>  \u041d\u0430 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0432\u0438\u0434\u043d\u043e, \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>Combine<\/code> \u0432\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0435 <code>HTTP<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u044b.\u00a0 \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u044d\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u043e \u0434\u0432\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>flatMap<\/code>.<\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u00a0\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u043c\u044b \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0442\u043e\u0439 \u0436\u0435 \u0441\u0430\u043c\u043e\u0439 \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u00a0\u0432\u00a0\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/modern-networking-in-swift-5-with-urlsession-combine-and-codable\/\" rel=\"nofollow\">\u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432<\/a>\u00a0<a href=\"https:\/\/developers.themoviedb.org\/3\/getting-started\/introduction\" rel=\"nofollow\">TMDb<\/a>\u00a0\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/488442\/\">\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u043e\u043c \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0\u00a0NewsAPI.org<\/a>. \u0425\u043e\u0442\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0441\u0442\u0430\u0442\u0435\u0439 \u0438\u043b\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u043a\u0430\u043a \u0438\u0445 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u0435\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0434\u0440\u0443\u0433\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0443\u044e \u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043d\u0430 Combine, \u043f\u043e\u043a\u0430\u0437\u0430\u043b\u0430 \u0441\u0432\u043e\u044e \u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u0443\u044e \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c.<\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 \u0432\u00a0\u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445\u00a0\u043c\u044b \u043e\u043f\u0438\u0440\u0430\u043b\u0438\u0441\u044c \u043d\u0430 \u043a\u043e\u0434 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e <code>Generic<\/code> \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>AnyPublisher&lt;T, Never&gt;<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442 <code>JSON <\/code>\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0430\u0435\u0442 \u0435\u0451 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 <code>Codable<\/code> \u041c\u043e\u0434\u0435\u043b\u0438<code> T<\/code>\u00a0\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0438\u00a0\u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0433\u043e\u00a0<code>url<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/y0\/zb\/di\/y0zbdidyjqkny4xxzoyaximi4si.png\"><\/p>\n<p>  \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb<code>\u00a0AnyPublisher&lt;Story, Never&gt;<\/code>, \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u043e\u0434\u043d\u0443 \u0438\u0441\u0442\u043e\u0440\u0438\u044e, \u0438 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb\u00a0<code>AnyPublisher&lt;[Stories], Never&gt;<\/code>, \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u0438 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>AnyPublisher&lt;[Int], Never&gt;<\/code>, \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u044b \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0438\u0441\u0442\u043e\u0440\u0438\u0439, \u0441 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/jk\/on\/03\/jkon03ci9miutbgajlnjue64rey.png\"><\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0438\u00bb \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 <code>ObservableObject <\/code>\u043a\u043b\u0430\u0441\u0441\u0430\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0432\u043e\u0438\u0445 <code>@Published <\/code>\u0441\u0432\u043e\u0439\u0441\u0442\u0432 \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u0421\u0418\u041d\u0425\u0420\u041e\u041d\u0418\u0417\u0418\u0420\u0423\u0415\u0422 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0438\u0437 \u0438\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u00a0<code>View<\/code>:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/y4\/sg\/p4\/y4sgp4fimzjdibm0svzl-o-v3ji.png\"><\/p>\n<p>  \u042d\u0442\u0430 \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0430\u044f <code>View Model<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0410\u0412\u0422\u041e\u041c\u0410\u0422\u0418\u0427\u0415\u0421\u041a\u0418 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u0439 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0441\u00a0\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>. \u00ab\u0418\u043d\u0438\u0446\u0438\u0430\u0442\u043e\u0440\u0430\u043c\u0438\u00bb \u044d\u0442\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u00bb <code>Timer<\/code>\u00a0\u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435\u00a0Hacker News, \u0442\u0430\u043a \u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0440\u0430\u0437\u043d\u044b\u0445 \u0442\u0438\u043f\u0430\u0445 \u0438\u0441\u0442\u043e\u0440\u0438\u0439: \u0441\u0430\u043c\u044b\u0445 \u0441\u0432\u0435\u0436\u0438\u0445, \u0442\u043e\u043f\u043e\u0432\u044b\u0445 \u0438\u043b\u0438 \u0441\u0430\u043c\u044b\u0445 \u043b\u0443\u0447\u0448\u0438\u0445.<\/p>\n<p>  \u041a\u043e\u0434 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/HackerNewsApp\" rel=\"nofollow\">Github<\/a>.<\/p>\n<p>  \u0421\u0441\u044b\u043b\u043a\u0438:<\/p>\n<p>  <a href=\"https:\/\/store.raywenderlich.com\/products\/combine-asynchronous-programming-with-swift\" rel=\"nofollow\">Combine: Asynchronous Programming with Swift<\/a><br \/>  <a href=\"https:\/\/bestkora.com\/IosDeveloper\/swiftui-combine-vmeste-luchshe-pochemu-swiftui-i-combine-pomogut-vam-sozdavat-bolee-luchshie-prilozheniya\/\" rel=\"nofollow\">\u00abSwiftUI &amp; Combine: \u041b\u0443\u0447\u0448\u0435 \u0432\u043c\u0435\u0441\u0442\u0435\u00bb<\/a><br \/>  <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2019\/722\/\" rel=\"nofollow\">Introducing Combine \u2014 WWDC 2019 \u2014 Videos \u2014 Apple Developer. session 722<\/a><br \/>  <a href=\"https:\/\/developer.apple.com\/videos\/play\/wwdc2019\/721\" rel=\"nofollow\">Combine in Practice \u2014 WWDC 2019 \u2014 Videos \u2014 Apple Developer. session 721<\/a><\/div>\n<p> \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\/post\/490486\/\"> https:\/\/habr.com\/ru\/post\/490486\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/490486\/\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/yp\/go\/he\/ypgohe5omouinjf-e93ilcegdvs.png\"><\/p>\n<p>  <a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u0447\u0435\u0439 <code>API<\/code> \u043c\u044b \u0441\u043e\u0431\u0438\u0440\u0430\u0435\u043c\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435, \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u043e\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u0430\u0439\u0442\u043e\u043c, \u0441\u0444\u043e\u043a\u0443\u0441\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043d\u0430 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0430\u0445 \u0438 \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u0435. \u0415\u0441\u043b\u0438 \u0432\u044b \u0441 \u043d\u0438\u043c \u0435\u0449\u0451 \u043d\u0435 \u0437\u043d\u0430\u043a\u043e\u043c\u044b, \u0432\u044b \u043d\u0430\u0439\u0434\u0451\u0442\u0435 \u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0433\u043e.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/en\/tc\/m1\/entcm1vprul86isvrkmtx3slaeq.png\"><\/p>\n<p>  \u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445\u00a0\u00a0\u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/modern-networking-in-swift-5-with-urlsession-combine-and-codable\/\" rel=\"nofollow\">\u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0438\u043b\u044c\u043c\u043e\u0432<\/a>\u00a0<a href=\"https:\/\/developers.themoviedb.org\/3\/getting-started\/introduction\" rel=\"nofollow\">TMDb<\/a>\u00a0\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/488442\/\">\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0NewsAPI.org<\/a>\u00a0\u0431\u044b\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u00a0<code>Combine <\/code>\u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <code>HTTP<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432\u00a0\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0445 \u0432\u043e\u00a0<code>View Model<\/code>\u00a0\u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f<code> UI<\/code>, \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>SwiftUI<\/code>.\u00a0\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043c \u0442\u0443 \u0436\u0435 \u0441\u0430\u043c\u0443\u044e \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u0434\u043b\u044f \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0433\u043e \u0441 \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u043e\u043c \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>, \u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0440\u0430\u0431\u043e\u0442\u0443 \u0441 \u00ab\u0432\u043d\u0435\u0448\u043d\u0438\u043c\u00bb \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u0435\u043c\u00a0<code>Timer<\/code> \u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0442\u044b \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043e\u0448\u0438\u0431\u043e\u043a.<\/p>\n<p>  \u041d\u0430\u0434\u043e \u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0440\u0435\u0441\u0443\u0440\u0441\u0435\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u0438\u043c\u0435\u0435\u0442 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0434\u0440\u0443\u0433\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443, \u0447\u0435\u043c \u0432 \u043d\u043e\u0432\u043e\u0441\u0442\u043d\u043e\u043c \u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0435\u00a0<a href=\"https:\/\/newsapi.org\/\" rel=\"nofollow\">NewsAPI.org<\/a>, \u043d\u043e \u0442\u0435\u0445\u043d\u043e\u043b\u043e\u0433\u0438\u044f, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u043d\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 <code>HTTP<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e\u00a0<code>Combine<\/code>, \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u043e \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u0432\u043e\u044e \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u044c \u0438 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438.\u00a0\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 <a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a> \u043e\u0447\u0435\u043d\u044c \u0447\u0430\u0441\u0442\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u00ab\u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044f\u00bb <code>Timer<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0441\u0442\u0443\u043f\u0430\u044e\u0449\u0438\u0435 \u043d\u0430 \u0441\u0430\u0439\u0442 \u043d\u043e\u0432\u044b\u0435 \u0438\u0441\u0442\u043e\u0440\u0438\u0438 (<code>Story<\/code>), \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0430\u043a \u0438\u0445 \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u043d\u0430 \u044d\u0442\u043e\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0435.<\/p>\n<p>  <code>API<\/code>\u00a0\u0430\u0433\u0440\u0435\u0433\u0430\u0442\u043e\u0440\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u0435\u0439\u00a0<a href=\"https:\/\/news.ycombinator.com\/newest\" rel=\"nofollow\">Hacker News<\/a>\u00a0\u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0438 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0438\u043a\u0430\u043a\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0434\u043b\u044f \u0430\u043a\u043a\u0430\u0443\u043d\u0442\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430. \u042d\u0442\u043e \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0434 \u043a\u043e\u0434\u043e\u043c \u0431\u0435\u0437 \u0434\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u043a\u0430\u043a \u043c\u044b \u0434\u0435\u043b\u0430\u043b\u0438 \u044d\u0442\u043e \u0441 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 <code>public APIs<\/code>.   <\/p>\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-299583","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/299583","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=299583"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/299583\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=299583"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=299583"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=299583"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}