{"id":16279,"date":"2024-12-01T18:24:23","date_gmt":"2024-12-01T18:24:23","guid":{"rendered":"https:\/\/bestkora.com\/IosDeveloper\/?p=16279"},"modified":"2024-12-03T08:38:46","modified_gmt":"2024-12-03T08:38:46","slug":"cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87","status":"publish","type":"post","link":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/","title":{"rendered":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 2."},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"646\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-1024x646.png\" alt=\"\" class=\"wp-image-16308\" srcset=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-1024x646.png 1024w, https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-300x189.png 300w, https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-768x484.png 768w, https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-1536x969.png 1536w, https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-2048x1291.png 2048w, https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25-476x300.png 476w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 <strong>Cursor AI <\/strong>\u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f <strong>iOS<\/strong> \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430  <a href=\"https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1\">\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.<\/a><br>UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">Grid<\/mark><\/code> \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdkAEb8xrRu4skLITkXUJJSkXlzKPVlxFIkJhVB_qyh-M3bhm05sfIxssQ-64ptGDmeG_o5CMlkyTU-mUI5Z8iv1oIKmTCxQPO_YdiHP1hCbTm7RbpnjkYx04sKl22W6zKpm-iGyA?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,  \u0442\u043e \u0435\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0442\u0430\u043a\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u043f\u043e\u0441\u0442\u0435 <a href=\"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-\u0432-ios-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435-\u0444\u043e\u0442\u043e-\u0441-flickr-com\/\" title=\"\">&#171;Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 1.&#187; <\/a><br>\u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <strong>PhotomaniaCursor<\/strong> \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/PhotomaniaCursor\" title=\"\">Github.com<\/a>. <br>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 <strong>PhotomaniaCursor<\/strong>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c <a href=\"https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1\" title=\"\">\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441 <strong>Flickr.com<\/strong><\/a>. \u0418 \u0432\u043e\u0442 \u043d\u0430\u0448 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441:<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u041a\u0430\u043a \u0447\u0430\u0441\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a&nbsp; Flickr API \u043f\u0440\u0438 \u043d\u0430\u0431\u043e\u0440\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u043e\u0438\u0441\u043a\u0430?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041d\u0430\u0448\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f 8 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <strong>PhotomaniaCursor<\/strong> \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u043a\u0430\u043a \u0438 \u0432\u0435\u0440\u0441\u0438\u044f 7, \u043d\u043e \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0447\u0435\u0442\u043a\u043e \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u043f\u0440\u0438 \u043a\u0430\u043a\u0438\u0445 \u0442\u0435\u0433\u0430\u0445 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">tags<\/mark><\/code> \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a&nbsp; <strong>Flickr API <\/strong>\u043f\u0440\u0438 \u043d\u0430\u0431\u043e\u0440\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code>. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u0432 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">FlickrViewModel<\/mark><\/code> \u0442\u0435\u0433\u0438 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">tags<\/mark><\/code>, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f, :<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(1 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"if let encodedTags = tags.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0print (&quot;--------------------------- \\(encodedTags)&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #56B6C2\">print<\/span><span style=\"color: #ABB2BF\"> (<\/span><span style=\"color: #98C379\">&quot;--------------------------- <\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #98C379\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0412\u0435\u0440\u0441\u0438\u044f 8<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeASdCOtOrRA8P63zfdN7hcto3xxKRJ-QQq4nbvkyc-K9r-41GRzcwSVN69Y6EXZp3cr8oljKBMh9kFxg-0RoDu81oEe0vwma7c2GKWMUa0LgUonsckCEj8Yb1uxfpPq-fVWm2V?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0427\u0442\u043e \u043d\u0430\u0441 \u0440\u0435\u0430\u043b\u044c\u043d\u043e \u0442\u0440\u0435\u0432\u043e\u0436\u0438\u0442, \u0442\u0430\u043a \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u043f\u0440\u0438 \u0432\u0432\u043e\u0434\u0435 \u201cRose\u201d, \u201cSunrise\u201d, \u201cOcean\u201d \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u0438\u043c\u0432\u043e\u043b\u0430 (\u0431\u0443\u043a\u0432\u044b) \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0438\u0437 <strong>Flickr.com,<\/strong> \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0435\u043f\u0440\u0438\u044f\u0442\u043d\u043e\u043c\u0443 \u043c\u0435\u043b\u044c\u043a\u0430\u043d\u0438\u044e \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u0438\u043b\u044c\u043d\u043e \u043d\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044c \u0442\u0440\u0430\u0444\u0438\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430 <strong>iPhone<\/strong>. <br>\u0427\u0442\u043e\u0431\u044b \u0441\u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442\u044c \u0434\u0435\u043d\u044c\u0433\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043c\u044b \u0434\u043e\u043b\u0436\u043d\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a. \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 &nbsp;<strong>Flickr.com <\/strong>\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043b\u0430\u0441\u044c \u043b\u0438\u0448\u044c \u0442\u043e\u0433\u0434\u0430, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442 \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435. <br>\u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">debounce<\/mark><\/code> \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 <strong>Combine<\/strong>.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 debounce \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a\u0430 Combine<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">debounce<\/mark><\/code> \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0435\u0430\u0433\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430 \u0432\u0432\u043e\u0434 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u043a\u0430\u0436\u0434\u043e\u0435 \u043f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435. \u041a \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u043c \u0441\u043b\u0443\u0447\u0430\u044f\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 <code>debounce<\/code> \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430, \u043a\u043e\u0433\u0434\u0430 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0434\u043e\u0436\u0434\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u043a\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442 \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u043f\u043e\u0438\u0441\u043a.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043c <strong>Composer Cursor AI<\/strong> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0434\u043b\u044f \u043d\u0430\u0441:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXc0oRuLks6Gk07n5jzlsUtuDOeq2izgA1NubXDHakHW-5zrkJ_R4jq-2pDTSuQDxGzJW3Tdt6CGqhle7dATMg74L6r6YrP4lf1CFczNWb94BEPQug1gqcWkCEsaOLuAWr4zd79OZg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><span style=\"font-weight: 400;\"><strong><em> <\/em><\/strong><\/span><img loading=\"lazy\" decoding=\"async\" width=\"41\" height=\"39\" class=\"wp-image-16237\" style=\"width: 41px;\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Screenshot-2024-11-30-at-16.54.50-1.png\" alt=\"\"><span style=\"font-weight: 400;\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u0434\u043b\u044f  \u00a0<code>FlickrViewModel Combine <\/code>\u0438 <code>.debounce(for:.millisecond(500))<\/code><\/span><\/p>\n\n\n\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042f \u043e\u0431\u043d\u043e\u0432\u043b\u044e <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">FlickrViewModel<\/mark><\/code> \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <strong>Combine<\/strong> \u0441 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">debounce<\/mark><\/code> \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code>:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import Foundation\nimport SwiftUI\nimport Combine\n\n@MainActor\nclass FlickrViewModel: ObservableObject {\n\u00a0 @Published var photos: [FlickrPhoto] = []\n\u00a0 @Published var searchText = &quot;&quot;\n\u00a0 @Published var isLoading = false\n\u00a0 @Published var errorMessage: String?\n\u00a0\n\u00a0 private let baseURL = &quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;\n\u00a0 private var cancellables = Set&lt;AnyCancellable&gt;()\n\u00a0\n\u00a0 init() {\n\u00a0 \u00a0 \u00a0 setupSearchSubscription()\n\u00a0 }\n\u00a0\n\u00a0 private func setupSearchSubscription() {\n\u00a0 \u00a0 \u00a0 $searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .removeDuplicates()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .sink { [weak self] _ in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await self?.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .store(in: &amp;cancellables)\n\u00a0 }\n\u00a0\n\u00a0 func fetchPhotos() async {\n\u00a0 \u00a0 \u00a0 isLoading = true\n\u00a0 \u00a0 \u00a0 errorMessage = nil\n\u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 do {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 var urlString = baseURL\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if !searchText.isEmpty {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let tags = searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .components(separatedBy: &quot; &quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .filter { !$0.isEmpty }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .joined(separator: &quot;,&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let encodedTags = tags.addingPercentEncoding(\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0}\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 guard let url = URL(string: urlString) else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 throw URLError(.badURL)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0let (data, _) = try await URLSession.shared.data(from: url)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0let result = try \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0    JSONDecoder().decode(FlickrFeedResult.self, from: data)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.items\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 } catch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.localizedDescription\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 }\n\u00a0 }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Foundation<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">SwiftUI<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Combine<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">class<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">ObservableObject <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> photos: [FlickrPhoto] = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> searchText = <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> errorMessage: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> baseURL = <\/span><span style=\"color: #98C379\">&quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> cancellables = <\/span><span style=\"color: #E5C07B\">Set<\/span><span style=\"color: #ABB2BF\">&lt;AnyCancellable&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">init<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 $searchText<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">debounce<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">for<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #61AFEF\">milliseconds<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">500<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">scheduler<\/span><span style=\"color: #ABB2BF\">: DispatchQueue.<\/span><span style=\"color: #E06C75\">main<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">removeDuplicates<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">sink<\/span><span style=\"color: #ABB2BF\"> { [<\/span><span style=\"color: #C678DD\">weak<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">] _ <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">?.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">store<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">in<\/span><span style=\"color: #ABB2BF\">: &amp;cancellables)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 errorMessage = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">do<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> urlString = baseURL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> !searchText.isEmpty {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags = searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">components<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separatedBy<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot; &quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">filter<\/span><span style=\"color: #ABB2BF\"> { !<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">.isEmpty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">joined<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separator<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;,&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0}<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">guard<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> url = <\/span><span style=\"color: #61AFEF\">URL<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: urlString) <\/span><span style=\"color: #C678DD\">else<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">throw<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">URLError<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">badURL<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> (data, _) = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> URLSession.<\/span><span style=\"color: #E06C75\">shared<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">data<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> result = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0    <\/span><span style=\"color: #61AFEF\">JSONDecoder<\/span><span style=\"color: #ABB2BF\">().<\/span><span style=\"color: #56B6C2\">decode<\/span><span style=\"color: #ABB2BF\">(FlickrFeedResult.<\/span><span style=\"color: #C678DD\">self<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: data)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.<\/span><span style=\"color: #E06C75\">items<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #C678DD\">catch<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.<\/span><span style=\"color: #E06C75\">localizedDescription<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0418 \u043e\u0431\u043d\u043e\u0432\u043b\u044e <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">ContentView<\/mark><\/code>, \u0447\u0442\u043e\u0431\u044b \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0440\u0443\u0447\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">.onChange<\/mark><\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e \u0432 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">ViewModel<\/mark><\/code>:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"struct ContentView: View {\n\u00a0 @StateObject private var viewModel = FlickrViewModel()\n\u00a0\n\u00a0 let columns = [\n\u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1),\n\u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1),\n\u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1)\n\u00a0 ]\n\u00a0\n\u00a0 var body: some View {\n\u00a0 \u00a0 \u00a0 NavigationStack {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ZStack {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Color.black.opacity(0.1)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ScrollView {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 LazyVGrid(columns: columns, spacing: 1) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ForEach(viewModel.photos) { photo in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 NavigationLink(destination: \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0        PhotoDetailView(photo: photo)) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PhotoGridItem(photo: photo)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if viewModel.isLoading {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ProgressView()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .scaleEffect(1.5)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .frame(maxWidth: .infinity, maxHeight: .infinity)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .background(Color.black.opacity(0.1))\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .navigationTitle(&quot;Flickr Photos&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .searchable(text: $viewModel.searchText, \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0             prompt: &quot;Search photos&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .alert(&quot;Error&quot;, isPresented: \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0                .constant(viewModel.errorMessage != nil)) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Button(&quot;OK&quot;) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 viewModel.errorMessage = nil\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } message: {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Text(viewModel.errorMessage ?? &quot;&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 .task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await viewModel.fetchPhotos()\n\u00a0 \u00a0 \u00a0 }\n\u00a0 }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">ContentView<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">View <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">@StateObject<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> viewModel = <\/span><span style=\"color: #61AFEF\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> columns = [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> body: <\/span><span style=\"color: #C678DD\">some<\/span><span style=\"color: #ABB2BF\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">NavigationStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ZStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ScrollView<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">LazyVGrid<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">columns<\/span><span style=\"color: #ABB2BF\">: columns, <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ForEach<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">photos<\/span><span style=\"color: #ABB2BF\">) { photo <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">NavigationLink<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">destination<\/span><span style=\"color: #ABB2BF\">: <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0        <\/span><span style=\"color: #61AFEF\">PhotoDetailView<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">PhotoGridItem<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> viewModel.isLoading {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ProgressView<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">scaleEffect<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">1.5<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">frame<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">maxWidth<\/span><span style=\"color: #ABB2BF\">: .infinity, <\/span><span style=\"color: #61AFEF\">maxHeight<\/span><span style=\"color: #ABB2BF\">: .infinity)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">background<\/span><span style=\"color: #ABB2BF\">(Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">navigationTitle<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Flickr Photos&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">searchable<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">text<\/span><span style=\"color: #ABB2BF\">: $viewModel.<\/span><span style=\"color: #E06C75\">searchText<\/span><span style=\"color: #ABB2BF\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0             <\/span><span style=\"color: #61AFEF\">prompt<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;Search photos&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">alert<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Error&quot;<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">isPresented<\/span><span style=\"color: #ABB2BF\">: <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0                .<\/span><span style=\"color: #61AFEF\">constant<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> != <\/span><span style=\"color: #D19A66\">nil<\/span><span style=\"color: #ABB2BF\">)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Button<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;OK&quot;<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #61AFEF\">message<\/span><span style=\"color: #ABB2BF\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Text<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> ?? <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> viewModel.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d <code>import Combine<\/code> \u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432 <code>FlickrViewModel<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f <code>var cancellables = Set&lt;AnyCancellable&gt;()<\/code><br>\u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043e\u043a<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0421\u043e\u0437\u0434\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <code>setupSearchSubscription()<\/code> \u0441 <code>debounce<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0423\u0434\u0430\u043b\u0435\u043d \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a <code>.onChange <\/code>\u0438\u0437 <code>ContentView<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0435 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u044c\u044e \u0441&nbsp;<code> [weak self]<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d <code>removeDuplicates() <\/code>\u0434\u043b\u044f \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u0432\u044b\u0437\u043e\u0432\u043e\u0432 API<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0438\u0441\u043a \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0447\u0435\u0440\u0435\u0437 500 \u043c\u0441 \u043f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e, \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442 \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c.\u042d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u0431\u043e\u043b\u0435\u0435 \u043f\u043b\u0430\u0432\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a \u0437\u0430 \u0441\u0447\u0435\u0442 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0432\u044b\u0437\u043e\u0432\u043e\u0432 API \u0438 \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 <strong>Flickr.com <\/strong>\u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u0431\u043e\u0440\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 <span style=\"font-weight: 400;\"> searchText <\/span>.<\/span><\/p>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u0441 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442, \u043e\u043f\u044f\u0442\u044c \u043a\u043b\u0438\u043a\u0430\u0435\u043c <strong>Accept All<\/strong>.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXduhoVdXbus2ynGEyU1_u7EmUyexVZhN7X2LF54MCT6O4WwYMyGYFkoc2SNpnwLNACbfi_1VXJByI8GKT7B4xqfSkAIrbqR88VngpM-uwx0Xs-FDwdSCnBSc33SrKC-8Coky_AzOg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:426px;height:auto\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0412\u0435\u0440\u0441\u0438\u044f 9<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Cursor9a-1.gif\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"526\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Cursor9a-1.gif\" alt=\"\" class=\"wp-image-16256\"\/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0442 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u043d\u0435\u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 <strong>Flickr.com<\/strong>, \u043d\u043e \u043c\u0430\u043b\u0435\u0439\u0448\u0430\u044f&nbsp; \u043d\u0435\u0443\u0432\u0435\u0440\u0435\u043d\u043d\u043e\u0441\u0442\u044c \u0432 \u043d\u0430\u0431\u043e\u0440\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c, \u0445\u043e\u0442\u044f \u0438 \u0432 \u043c\u0435\u043d\u044c\u0448\u0435\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438, \u0447\u0435\u043c \u043f\u0440\u0435\u0436\u0434\u0435.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u041a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Flickr Photos<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u043c \u0441\u043e\u043a\u0440\u0430\u0449\u0430\u0442\u044c \u0447\u0438\u0441\u043b\u043e \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 <strong>Flickr.com<\/strong> \u0438 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0443\u0435\u043c \u043a\u044d\u0448 \u0434\u043b\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0443 \u0438 \u043e\u043f\u044f\u0442\u044c \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043c <strong>Composer Cursor AI <\/strong>\u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0434\u043b\u044f \u043d\u0430\u0441:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcxWhbFfOtg3-PGl5WkJpLvzAXpea7pLVu4BvM3XmC9rb7Z3_bMNdyTFdSd_gKMTnx0uNnn01sfurf1pg4Aex1PtW8vQ6nm34RljQ-vgNcy66Xf_V1-cW0tLi539Xo1q_q5f9hIdg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><span style=\"font-weight: 400;\"><strong><em> <\/em><\/strong><\/span><img loading=\"lazy\" decoding=\"async\" width=\"41\" height=\"39\" class=\"wp-image-16237\" style=\"width: 41px;\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Screenshot-2024-11-30-at-16.54.50-1.png\" alt=\"\"><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u044d\u0448  \u0434\u043b\u044f  \u00a0<code>FlickrPhotos <\/code><\/span><\/p>\n\n\n\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0427\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 <strong>Flickr<\/strong>, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">FlickrViewModel<\/mark><\/code>, \u0432\u043a\u043b\u044e\u0447\u0438\u0432 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. <br>\u041c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">NSCache<\/mark><\/code> \u0434\u043b\u044f \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0430\u043c\u044f\u0442\u0438. \u0412\u043e\u0442 \u043a\u0430\u043a \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">ContentView<\/mark><\/code> \u0438 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">FlickrViewModel<\/mark><\/code>:<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u043c FlickrViewModel:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import Foundation\nimport SwiftUI\nimport Combine\n@MainActor\nclass FlickrViewModel: ObservableObject {\n\u00a0 \u00a0 @Published var photos: [FlickrPhoto] = []\n\u00a0 \u00a0 @Published var searchText = &quot;&quot;\n\u00a0 \u00a0 @Published var isLoading = false\n\u00a0 \u00a0 @Published var errorMessage: String?\n\u00a0 \u00a0\n\u00a0 \u00a0 private let baseURL = &quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;\n\u00a0 \u00a0 private var cancellables = Set&lt;AnyCancellable&gt;()\n\u00a0 \u00a0 private let cache = NSCache&lt;NSString, NSArray&gt;()\n\u00a0 \u00a0\n\u00a0 \u00a0 init() {\n\u00a0 \u00a0 \u00a0 \u00a0 setupSearchSubscription()\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 private func setupSearchSubscription() {\n\u00a0 \u00a0 \u00a0 \u00a0 $searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .debounce(for: .milliseconds(500), \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0           scheduler: DispatchQueue.main)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .removeDuplicates()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .sink { [weak self] _ in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await self?.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .store(in: &amp;cancellables)\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func fetchPhotos() async {\n\u00a0 \u00a0 \u00a0 \u00a0 isLoading = true\n\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = nil\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 do {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let cacheKey = NSString(string: searchText)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let cachedPhotos = cache.object(forKey: cacheKey) \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0    as? [FlickrPhoto] {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 var urlString = baseURL\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if !searchText.isEmpty {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let tags = searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .components(separatedBy: &quot; &quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .filter { !$0.isEmpty }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .joined(separator: &quot;,&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let encodedTags = tags.addingPercentEncoding(\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 guard let url = URL(string: urlString) else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 throw URLError(.badURL)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0let (data, _) = try await URLSession.shared.data(from: url)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0let result = try   \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0   JSONDecoder().decode(FlickrFeedResult.self, from: data)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.items\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.setObject(result.items as NSArray, forKey: cacheKey)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 } catch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.localizedDescription\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n}\u00a0\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Foundation<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">SwiftUI<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Combine<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">class<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">ObservableObject <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> photos: [FlickrPhoto] = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> searchText = <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> errorMessage: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> baseURL = <\/span><span style=\"color: #98C379\">&quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> cancellables = <\/span><span style=\"color: #E5C07B\">Set<\/span><span style=\"color: #ABB2BF\">&lt;AnyCancellable&gt;()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cache = NSCache&lt;NSString, NSArray&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">init<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 $searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">debounce<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">for<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #61AFEF\">milliseconds<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">500<\/span><span style=\"color: #ABB2BF\">), <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0           <\/span><span style=\"color: #61AFEF\">scheduler<\/span><span style=\"color: #ABB2BF\">: DispatchQueue.<\/span><span style=\"color: #E06C75\">main<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">removeDuplicates<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">sink<\/span><span style=\"color: #ABB2BF\"> { [<\/span><span style=\"color: #C678DD\">weak<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">] _ <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">?.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">store<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">in<\/span><span style=\"color: #ABB2BF\">: &amp;cancellables)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">do<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cacheKey = <\/span><span style=\"color: #61AFEF\">NSString<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: searchText)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cachedPhotos = cache.<\/span><span style=\"color: #61AFEF\">object<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey) <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0    as? [FlickrPhoto] {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> urlString = baseURL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> !searchText.isEmpty {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags = searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">components<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separatedBy<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot; &quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">filter<\/span><span style=\"color: #ABB2BF\"> { !<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">.isEmpty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">joined<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separator<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;,&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">guard<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> url = <\/span><span style=\"color: #61AFEF\">URL<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: urlString) <\/span><span style=\"color: #C678DD\">else<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">throw<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">URLError<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">badURL<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> (data, _) = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> URLSession.<\/span><span style=\"color: #E06C75\">shared<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">data<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> result = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\">   <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0   <\/span><span style=\"color: #61AFEF\">JSONDecoder<\/span><span style=\"color: #ABB2BF\">().<\/span><span style=\"color: #56B6C2\">decode<\/span><span style=\"color: #ABB2BF\">(FlickrFeedResult.<\/span><span style=\"color: #C678DD\">self<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: data)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.<\/span><span style=\"color: #E06C75\">items<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">setObject<\/span><span style=\"color: #ABB2BF\">(result.<\/span><span style=\"color: #E06C75\">items<\/span><span style=\"color: #ABB2BF\"> as NSArray, <\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #C678DD\">catch<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.<\/span><span style=\"color: #E06C75\">localizedDescription<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}\u00a0<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u043c <code>ContentView<\/code>, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import SwiftUI\nstruct ContentView: View {\n\u00a0 \u00a0 @StateObject private var viewModel = FlickrViewModel()\n\u00a0 \u00a0\n\u00a0 \u00a0 let columns = [\n\u00a0 \u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1),\n\u00a0 \u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1),\n\u00a0 \u00a0 \u00a0 \u00a0 GridItem(.adaptive(minimum: 108), spacing: 1)\n\u00a0 \u00a0 ]\n\u00a0 \u00a0\n\u00a0 \u00a0 var body: some View {\n\u00a0 \u00a0 \u00a0 \u00a0 NavigationStack {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ZStack {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Color.black.opacity(0.1)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ScrollView {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 LazyVGrid(columns: columns, spacing: 1) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ForEach(viewModel.photos) { photo in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 NavigationLink(destination:  \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0     PhotoDetailView(photo: photo)) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 PhotoGridItem(photo: photo)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if viewModel.isLoading {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ProgressView()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .scaleEffect(1.5)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .frame(maxWidth: .infinity, \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0        maxHeight: .infinity)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .background(Color.black.opacity(0.1))\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .navigationTitle(&quot;Flickr Photos&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .searchable(text: $viewModel.searchText, \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0             prompt: &quot;Search photos&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .alert(&quot;Error&quot;, isPresented: \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0             .constant(viewModel.errorMessage != nil)) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Button(&quot;OK&quot;) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 viewModel.errorMessage = nil\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } message: {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Text(viewModel.errorMessage ?? &quot;&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .toolbar {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ToolbarItem(placement: .navigationBarTrailing) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Button(action: {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await viewModel.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Image(systemName: &quot;arrow.clockwise&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 .task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await viewModel.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">SwiftUI<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">ContentView<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">View <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@StateObject<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> viewModel = <\/span><span style=\"color: #61AFEF\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> columns = [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> body: <\/span><span style=\"color: #C678DD\">some<\/span><span style=\"color: #ABB2BF\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">NavigationStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ZStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ScrollView<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">LazyVGrid<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">columns<\/span><span style=\"color: #ABB2BF\">: columns, <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ForEach<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">photos<\/span><span style=\"color: #ABB2BF\">) { photo <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">NavigationLink<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">destination<\/span><span style=\"color: #ABB2BF\">:  <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0     <\/span><span style=\"color: #61AFEF\">PhotoDetailView<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">PhotoGridItem<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> viewModel.isLoading {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ProgressView<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">scaleEffect<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">1.5<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">frame<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">maxWidth<\/span><span style=\"color: #ABB2BF\">: .infinity, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0        <\/span><span style=\"color: #61AFEF\">maxHeight<\/span><span style=\"color: #ABB2BF\">: .infinity)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">background<\/span><span style=\"color: #ABB2BF\">(Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">navigationTitle<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Flickr Photos&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">searchable<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">text<\/span><span style=\"color: #ABB2BF\">: $viewModel.<\/span><span style=\"color: #E06C75\">searchText<\/span><span style=\"color: #ABB2BF\">, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0             <\/span><span style=\"color: #61AFEF\">prompt<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;Search photos&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">alert<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Error&quot;<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">isPresented<\/span><span style=\"color: #ABB2BF\">: <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0             .<\/span><span style=\"color: #61AFEF\">constant<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> != <\/span><span style=\"color: #D19A66\">nil<\/span><span style=\"color: #ABB2BF\">)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Button<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;OK&quot;<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #61AFEF\">message<\/span><span style=\"color: #ABB2BF\">: {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Text<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> ?? <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">toolbar<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">ToolbarItem<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">placement<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">navigationBarTrailing<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Button<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">action<\/span><span style=\"color: #ABB2BF\">: {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> viewModel.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Image<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">systemName<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;arrow.clockwise&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> viewModel.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042d\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0435:<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0412 <\/strong><strong>FlickrViewModel<\/strong><strong>:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\">\u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 <code>NSCache<\/code> \u0434\u043b\u044f \u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439.<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u041f\u0435\u0440\u0435\u0434 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u044b \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u0442\u044c \u043b\u0438 \u0443\u0436\u0435 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0434\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 \u043a\u044d\u0448\u0435 <code>NSCache<\/code>.<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0415\u0441\u043b\u0438 \u043e\u043d\u0438 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u043a\u044d\u0448\u0435, \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0432\u043c\u0435\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430.<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u041f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0438\u0445 \u0432 \u043a\u044d\u0448\u0435.<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u0412 ContentView:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\">\u041c\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043a\u043d\u043e\u043f\u043a\u0443 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u0443\u044e \u043f\u0430\u043d\u0435\u043b\u044c, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 <code>viewModel.fetchPhotos() <\/code>\u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438.<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042d\u0442\u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438, \u0447\u0442\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442&nbsp; \u043e\u0434\u043d\u0438 \u0438 \u0442\u0435 \u0436\u0435 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 <code>searchText<\/code> \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u0438\u043b\u0438 \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0442\u0441\u044f \u043a \u0433\u043b\u0430\u0432\u043d\u043e\u043c\u0443 <code>View<\/code> \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438. \u041a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u043c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438, \u043c\u0438\u043d\u0443\u044f \u043a\u044d\u0448.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041f\u043e\u043c\u043d\u0438\u0442\u0435, \u0447\u0442\u043e \u044d\u0442\u043e\u0442 \u043a\u044d\u0448 \u0432 \u043f\u0430\u043c\u044f\u0442\u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0447\u0438\u0449\u0435\u043d \u043f\u0440\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0438 \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e\u0433\u043e \u043a\u044d\u0448\u0430 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f <code>Core Data<\/code> \u0438\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435.<\/span><\/p>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u0441 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442, \u043e\u043f\u044f\u0442\u044c \u043a\u043b\u0438\u043a\u0430\u0435\u043c <strong>Accept All<\/strong>.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXduhoVdXbus2ynGEyU1_u7EmUyexVZhN7X2LF54MCT6O4WwYMyGYFkoc2SNpnwLNACbfi_1VXJByI8GKT7B4xqfSkAIrbqR88VngpM-uwx0Xs-FDwdSCnBSc33SrKC-8Coky_AzOg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:444px;height:auto\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0412\u0435\u0440\u0441\u0438\u044f 10<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXf0cgp6vAOIi5--2VzbW0e_B43AQd15UCvKivc2xuhpKB2XIGANLXDNxoXRdHa4iCBpe3rXBLMTiKy5xIlKOitSsyC2sXzft3XGPq8ch_Tkm7cOjXfVeeO8Xo5nIFG5QT49VKWxzA?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041f\u043e\u0441\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u044d\u0448 \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438, \u0440\u0430\u0432\u043d\u044b\u043c\u0438 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u043f\u0443\u0441\u0442\u043e\u0439 \u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0430\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u0441\u0435 \u201c\u0437\u0430\u043a\u043e\u043d\u0441\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c\u201d \u043d\u0430\u0433\u043b\u0443\u0445\u043e, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f &nbsp; \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u0438 \u0435\u0451 \u043d\u0435\u0442 \u0432 \u043a\u044d\u0448\u0435. \u041a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0430\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e, \u043a\u043e\u0433\u0434\u0430 \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430&nbsp; <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u043f\u0443\u0441\u0442\u0430, \u0430 \u0434\u043b\u044f \u043f\u0443\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u044d\u0448.\u041f\u043e\u0441\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0445 \u0441\u0442\u0440\u043e\u043a <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u044d\u0448 \u0441 \u043a\u043b\u044e\u0447\u0430\u043c\u0438, \u0440\u0430\u0432\u043d\u044b\u043c\u0438 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438 \u043f\u0443\u0441\u0442\u043e\u0439 \u0438 \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0430\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u0441\u0435 \u201c\u0437\u0430\u043a\u043e\u043d\u0441\u0435\u0440\u0432\u0438\u0440\u043e\u0432\u0430\u043b\u043e\u0441\u044c\u201d \u043d\u0430\u0433\u043b\u0443\u0445\u043e, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438, \u043a\u043e\u0433\u0434\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442\u0441\u044f &nbsp; \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u0438 \u0435\u0451 \u043d\u0435\u0442 \u0432 \u043a\u044d\u0448\u0435. \u041a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u0438\u0447\u0435\u0433\u043e \u043d\u0435 \u0434\u0430\u0435\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u043e\u043b\u044c\u043a\u043e, \u043a\u043e\u0433\u0434\u0430 \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430&nbsp; <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u043f\u0443\u0441\u0442\u0430, \u0430 \u0434\u043b\u044f \u043d\u0435\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u044d\u0448.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u041e\u0431\u043d\u0443\u043b\u0435\u043d\u0438\u0435 \u043a\u0435\u0448\u0430<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e&nbsp; \u0432\u044b\u0437\u043e\u0432\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">viewModel.fetchPhotos()<\/mark><\/code>, \u043d\u043e \u0438 \u043e\u0431\u043d\u0443\u043b\u044f\u0442\u044c \u043a\u044d\u0448. <br>\u041e\u043f\u044f\u0442\u044c \u043f\u043e\u043f\u0440\u043e\u0441\u0438\u043c <strong>Composer Cursor AI<\/strong> \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u0434\u043b\u044f \u043d\u0430\u0441:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcdQINlbFlRJTz3-0FE6U249Tr4tOSTJ60AE0zanoCDCMf8qZtG46A4obzpiRC_Fmd2Cc594Km5wzWXIDKuokeN9pdQVi4YqZJ3xBrI_efQXUcxdzWcOAZVQOO0dF7jSgTXu55Pkg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><span style=\"font-weight: 400;\"><img loading=\"lazy\" decoding=\"async\" width=\"41\" height=\"39\" class=\"wp-image-16237\" style=\"width: 41px;\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Screenshot-2024-11-30-at-16.54.50-1.png\" alt=\"\">\u041a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u043f\u0443\u0442\u0435\u043c \u0432\u044b\u0437\u043e\u0432\u0430<span style=\"font-weight: 400;\"> <code>viewModel.fetchPhotos()<\/code>, \u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0442\u044c \u043a\u044d\u0448<\/span><\/span>.<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042f \u043f\u043e\u043c\u043e\u0433\u0443 \u0432\u0430\u043c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c <code>FlickrViewModel<\/code>, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u043e\u0431\u043d\u0443\u043b\u0435\u043d\u0438\u044f&nbsp; \u043a\u044d\u0448\u0430.&nbsp;\u0412\u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import Foundation\nimport SwiftUI\nimport Combine\n@MainActor\nclass FlickrViewModel: ObservableObject {\n\u00a0 \u00a0 @Published var photos: [FlickrPhoto] = []\n\u00a0 \u00a0 @Published var searchText = &quot;&quot;\n\u00a0 \u00a0 @Published var isLoading = false\n\u00a0 \u00a0 @Published var errorMessage: String?\n\u00a0 \u00a0\n\u00a0 \u00a0 private let baseURL =\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;\n\u00a0 \u00a0 private var cancellables = Set&lt;AnyCancellable&gt;()\n\u00a0 \u00a0 private let cache = NSCache&lt;NSString, NSArray&gt;()\n\u00a0 \u00a0\n\u00a0 \u00a0 init() {\n\u00a0 \u00a0 \u00a0 \u00a0 setupSearchSubscription()\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 private func setupSearchSubscription() {\n\u00a0 \u00a0 \u00a0 \u00a0 $searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .removeDuplicates()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .sink { [weak self] _ in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Task {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await self?.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .store(in: &amp;cancellables)\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func fetchPhotos() async {\n\u00a0 \u00a0 \u00a0 \u00a0 isLoading = true\n\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = nil\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 do {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let cacheKey = NSString(string: searchText)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let cachedPhotos = cache.object(forKey: cacheKey) as? [FlickrPhoto] {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 var urlString = baseURL\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if !searchText.isEmpty {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let tags = searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .components(separatedBy: &quot; &quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .filter { !$0.isEmpty }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .joined(separator: &quot;,&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0if let encodedTags = tags.addingPercentEncoding(\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 guard let url = URL(string: urlString) else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 throw URLError(.badURL)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let (data, _) = try await URLSession.shared.data(from: url)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let result = try \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0          JSONDecoder().decode(FlickrFeedResult.self, from: data)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.items\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.setObject(result.items as NSArray, forKey: cacheKey)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 } catch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.localizedDescription\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func clearCache() {\n\u00a0 \u00a0 \u00a0 \u00a0 cache.removeAllObjects()\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func refreshPhotos() async {\n\u00a0 \u00a0 \u00a0 \u00a0 clearCache()\n\u00a0 \u00a0 \u00a0 \u00a0 await fetchPhotos()\n\u00a0 \u00a0 }\n}\u00a0\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Foundation<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">SwiftUI<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Combine<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">class<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">ObservableObject <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> photos: [FlickrPhoto] = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> searchText = <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@Published<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> errorMessage: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> baseURL =\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #98C379\">&quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> cancellables = <\/span><span style=\"color: #E5C07B\">Set<\/span><span style=\"color: #ABB2BF\">&lt;AnyCancellable&gt;()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cache = NSCache&lt;NSString, NSArray&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">init<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 $searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">debounce<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">for<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #61AFEF\">milliseconds<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">500<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">scheduler<\/span><span style=\"color: #ABB2BF\">: DispatchQueue.<\/span><span style=\"color: #E06C75\">main<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">removeDuplicates<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">sink<\/span><span style=\"color: #ABB2BF\"> { [<\/span><span style=\"color: #C678DD\">weak<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">] _ <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">?.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">store<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">in<\/span><span style=\"color: #ABB2BF\">: &amp;cancellables)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">do<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cacheKey = <\/span><span style=\"color: #61AFEF\">NSString<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: searchText)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cachedPhotos = cache.<\/span><span style=\"color: #61AFEF\">object<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey) as? [FlickrPhoto] {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">return<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> urlString = baseURL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> !searchText.isEmpty {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags = searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">components<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separatedBy<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot; &quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">filter<\/span><span style=\"color: #ABB2BF\"> { !<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">.isEmpty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">joined<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separator<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;,&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">guard<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> url = <\/span><span style=\"color: #61AFEF\">URL<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: urlString) <\/span><span style=\"color: #C678DD\">else<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">throw<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">URLError<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">badURL<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> (data, _) = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> URLSession.<\/span><span style=\"color: #E06C75\">shared<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">data<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> result = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0          <\/span><span style=\"color: #61AFEF\">JSONDecoder<\/span><span style=\"color: #ABB2BF\">().<\/span><span style=\"color: #56B6C2\">decode<\/span><span style=\"color: #ABB2BF\">(FlickrFeedResult.<\/span><span style=\"color: #C678DD\">self<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: data)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.<\/span><span style=\"color: #E06C75\">items<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">setObject<\/span><span style=\"color: #ABB2BF\">(result.<\/span><span style=\"color: #E06C75\">items<\/span><span style=\"color: #ABB2BF\"> as NSArray, <\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #C678DD\">catch<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.<\/span><span style=\"color: #E06C75\">localizedDescription<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">clearCache<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">removeAllObjects<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">refreshPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">clearCache<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}\u00a0<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0434\u0432\u0430 \u043d\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u0430 \u0432 <code>FlickrViewModel<\/code>:&nbsp;<\/span><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\"><code>clearCache()<\/code> \u0434\u043b\u044f \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0432\u0441\u0435\u0445 \u043a\u044d\u0448\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\"><code>refreshPhotos()<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u0442 \u043e\u0431\u043d\u0443\u043b\u0435\u043d\u0438\u0435 \u043a\u0435\u0448\u0430 \u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439<\/span><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043d\u043e\u043f\u043a\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043e\u0447\u0438\u0441\u0442\u0438\u0442 \u043a\u044d\u0448 \u0438 \u0438\u0437\u0432\u043b\u0435\u0447\u0435\u0442 \u0441\u0432\u0435\u0436\u0438\u0435 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0438\u0437 <strong>API Flickr<\/strong>.<\/span><\/p>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u043d\u0430\u0441 \u0443\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442, \u043e\u043f\u044f\u0442\u044c \u043a\u043b\u0438\u043a\u0430\u0435\u043c <strong>Accept All<\/strong>.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXduhoVdXbus2ynGEyU1_u7EmUyexVZhN7X2LF54MCT6O4WwYMyGYFkoc2SNpnwLNACbfi_1VXJByI8GKT7B4xqfSkAIrbqR88VngpM-uwx0Xs-FDwdSCnBSc33SrKC-8Coky_AzOg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:428px;height:auto\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0412\u0435\u0440\u0441\u0438\u044f 11<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXdtq_7X3J5LYMzwR11T5OtOIHH1EEQsTx3DIVlZtax0GpdZGGSQXPnLvU6vICQO13HSvPIVt0POaftKC3jKv-t1fdhk_ozloiisCaaBZA0Dv54oACBZCi8qSETVWRl9KOwN2C7a?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0412\u043d\u0430\u0447\u0430\u043b\u0435 \u043c\u044b \u0434\u0435\u0439\u0441\u0442\u0432\u0443\u0435\u043c \u043a\u0430\u043a \u043e\u0431\u044b\u0447\u043d\u043e: \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u043c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0441 \u0442\u0435\u0433\u0430\u043c\u0438 \u201cRose\u201d \u0438 \u201cSunrise\u201d&nbsp; \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <strong>API Flickr<\/strong> \u0438 \u043e\u043d\u0438 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u043a\u044d\u0448. \u0415\u0441\u043b\u0438 \u043c\u044b \u0432\u043e\u043e\u0431\u0449\u0435 \u043e\u0447\u0438\u0449\u0430\u0435\u043c \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u043a\u0443, \u0442\u043e \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0442\u0430\u043a\u0436\u0435 \u0432\u044b\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0438\u0437 \u043a\u044d\u0448\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">searchText<\/mark><\/code> \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0432 \u043a\u044d\u0448 \u0441\u043e \u0441\u0432\u043e\u0438\u043c\u0438 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u044f\u043c\u0438:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(1 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"let cacheKey = NSString(string: searchText)\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cacheKey = <\/span><span style=\"color: #61AFEF\">NSString<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: searchText)<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041d\u043e \u0435\u0441\u043b\u0438 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0441\u0432\u0435\u0436\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0442\u043e \u043a\u043b\u0438\u043a\u0430\u0435\u043c \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0447\u0438\u0449\u0430\u0435\u0442 \u043a\u044d\u0448 \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u0442 \u0441\u0432\u0435\u0436\u0438\u0435 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0438\u0437 <strong>API Flickr<\/strong>.<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfuh-8CsrdlfVyvHZKSy9CuDPlfStdCpaFgQrwFsaZE72-Yb1VNKJ6mCjN_uEV5z2OQQ5oIvMsPcMLIquxjs4A6DApVwGXFgR5YfOtFBRE9tyPuWg0ZqvBT6H_7s7ZeCgyAl5mV-Q?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:410px;height:auto\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u041a\u043e\u0440\u0440\u0435\u043a\u0446\u0438\u044f \u041c\u043e\u0434\u0435\u043b\u0438<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0415\u0441\u043b\u0438 \u043c\u044b \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043d\u0430 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e&nbsp; \u043e \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438, \u0442\u043e \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c, \u0447\u0442\u043e \u0434\u0430\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">dataUpload<\/mark><\/code> \u0438\u043c\u0435\u0435\u0442 \u0441\u0442\u0440\u0430\u043d\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXe6KuDaUSFWXYidIpF_7ItuVessh871nsa1ap4ZUAGvrRZxpsU8yHLdyf8IxfjUttJ1rOiZX4LdpZlC3Xq-daR1R3kcglH6nZxmjcgMk2Tnp_wb2jXj0VYvE5EfDBBizt-ZeMdlgg?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:341px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e\u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432 \u041c\u043e\u0434\u0435\u043b\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">dataUpload<\/mark><\/code> \u0438 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">published<\/mark><\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0434\u0430\u0442\u0430\u043c\u0438, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043a\u0430\u043a \u0441\u0442\u0440\u043e\u043a\u0438 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">String<\/mark><\/code>:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXexB-AW2DTdvAAQjac6Uuh6lhZyhJu9aMg3VQFV3APi-IegcSPSOxMd7txdZXcfWKZ5NYFOrfJnoTrHmBVdhPhiyZWstcK-xqLy6QkZ6gcy_ULVwTLjfTputNstkQAadBPOyOgWuw?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0422\u0430\u043a \u043a\u0430\u043a \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">FlickrPhoto<\/mark><\/code> \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">Codable<\/mark><\/code>, \u0442\u043e \u043c\u044b \u043c\u043e\u0433\u043b\u0438 \u0431\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0432 \u0434\u0430\u0442\u044b <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">Date<\/mark><\/code> \u043f\u0440\u0438 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code><mark style=\"background-color:#e2e2e2\" class=\"has-inline-color\">JSONDecoder()<\/mark><\/code>.<br>\u041f\u0440\u043e\u0441\u0438\u043c \u043e\u0431 \u044d\u0442\u043e\u043c<strong> Cursor AI:<\/strong><\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXc-_yzn52qU2X0fXMaDXMqYu1fzvRERvzcMfLzHd9IwYIac1YE8Q-yXkIq02uNIxW0Jewf7kDODSgkT4Et1VX6T3EpHR_vF3_ROD9Jk9n4yqeY5CxsO9m-cx_KH6pVb2HQ21LIsBQ?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><span style=\"font-weight: 400;\"><img loading=\"lazy\" decoding=\"async\" width=\"41\" height=\"39\" class=\"wp-image-16237\" style=\"width: 41px;\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Screenshot-2024-11-30-at-16.54.50-1.png\" alt=\"\">\u0412 \u041c\u043e\u0434\u0435\u043b\u0438 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>published<\/code> \u0438 <code>dateTaken<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u043a\u0430\u043a \u0434\u0430\u0442\u0443 <code>Date<\/code> \u0438 \u043e\u0431\u043d\u043e\u0432\u0438 <code>JSONDecoder() <\/code>\u0441 <code>JSONDecoder.DateDecodingStratege.iso8601<\/code><\/span><\/p>\n\n\n\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042f \u043f\u043e\u043c\u043e\u0433\u0443 \u0432\u0430\u043c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c <code>FlickrPhoto<\/code> \u0438 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044e \u0434\u0435\u043a\u043e\u0434\u0435\u0440\u0430.&nbsp;<br>\u0412\u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"struct FlickrFeedResult: Codable {\n    let items: [FlickrPhoto]\n}\n\nstruct FlickrPhoto: Codable, Identifiable {\n    let title: String\n    let link: String\n    let media: Media\n    let dateTaken: Date\n    let description: String\n    let published: Date\n    let author: String\n    let tags: String\n    \n    \/\/ Computed property for ID\n    var id: String { link }\n    \n    enum CodingKeys: String, CodingKey {\n        case title, link, media\n        case dateTaken = &quot;date_taken&quot;\n        case description, published, author, tags\n    }\n}\n\nstruct Media: Codable {\n    let m: String\n    \n    var originalURL: String {\n        m.replacingOccurrences(of: &quot;_m.&quot;, with: &quot;.&quot;)\n    }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrFeedResult<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">Codable <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> items: [FlickrPhoto]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrPhoto<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">Codable<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E5C07B\">Identifiable <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> title: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> link: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> media: Media<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> dateTaken: Date<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> description: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> published: Date<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> author: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #7F848E; font-style: italic\">\/\/ Computed property for ID<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> id: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\"> { link }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">enum<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">CodingKeys<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E5C07B\">CodingKey <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #C678DD\">case<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E06C75\">title<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E06C75\">link<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E06C75\">media<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #C678DD\">case<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E06C75\">dateTaken<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #56B6C2\">=<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #98C379\">&quot;date_taken&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #C678DD\">case<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E06C75\">description<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E06C75\">published<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E06C75\">author<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #E06C75\">tags<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Media<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">Codable <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> m: <\/span><span style=\"color: #E5C07B\">String<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> originalURL: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        m.<\/span><span style=\"color: #61AFEF\">replacingOccurrences<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">of<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;_m.&quot;<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">with<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;.&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0418 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 <code>JSONDecoder<\/code>() \u0432 <code>FlickrViewModel<\/code>:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXcza5e_F-zYDoLe1Fht9FhH5vB1GLfcfjwZT8wWMZlZqDNVPXwMwzUrl1gehXwFJ9K-F2rlegiDRbbsMan59QxJJGrFneW72QFANw6y9QQ7fj2mbVfV1_Yzk5BXE5LJuhYGLQEJ?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0412\u043e\u0442 \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 <code>FlickrViewModel<\/code>:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ ... existing code ...\n\nfunc fetchPhotos() async {\n\u00a0 isLoading = true\n\u00a0 errorMessage = nil\n\u00a0\n\u00a0 do {\n\u00a0 \u00a0 \u00a0 let cacheKey = NSString(string: searchText)\n\u00a0 \u00a0 \u00a0 if let cachedPhotos = cache.object(forKey: cacheKey) as? [FlickrPhoto] {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 var urlString = baseURL\n\u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 if !searchText.isEmpty {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let tags = searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .components(separatedBy: &quot; &quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .filter { !$0.isEmpty }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .joined(separator: &quot;,&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0if let encodedTags = tags.addingPercentEncoding(\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 guard let url = URL(string: urlString) else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 throw URLError(.badURL)\n\u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 let (data, _) = try await URLSession.shared.data(from: url)\n\u00a0 \u00a0 \u00a0 let decoder = JSONDecoder()\n\u00a0 \u00a0 \u00a0 decoder.dateDecodingStrategy = .iso8601\n\u00a0 \u00a0 \u00a0 let result = try decoder.decode(FlickrFeedResult.self, from: data)\n\u00a0 \u00a0 \u00a0 photos = result.items\n\u00a0 \u00a0 \u00a0 cache.setObject(result.items as NSArray, forKey: cacheKey)\n\u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 } catch {\n\u00a0 \u00a0 \u00a0 errorMessage = error.localizedDescription\n\u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 }\n}\n\n\/\/ ... rest of the code ...\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7F848E; font-style: italic\">\/\/ ... existing code ...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 isLoading = <\/span><span style=\"color: #D19A66\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 errorMessage = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 <\/span><span style=\"color: #C678DD\">do<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cacheKey = <\/span><span style=\"color: #61AFEF\">NSString<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: searchText)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cachedPhotos = cache.<\/span><span style=\"color: #61AFEF\">object<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey) as? [FlickrPhoto] {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> urlString = baseURL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> !searchText.isEmpty {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags = searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">components<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separatedBy<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot; &quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">filter<\/span><span style=\"color: #ABB2BF\"> { !<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">.isEmpty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">joined<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separator<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;,&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">guard<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> url = <\/span><span style=\"color: #61AFEF\">URL<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: urlString) <\/span><span style=\"color: #C678DD\">else<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">throw<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">URLError<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">badURL<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> (data, _) = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> URLSession.<\/span><span style=\"color: #E06C75\">shared<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">data<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: url)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> decoder = <\/span><span style=\"color: #61AFEF\">JSONDecoder<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 decoder.<\/span><span style=\"color: #E06C75\">dateDecodingStrategy<\/span><span style=\"color: #ABB2BF\"> = .<\/span><span style=\"color: #E06C75\">iso8601<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> result = <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> decoder.<\/span><span style=\"color: #56B6C2\">decode<\/span><span style=\"color: #ABB2BF\">(FlickrFeedResult.<\/span><span style=\"color: #C678DD\">self<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: data)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 photos = result.<\/span><span style=\"color: #E06C75\">items<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">setObject<\/span><span style=\"color: #ABB2BF\">(result.<\/span><span style=\"color: #E06C75\">items<\/span><span style=\"color: #ABB2BF\"> as NSArray, <\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 } <\/span><span style=\"color: #C678DD\">catch<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 errorMessage = error.<\/span><span style=\"color: #E06C75\">localizedDescription<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7F848E; font-style: italic\">\/\/ ... rest of the code ...<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043d\u0430\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c <code>PhotoDetailView<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435&nbsp; <code>Date<\/code> \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\/\/ ... existing code ...\n\nText(&quot;Taken on \\(formatDate(photo.dateTaken))&quot;)\n\u00a0 \u00a0 .font(.subheadline)\n\u00a0 \u00a0 .foregroundColor(.secondary)\n\n\/\/ ... rest of the code ...\n\n\/\/ Update formatDate to take Date instead of optional Date\nprivate func formatDate(_ date: Date) -&gt; String {\n\u00a0 \u00a0 let formatter = DateFormatter()\n\u00a0 \u00a0 formatter.dateStyle = .long\n\u00a0 \u00a0 formatter.timeStyle = .short\n\u00a0 \u00a0 return formatter.string(from: date)\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #7F848E; font-style: italic\">\/\/ ... existing code ...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #61AFEF\">Text<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Taken on <\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #61AFEF\">formatDate<\/span><span style=\"color: #ABB2BF\">(photo.<\/span><span style=\"color: #E06C75\">dateTaken<\/span><span style=\"color: #ABB2BF\">)<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">font<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">subheadline<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">foregroundColor<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">secondary<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7F848E; font-style: italic\">\/\/ ... rest of the code ...<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #7F848E; font-style: italic\">\/\/ Update formatDate to take Date instead of optional Date<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">formatDate<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">_<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #ABB2BF; font-style: italic\">date<\/span><span style=\"color: #ABB2BF\">: Date) -&gt; <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> formatter = <\/span><span style=\"color: #61AFEF\">DateFormatter<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 formatter.<\/span><span style=\"color: #E06C75\">dateStyle<\/span><span style=\"color: #ABB2BF\"> = .<\/span><span style=\"color: #E06C75\">long<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 formatter.<\/span><span style=\"color: #E06C75\">timeStyle<\/span><span style=\"color: #ABB2BF\"> = .<\/span><span style=\"color: #E06C75\">short<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">return<\/span><span style=\"color: #ABB2BF\"> formatter.<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: date)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\">\u0421\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 <code>dateTaken<\/code> \u0438 <code>published<\/code> \u0442\u0438\u043f\u0430\u043c\u0438 <code>Date<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>String<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u0442\u0435 <code>JSONDecode<\/code>r \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u0442 ISO8601<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0423\u0434\u0430\u043b\u0438\u0442\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>dateUpload<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e <code>published<\/code> \u043a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u0434\u0430\u0442\u0430 <code>Date<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u041e\u0431\u043d\u043e\u0432\u0438\u0442\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <code>formatDate<\/code>, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0430 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u043b\u0430 \u041d\u0415 <code>Optional Date<\/code><\/span><\/li>\n<\/ol>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042d\u0442\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442 \u043d\u0430\u0434\u043b\u0435\u0436\u0430\u0449\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0434\u0430\u0442 <code>Date<\/code> \u0432\u043e \u0432\u0441\u0435\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438 \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043d\u044f\u0442\u043d\u044b\u0439 \u043a\u043e\u0434 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u0442.<br> \u0422\u0435\u043f\u0435\u0440\u044c \u0434\u0430\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0438 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfxENmHnMrpmxk6AEAJya9EQIsfgtFDAZWGN_sZG1bgk23XmPok34MY5EP_R2V8r7qTkWq1WxxxDCuyytDE8H_cbKCoC-0544BtbWRED-O48yLrvP9xahuO_G4Ws9tgq3wIZXTn?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\" style=\"width:396px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>&nbsp;\u0417\u0430\u043c\u0435\u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 ObservableObject \u043d\u0430 \u043c\u0430\u043a\u0440\u043e\u0441 @Observable<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXfOvc85XoTPaHSGqvA-PEbmlOKqROzC7GiTgYdA0pJkeoR9IV-wigJqrMNKX9ZTuv5QiYzHwufWwU79G5eUHyXbg_5qlzJ2jyXo80nC6esZqa9LjJHbmIGWisiAC4ifhm5JUXcdzQ?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-light-gray-background-color has-background wp-block-paragraph\"><span style=\"font-weight: 400;\"><img loading=\"lazy\" decoding=\"async\" width=\"41\" height=\"39\" class=\"wp-image-16237\" style=\"width: 41px;\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/11\/Screenshot-2024-11-30-at-16.54.50-1.png\" alt=\"\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 \u043c\u0430\u043a\u0440\u043e\u0441<code> @Observable<\/code> \u0434\u043b\u044f <code>FlickrViewModel<\/code> \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439 <code>Combine<\/code> \u0438 <code>var searchSubject = PassthroughSubject&lt;String, Never>()<\/code><\/span><\/p>\n\n\n\n<div class=\"wp-block-group has-light-gray-background-color has-background\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042f \u043f\u043e\u043c\u043e\u0433\u0443 \u0432\u0430\u043c \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c <code>FlickrViewModel<\/code> \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0430\u043a\u0440\u043e\u0441\u0430 <code>@Observable <\/code>\u0438 <code>Combine PassthroughSubject<\/code>. \u0412\u043e\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u043d\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"import Foundation\nimport SwiftUI\nimport Combine\n\n@Observable\nfinal class FlickrViewModel {\n\u00a0 \u00a0 var photos: [FlickrPhoto] = []\n\u00a0 \u00a0 var searchText = &quot;&quot;\n\u00a0 \u00a0 var isLoading = false\n\u00a0 \u00a0 var errorMessage: String?\n\u00a0 \u00a0\n\u00a0 \u00a0 private let baseURL = &quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;\n\u00a0 \u00a0 private var cancellables = Set&lt;AnyCancellable&gt;()\n\u00a0 \u00a0 private let cache = NSCache&lt;NSString, NSArray&gt;()\n\u00a0 \u00a0 private let searchSubject = PassthroughSubject&lt;String, Never&gt;()\n\u00a0 \u00a0\n\u00a0 \u00a0 init() {\n\u00a0 \u00a0 \u00a0 \u00a0 setupSearchSubscription()\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 private func setupSearchSubscription() {\n\u00a0 \u00a0 \u00a0 \u00a0 searchSubject\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .removeDuplicates()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .sink { [weak self] _ in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Task { @MainActor in\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 await self?.fetchPhotos()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .store(in: &amp;cancellables)\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func updateSearchText(_ newText: String) {\n\u00a0 \u00a0 \u00a0 \u00a0 searchText = newText\n\u00a0 \u00a0 \u00a0 \u00a0 searchSubject.send(newText)\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 @MainActor\n\u00a0 \u00a0 func fetchPhotos() async {\n\u00a0 \u00a0 \u00a0 \u00a0 isLoading = true\n\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = nil\n\u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 do {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let cacheKey = NSString(string: searchText)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let cachedPhotos = \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0      cache.object(forKey: cacheKey) as? [FlickrPhoto] {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 return\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 var urlString = baseURL\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if !searchText.isEmpty {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let tags = searchText\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .components(separatedBy: &quot; &quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .filter { !$0.isEmpty }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .joined(separator: &quot;,&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if let encodedTags = tags.addingPercentEncoding(\u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0 \u00a0 \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 guard let url = URL(string: urlString) else {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 throw URLError(.badURL)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let (data, _) = \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0     try await URLSession.shared.data(from: url)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let decoder = JSONDecoder()\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 decoder.dateDecodingStrategy = .iso8601\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 let result = \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   try decoder.decode(FlickrFeedResult.self, from: data)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.items\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.setObject(result.items as NSArray, \n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0                 forKey: cacheKey)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 } catch {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.localizedDescription\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = false\n\u00a0 \u00a0 \u00a0 \u00a0 }\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 func clearCache() {\n\u00a0 \u00a0 \u00a0 \u00a0 cache.removeAllObjects()\n\u00a0 \u00a0 }\n\u00a0 \u00a0\n\u00a0 \u00a0 @MainActor\n\u00a0 \u00a0 func refreshPhotos() async {\n\u00a0 \u00a0 \u00a0 \u00a0 clearCache()\n\u00a0 \u00a0 \u00a0 \u00a0 await fetchPhotos()\n\u00a0 \u00a0 }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Foundation<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">SwiftUI<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #C678DD\">import<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">Combine<\/span><\/span>\n<span class=\"line\"><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">@Observable<\/span><\/span>\n<span class=\"line\"><span style=\"color: #C678DD\">final<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">class<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> photos: [FlickrPhoto] = []<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> searchText = <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> errorMessage: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">?<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> baseURL = <\/span><span style=\"color: #98C379\">&quot;https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> cancellables = <\/span><span style=\"color: #E5C07B\">Set<\/span><span style=\"color: #ABB2BF\">&lt;AnyCancellable&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cache = NSCache&lt;NSString, NSArray&gt;()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> searchSubject = PassthroughSubject&lt;<\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">, Never&gt;()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">init<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">setupSearchSubscription<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 searchSubject<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">debounce<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">for<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #61AFEF\">milliseconds<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">500<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">scheduler<\/span><span style=\"color: #ABB2BF\">: DispatchQueue.<\/span><span style=\"color: #E06C75\">main<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">removeDuplicates<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">sink<\/span><span style=\"color: #ABB2BF\"> { [<\/span><span style=\"color: #C678DD\">weak<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">] _ <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> { <\/span><span style=\"color: #C678DD\">@MainActor<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">self<\/span><span style=\"color: #ABB2BF\">?.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">store<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">in<\/span><span style=\"color: #ABB2BF\">: &amp;cancellables)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">updateSearchText<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">_<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #ABB2BF; font-style: italic\">newText<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">String<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 searchText = newText<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 searchSubject.<\/span><span style=\"color: #61AFEF\">send<\/span><span style=\"color: #ABB2BF\">(newText)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">true<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 errorMessage = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">do<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cacheKey = <\/span><span style=\"color: #61AFEF\">NSString<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: searchText)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> cachedPhotos = <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0      cache.<\/span><span style=\"color: #61AFEF\">object<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey) as? [FlickrPhoto] {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = cachedPhotos<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">return<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> urlString = baseURL<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> !searchText.isEmpty {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> tags = searchText<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #61AFEF\">components<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separatedBy<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot; &quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">filter<\/span><span style=\"color: #ABB2BF\"> { !<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">.isEmpty }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 .<\/span><span style=\"color: #56B6C2\">joined<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">separator<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;,&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\">(\u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   }\u00a0 \u00a0 <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">guard<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> url = <\/span><span style=\"color: #61AFEF\">URL<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">string<\/span><span style=\"color: #ABB2BF\">: urlString) <\/span><span style=\"color: #C678DD\">else<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">throw<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">URLError<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #E06C75\">badURL<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> (data, _) = <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0     <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> URLSession.<\/span><span style=\"color: #E06C75\">shared<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">data<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: url)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> decoder = <\/span><span style=\"color: #61AFEF\">JSONDecoder<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 decoder.<\/span><span style=\"color: #E06C75\">dateDecodingStrategy<\/span><span style=\"color: #ABB2BF\"> = .<\/span><span style=\"color: #E06C75\">iso8601<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> result = <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0   <\/span><span style=\"color: #C678DD\">try<\/span><span style=\"color: #ABB2BF\"> decoder.<\/span><span style=\"color: #56B6C2\">decode<\/span><span style=\"color: #ABB2BF\">(FlickrFeedResult.<\/span><span style=\"color: #C678DD\">self<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">from<\/span><span style=\"color: #ABB2BF\">: data)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 photos = result.<\/span><span style=\"color: #E06C75\">items<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">setObject<\/span><span style=\"color: #ABB2BF\">(result.<\/span><span style=\"color: #E06C75\">items<\/span><span style=\"color: #ABB2BF\"> as NSArray, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0                 <\/span><span style=\"color: #61AFEF\">forKey<\/span><span style=\"color: #ABB2BF\">: cacheKey)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 } <\/span><span style=\"color: #C678DD\">catch<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 errorMessage = error.<\/span><span style=\"color: #E06C75\">localizedDescription<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 isLoading = <\/span><span style=\"color: #D19A66\">false<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">clearCache<\/span><span style=\"color: #ABB2BF\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 cache.<\/span><span style=\"color: #61AFEF\">removeAllObjects<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">@MainActor<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">func<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">refreshPhotos<\/span><span style=\"color: #ABB2BF\">() <\/span><span style=\"color: #C678DD\">async<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #61AFEF\">clearCache<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0410 \u0432\u043e\u0442 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0439 <code>ContentView<\/code> \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043d\u043e\u0432\u043e\u0439 <code>FlickrViewModel<\/code>:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(2 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"struct ContentView: View {\n    @State private var viewModel = FlickrViewModel()\n   \n    let columns = [\n        GridItem(.adaptive(minimum: 108), spacing: 1),\n        GridItem(.adaptive(minimum: 108), spacing: 1),\n        GridItem(.adaptive(minimum: 108), spacing: 1)\n    ]\n   \n    var body: some View {\n        NavigationStack {\n            ZStack {\n                Color.black.opacity(0.1)\n               \n                ScrollView {\n                    LazyVGrid(columns: columns, spacing: 1) {\n                        ForEach(viewModel.photos) { photo in\n                            NavigationLink(destination: \n                                 PhotoDetailView(photo: photo)) {\n                                PhotoGridItem(photo: photo)\n                            }\n                        }\n                    }\n                }\n               \n                if viewModel.isLoading {\n                    ProgressView()\n                        .scaleEffect(1.5)\n                        .frame(maxWidth: .infinity, \n                               maxHeight: .infinity)\n                        .background(Color.black.opacity(0.1))\n                }\n            }\n            .navigationTitle(&quot;Flickr Photos&quot;)\n            .searchable(\n                text: .init(\n                    get: { viewModel.searchText },\n                    set: { viewModel.updateSearchText($0) }\n                ),\n                prompt: &quot;Search photos&quot;\n            )\n            .alert(&quot;Error&quot;, isPresented:\n                      .constant(viewModel.errorMessage != nil)) {\n                Button(&quot;OK&quot;) {\n                    viewModel.errorMessage = nil\n                }\n            } message: {\n                Text(viewModel.errorMessage ?? &quot;&quot;)\n            }\n            .toolbar {\n                ToolbarItem(placement: .navigationBarTrailing) {\n                    Button(action: {\n                        Task {\n                            await viewModel.refreshPhotos()\n                        }\n                    }) {\n                        Image(systemName: &quot;arrow.clockwise&quot;)\n                    }\n                }\n            }\n        }\n        .task {\n            await viewModel.fetchPhotos()\n        }\n    }\n}\" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #C678DD\">struct<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #E5C07B\">ContentView<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #E5C07B\">View <\/span><span style=\"color: #ABB2BF\">{<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">@State<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">private<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> viewModel = <\/span><span style=\"color: #61AFEF\">FlickrViewModel<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">   <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> columns = [<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">),<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #61AFEF\">GridItem<\/span><span style=\"color: #ABB2BF\">(.<\/span><span style=\"color: #61AFEF\">adaptive<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">minimum<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">108<\/span><span style=\"color: #ABB2BF\">), <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    ]<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">   <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    <\/span><span style=\"color: #C678DD\">var<\/span><span style=\"color: #ABB2BF\"> body: <\/span><span style=\"color: #C678DD\">some<\/span><span style=\"color: #ABB2BF\"> View {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        <\/span><span style=\"color: #61AFEF\">NavigationStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            <\/span><span style=\"color: #61AFEF\">ZStack<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">               <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">ScrollView<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    <\/span><span style=\"color: #61AFEF\">LazyVGrid<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">columns<\/span><span style=\"color: #ABB2BF\">: columns, <\/span><span style=\"color: #61AFEF\">spacing<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #D19A66\">1<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        <\/span><span style=\"color: #61AFEF\">ForEach<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">photos<\/span><span style=\"color: #ABB2BF\">) { photo <\/span><span style=\"color: #C678DD\">in<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                            <\/span><span style=\"color: #61AFEF\">NavigationLink<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">destination<\/span><span style=\"color: #ABB2BF\">: <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                                 <\/span><span style=\"color: #61AFEF\">PhotoDetailView<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                                <\/span><span style=\"color: #61AFEF\">PhotoGridItem<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">photo<\/span><span style=\"color: #ABB2BF\">: photo)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">               <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> viewModel.isLoading {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    <\/span><span style=\"color: #61AFEF\">ProgressView<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        .<\/span><span style=\"color: #61AFEF\">scaleEffect<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">1.5<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        .<\/span><span style=\"color: #61AFEF\">frame<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">maxWidth<\/span><span style=\"color: #ABB2BF\">: .infinity, <\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                               <\/span><span style=\"color: #61AFEF\">maxHeight<\/span><span style=\"color: #ABB2BF\">: .infinity)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        .<\/span><span style=\"color: #61AFEF\">background<\/span><span style=\"color: #ABB2BF\">(Color.<\/span><span style=\"color: #E06C75\">black<\/span><span style=\"color: #ABB2BF\">.<\/span><span style=\"color: #61AFEF\">opacity<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #D19A66\">0.1<\/span><span style=\"color: #ABB2BF\">))<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">            .<\/span><span style=\"color: #61AFEF\">navigationTitle<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Flickr Photos&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">            .<\/span><span style=\"color: #61AFEF\">searchable<\/span><span style=\"color: #ABB2BF\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">text<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #C678DD\">init<\/span><span style=\"color: #ABB2BF\">(<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">                    <\/span><span style=\"color: #61AFEF\">get<\/span><span style=\"color: #ABB2BF\">: { viewModel.<\/span><span style=\"color: #E06C75\">searchText<\/span><span style=\"color: #ABB2BF\"> },<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">                    <\/span><span style=\"color: #61AFEF\">set<\/span><span style=\"color: #ABB2BF\">: { viewModel.<\/span><span style=\"color: #61AFEF\">updateSearchText<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #E5C07B\">$0<\/span><span style=\"color: #ABB2BF\">) }<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">                ),<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">prompt<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;Search photos&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            )<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            .<\/span><span style=\"color: #61AFEF\">alert<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;Error&quot;<\/span><span style=\"color: #ABB2BF\">, <\/span><span style=\"color: #61AFEF\">isPresented<\/span><span style=\"color: #ABB2BF\">:<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                      .<\/span><span style=\"color: #61AFEF\">constant<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> != <\/span><span style=\"color: #D19A66\">nil<\/span><span style=\"color: #ABB2BF\">)) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">Button<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #98C379\">&quot;OK&quot;<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> = <\/span><span style=\"color: #D19A66\">nil<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            } <\/span><span style=\"color: #61AFEF\">message<\/span><span style=\"color: #ABB2BF\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">Text<\/span><span style=\"color: #ABB2BF\">(viewModel.<\/span><span style=\"color: #E06C75\">errorMessage<\/span><span style=\"color: #ABB2BF\"> ?? <\/span><span style=\"color: #98C379\">&quot;&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            .<\/span><span style=\"color: #61AFEF\">toolbar<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                <\/span><span style=\"color: #61AFEF\">ToolbarItem<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">placement<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">navigationBarTrailing<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    <\/span><span style=\"color: #61AFEF\">Button<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">action<\/span><span style=\"color: #ABB2BF\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        <\/span><span style=\"color: #61AFEF\">Task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                            <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> viewModel.<\/span><span style=\"color: #61AFEF\">refreshPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    }) {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                        <\/span><span style=\"color: #61AFEF\">Image<\/span><span style=\"color: #ABB2BF\">(<\/span><span style=\"color: #61AFEF\">systemName<\/span><span style=\"color: #ABB2BF\">: <\/span><span style=\"color: #98C379\">&quot;arrow.clockwise&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">                }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        .<\/span><span style=\"color: #61AFEF\">task<\/span><span style=\"color: #ABB2BF\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">            <\/span><span style=\"color: #C678DD\">await<\/span><span style=\"color: #ABB2BF\"> viewModel.<\/span><span style=\"color: #61AFEF\">fetchPhotos<\/span><span style=\"color: #ABB2BF\">()<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">    }<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">}<\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f:<\/strong><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><span style=\"font-weight: 400;\">\u0417\u0430\u043c\u0435\u043d\u0435\u043d\u044b <code>@MainActo<\/code>r class \u0438 <code>@Published <\/code>\u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 <code>@Observable<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d <code>PassthroughSubject<\/code> \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0421\u043e\u0437\u0434\u0430\u043d \u043d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <code>updateSearchText <\/code>\u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">C\u0434\u0435\u043b\u0430\u043b\u0438 \u200b\u200b<code>FlickrViewModel final class<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0418\u0437\u043c\u0435\u043d\u0435\u043d <code>@StateObject<\/code> \u043d\u0430 <code>@State <\/code>\u0432 <code>ContentView<\/code>, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c <code>@Observable<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u041e\u0431\u043d\u043e\u0432\u043b\u0451\u043d \u200b\u200b <code>.searchable <\/code>\u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 <code>updateSearchText<\/code><\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u044f\u0432\u043d\u044b\u0435 \u0430\u043d\u043d\u043e\u0442\u0430\u0446\u0438\u0438 <code>@MainActor<\/code>, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e<\/span><\/li>\n\n\n\n<li><span style=\"font-weight: 400;\">\u0423\u0434\u0430\u043b\u0435\u043d\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 <code>ObservableObject,<\/code> \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043e\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e<\/span><\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042d\u0442\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043c\u043e\u0434\u0435\u0440\u043d\u0438\u0437\u0438\u0440\u0443\u044e\u0442 \u043a\u043e\u0434 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0431\u043e\u043b\u0435\u0435 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 Swift, \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044f \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u0442\u0443 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c. \u0424\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0438\u0441\u043a\u0430 \u0442\u0435\u043f\u0435\u0440\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>PassthroughSubject<\/code> \u0434\u043b\u044f \u043b\u0443\u0447\u0448\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u043d\u0430\u0434 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u043e\u0438\u0441\u043a\u0430 <code>searchText<\/code>.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u0447\u0435\u043d\u044c \u043a\u0440\u0443\u0442\u043e\u0439 \u043a\u043e\u0434, \u0441\u043e\u0447\u0435\u0442\u0430\u044e\u0449\u0438\u0439 \u043c\u0430\u043a\u0440\u043e\u0441 <code>@Observable<\/code> \u0441 <code>Combine<\/code>.&nbsp;<\/span><\/p>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442. \u0414\u043b\u044f \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043d\u0435\u0442 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u201c\u043f\u0430\u0440\u0430\u0437\u0438\u0442\u043d\u044b\u0439\u201d \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043a <strong>Flickr API<\/strong> &nbsp;\u043f\u0440\u0438 \u043d\u0430\u0431\u043e\u0440\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 <code>searchText<\/code>, \u0431\u0443\u0434\u0435\u043c \u043a\u0430\u043a \u0438 \u0440\u0430\u043d\u044c\u0448\u0435 \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c <code>tags<\/code>, \u0434\u043b\u044f \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044d\u0442\u043e\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f:<\/span><\/p>\n\n\n\n<div class=\"wp-block-kevinbatdorf-code-block-pro cbp-has-line-numbers\" data-code-block-pro-font-family=\"Code-Pro-JetBrains-Mono\" style=\"font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-color:#abb2bf;--cbp-line-number-width:calc(1 * 0.6 * .75rem);--cbp-line-highlight-color:rgba(134, 167, 228, 0.2);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)\"><span style=\"display:block;padding:16px 0 0 16px;margin-bottom:-1px;width:100%;text-align:left;background-color:#282c34\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"54\" height=\"14\" viewBox=\"0 0 54 14\"><g fill=\"none\" fill-rule=\"evenodd\" transform=\"translate(1 1)\"><circle cx=\"6\" cy=\"6\" r=\"6\" fill=\"#FF5F56\" stroke=\"#E0443E\" stroke-width=\".5\"><\/circle><circle cx=\"26\" cy=\"6\" r=\"6\" fill=\"#FFBD2E\" stroke=\"#DEA123\" stroke-width=\".5\"><\/circle><circle cx=\"46\" cy=\"6\" r=\"6\" fill=\"#27C93F\" stroke=\"#1AAB29\" stroke-width=\".5\"><\/circle><\/g><\/svg><\/span><span role=\"button\" tabindex=\"0\" data-code=\"\u00a0if let encodedTags = tags.addingPercentEncoding (\n\u00a0                                 withAllowedCharacters: .urlQueryAllowed) {\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print (&quot;--------------------------- \\(encodedTags)&quot;)\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += &quot;&amp;tags=\\(encodedTags)&quot;\n\u00a0 } \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \" style=\"color:#abb2bf;display:none\" aria-label=\"Copy\" class=\"code-block-pro-copy-button\"><svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" style=\"width:24px;height:24px\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\"><path class=\"with-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M4.5 12.75l6 6 9-13.5\"><\/path><path class=\"without-check\" stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6\"><\/path><\/svg><\/span><pre class=\"shiki one-dark-pro\" style=\"background-color: #282c34\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0<\/span><span style=\"color: #C678DD\">if<\/span><span style=\"color: #ABB2BF\"> <\/span><span style=\"color: #C678DD\">let<\/span><span style=\"color: #ABB2BF\"> encodedTags = tags.<\/span><span style=\"color: #61AFEF\">addingPercentEncoding<\/span><span style=\"color: #ABB2BF\"> (<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0                                 <\/span><span style=\"color: #61AFEF\">withAllowedCharacters<\/span><span style=\"color: #ABB2BF\">: .<\/span><span style=\"color: #E06C75\">urlQueryAllowed<\/span><span style=\"color: #ABB2BF\">) {<\/span><\/span>\n<span class=\"line cbp-line-highlight\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"color: #56B6C2\">print<\/span><span style=\"color: #ABB2BF\"> (<\/span><span style=\"color: #98C379\">&quot;--------------------------- <\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><span style=\"color: #ABB2BF\">)<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 urlString += <\/span><span style=\"color: #98C379\">&quot;&amp;tags=<\/span><span style=\"color: #C678DD\">\\(<\/span><span style=\"color: #ABB2BF\">encodedTags<\/span><span style=\"color: #C678DD\">)<\/span><span style=\"color: #98C379\">&quot;<\/span><\/span>\n<span class=\"line\"><span style=\"color: #ABB2BF\">\u00a0 } \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><\/span><\/code><\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0412\u0435\u0440\u0441\u0438\u044f 12<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXf5Cw5yKxtPUsB2nodmjGKnsZiwpLvadygw0DF61FdbFbbPHuiFLJ93CyMY4qtK3GEoS_wLGjLtoXIR061Fo8nzxgVXeUFI7pnMNv1OL9bTAQLZVDQbB63qVUvwKnww-7n1pItOvQ?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041c\u044b \u0432\u0438\u0434\u0438\u043c, \u0447\u0442\u043e \u0432\u0441\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432\u0435\u043b\u0438\u043a\u043e\u043b\u0435\u043f\u043d\u043e &#8212; \u043d\u0438\u043a\u0430\u043a\u0438\u0445 \u043d\u0435\u043d\u0443\u0436\u043d\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u0440\u0438 \u043d\u0430\u0431\u043e\u0440\u0435 \u0432 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u201cRose\u201d, \u201cSunrise\u201d, \u201cOcean\u201d \u043d\u0435\u0442. \u041f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0434\u043d\u043e\u043a\u0440\u0430\u0442\u043d\u0430\u044f \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0438 \u0437\u0430\u043f\u0438\u0441\u044c \u0432 \u043a\u044d\u0448. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u043d\u0430\u0431\u043e\u0440\u0435&nbsp; \u201cSunrise\u201d \u044d\u0442\u043e \u0441\u043b\u043e\u0432\u043e \u043d\u0430 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u043d\u0435 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u0432\u044b\u0431\u043e\u0440\u043a\u0430 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438\u0434\u0435\u0442 \u0438\u0437 \u043a\u044d\u0448\u0430.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <strong>PhotomaniaCursor<\/strong> \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/PhotomaniaCursor\" title=\"\">Github.com<\/a>. <br>\u041e\u0442\u043c\u0435\u0447\u0443, \u0447\u0442\u043e \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0430 <strong>LLM Claude 3.5 Sonnet<\/strong>:&nbsp;<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeezEM2wzWRngnVIfoigs1iDlWIXy6IoGnYzBSTIoGhAwbvNqncutCowHbNjNJtGlTOLpxdYd2jSvOq_M8GFZ71LQJ4Zf-O2zojFNNHb0VWCoEdj8y2bV1l_DF7kvD0BQ5v2_Fp-A?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u2026 \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0447\u0435\u043d\u044c \u0445\u043e\u0440\u043e\u0448\u0430 \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u043e \u0431\u0443\u0434\u044c\u0442\u0435 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u044b \u0441 <strong>Claude 3.5 Sonnet<\/strong>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0438\u043d\u043e\u0433\u0434\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0447\u0435\u043d\u044c \u0442\u0440\u0443\u0434\u043d\u043e \u043d\u0430\u0439\u0442\u0438. \u041d\u0435 \u043f\u043e\u0434\u0434\u0430\u0432\u0430\u0439\u0442\u0435\u0441\u044c \u044d\u0439\u0444\u043e\u0440\u0438\u0438 \u0438 \u043d\u0435 \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0439 \u0437\u0430\u0432\u0435\u0441\u0442\u0438 \u0441\u0435\u0431\u044f \u0432 \u0437\u0430\u043f\u0443\u0442\u0430\u043d\u043d\u0443\u044e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044e, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0439\u0442\u0435 \u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0439\u0442\u0435 \u043a\u043e\u0434. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0432 \u044d\u0442\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439 \u043d\u0435 \u0431\u044b\u043b\u043e. <br>\u041a\u0430\u043a \u0432\u0438\u0434\u043d\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 LLM.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0420\u0430\u0431\u043e\u0442\u0430 \u0441 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u043c \u043a\u043e\u0434\u0430<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0414\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438 \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u0443 \u201c\u0444\u0438\u0448\u043a\u0443\u201d &nbsp;<strong>Cursor AI &#8212; Composer<\/strong>, a \u0438\u0445 \u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e: Chat, \u2318K , \u2318L ,Tab, Editor \u0438 Terminal.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e  \u2318 K \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u0442\u044c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430, a \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0438\u0442\u044c \u043e\u0431\u044a\u044f\u0441\u043d\u0435\u043d\u0438\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0434\u0435\u043b\u0430\u0435\u0442 \u044d\u0442\u043e\u0442 \u043a\u043e\u0434, \u0438 <strong>Cursor AI<\/strong> \u0434\u043e\u0431\u0430\u0432\u0438\u0442 \u0432\u0430\u043c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0438, \u0440\u0430\u0437\u044a\u044f\u0441\u043d\u044f\u044e\u0449\u0438\u0435 \u044d\u0442\u043e\u0442 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442 \u043a\u043e\u0434\u0430 \u2014 \u044d\u0442\u043e \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0443\u0447\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e:<\/span><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/lh7-rt.googleusercontent.com\/docsz\/AD_4nXeCFXKLE5HOJ9NOXIR64Vq53jUTjnrwLSUe5Cd0KapVsQg6Hgsu_ePn_-nzx7vccwcOq6dEYrcqaHK0ZJRHhlktR6NIfyfCWhAcqrSgDw1n8dIsqNW4arl3kLkBJlHQMylwoNhf?key=edBqZqn7yehD8oQ2p_qxy-Ie\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>\u0417\u0410\u041a\u041b\u042e\u0427\u0415\u041d\u0418\u0415.<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f <strong>Composer Cursor AI <\/strong>\u043d\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0448\u0430\u0433\u043e\u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u043a\u0438 \u0438 \u043f\u043e\u043a\u0430\u0437\u0430 <a href=\"https:\/\/api.flickr.com\/services\/feeds\/photos_public.gne?format=json&amp;nojsoncallback=1\">\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0441 Flickr.com<\/a>, \u043d\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0432 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0438 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u0447\u043a\u0438 \u043a\u043e\u0434\u0430 \u043d\u0430 SwiftUI. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0447\u0435\u043d\u044c \u043a\u043e\u043c\u043f\u0430\u043a\u0442\u043d\u044b\u0439 \u0438 \u0445\u043e\u0440\u043e\u0448\u043e \u0447\u0438\u0442\u0430\u0435\u043c\u044b\u0439 \u043a\u043e\u0434, \u042d\u0442\u043e \u043d\u0435 \u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c Swift \u0438 SwiftUI, \u043d\u0430\u043e\u0431\u043e\u0440\u043e\u0442, \u0432\u0441\u0435 \u043d\u0430\u0448\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0438 (Prompts) \u0431\u044b\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u043d\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0430\u043d\u0430\u043b\u0438\u0437\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0437\u043d\u0430\u043d\u0438\u0439 Swift \u0438 SwiftUI. <br>\u041d\u043e \u043a\u043e\u0434 \u0433\u0435\u043d\u0435\u0440\u0438\u043b\u0441\u044f \u0432 <strong>Cursor AI<\/strong> \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b\u0441\u044f \u0432 <strong>Xcode <\/strong>\u0442\u0430\u043a \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e, \u0447\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u043b\u043e\u0441\u044c \u0432\u0441\u0435\u0433\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0438\u043d\u0443\u0442, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044d\u0442\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442\u0441\u044f \u043a\u0432\u0430\u043b\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0434\u0441\u043a\u0430\u0437\u043a\u0430\u043c\u0438 (Prompts),&nbsp; \u043d\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0442 \u043d\u0435\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u043e.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f <strong>PhotomaniaCursor<\/strong> \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u0430 <a href=\"https:\/\/github.com\/BestKora\/PhotomaniaCursor\" title=\"\">Github.com<\/a>. <\/span><\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/PhotomaniaCursorDemo.gif\"><img loading=\"lazy\" decoding=\"async\" width=\"516\" height=\"520\" src=\"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/PhotomaniaCursorDemo.gif\" alt=\"\" class=\"wp-image-16310\"\/><\/a><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">P.S. <\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u0441\u043d\u043e\u0432\u043e\u0439 \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u0441\u0442\u043e\u0432 \u0441\u0442\u0430\u043b\u043e \u0432\u0438\u0434\u0435\u043e <a href=\"https:\/\/www.youtube.com\/watch?v=oe3Jn6FRoII\"><strong>\u201dI Made an iOS App in MINUTES with This AI Tool!\u201d<\/strong><\/a> (\u201c\u042f \u0441\u0434\u0435\u043b\u0430\u043b \u044d\u0442\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043d\u0443\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u0442\u043e\u0433\u043e \u0418\u0418 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u201d).<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u042f \u043d\u0435 \u0432\u0435\u0440\u044e, \u0447\u0442\u043e \u0431\u0435\u0437 \u0437\u043d\u0430\u043d\u0438\u044f Swift \u0438 SwiftUI \u0438\u043b\u0438 UIKit \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0435 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043d\u043e \u043c\u043d\u0435 \u0431\u044b\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u043a\u0430\u043a\u0438\u0435 \u201c\u0444\u0438\u0448\u043a\u0438\u201d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u0430\u0432\u0442\u043e\u0440 \u0432\u043d\u0443\u0442\u0440\u0438 Cursor AI, \u0438\u0445 \u0442\u0430\u043c \u043c\u043d\u043e\u0433\u043e: Chat, Composer,<strong> <\/strong>\u2318K<strong> <\/strong>, Tab, Editor \u0438 Terminal.<\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><span style=\"font-weight: 400;\">\u041e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u0430\u0432\u0442\u043e\u0440 \u044d\u0442\u043e\u0433\u043e \u0432\u0438\u0434\u0435\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e <strong>Cursor AI Composer<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0446\u0435\u043b\u044b\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u043c. \u042d\u0442\u043e \u0437\u0430\u043c\u0435\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0435\u0433\u043e \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0438\u043b\u0438 \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0435\u0433\u043e \u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442 <a href=\"https:\/\/docs.google.com\/document\/d\/1alV9O5tULcsHl3VSsBQg6yrEzY_DOHDwiPyzppAnCsI\/edit?usp=drive_link\">\u0437\u0434\u0435\u0441\u044c<\/a>. A \u0442\u0430\u043a\u0436\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u201c\u041f\u0440\u0438\u043b\u0438\u0432\u044b\u201d <strong>Tide Times<\/strong> \u043d\u0430<a href=\"https:\/\/github.com\/BestKora\/Tile-Times\"> Github<\/a>, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0441\u043e\u0437\u0434\u0430\u043b\u0430, \u0441\u043b\u0435\u0434\u0443\u044f \u044d\u0442\u043e\u043c\u0443 \u0432\u0438\u0434\u0435\u043e. \u041d\u043e \u0434\u043e\u0441\u0442\u0443\u043f \u043a <a href=\"https:\/\/www.worldtides.info\/\">\u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u201c\u043f\u0440\u0438\u043b\u0438\u0432\u0430\u0445\u201d<\/a> \u0442\u0440\u0435\u0431\u0443\u0435\u0442 API key \u0438 \u043f\u0435\u0440\u0432\u044b\u0435 100 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0432\u044b \u0434\u0435\u043b\u0430\u0435\u0442\u0435 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e, a \u0437\u0430\u0442\u0435\u043c \u043d\u0443\u0436\u043d\u0430 \u043f\u043b\u0430\u0442\u043d\u0430\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u043a\u0430.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 &hellip; <a href=\"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/\">\u0427\u0438\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u0435\u0435 <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60,114,14,54,108],"tags":[115,31,56,116],"class_list":["post-16279","post","type-post","status-publish","format-standard","hentry","category-combine","category-cursor-ai","category-swift","category-swiftui","category-108","tag-cursor-ai","tag-swift","tag-swiftui","tag-116"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.8 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,\" \/>\n\t<meta name=\"robots\" content=\"max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n\t<meta name=\"author\" content=\"tatiana.kornilova@gmail.com\"\/>\n\t<meta name=\"keywords\" content=\"cursor ai,ios application,xcode + cursorai,flickr.com,\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439,developer ios app,swift\" \/>\n\t<link rel=\"canonical\" href=\"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.8\" \/>\n\t\t<meta property=\"og:locale\" content=\"ru_RU\" \/>\n\t\t<meta property=\"og:site_name\" content=\"\u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. | \u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442 \u043b\u0435\u043a\u0446\u0438\u0439 \u0421\u0442\u044d\u043d\u0444\u043e\u0440\u0434\u0441\u043a\u043e\u0433\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0430 &quot; \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439&quot; 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 , 2023,  2024,  2025  \u0438 2026 \u0433\u0433., \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0435\u0439 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a \u043d\u043e\u0432\u044b\u043c \u0432\u0435\u0440\u0441\u0438\u044f\u043c Swift, Objective-C \u0438 iOS.\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2024-12-01T18:24:23+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2024-12-03T08:38:46+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary\" \/>\n\t\t<meta name=\"twitter:title\" content=\"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.\" \/>\n\t\t<meta name=\"twitter:description\" content=\"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#article\",\"name\":\"Cursor AI \\u0432 iOS \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435. \\u041f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0435 \\u00ab\\u0424\\u043e\\u0442\\u043e \\u0441 Flickr.com\\u00bb. \\u0427\\u0430\\u0441\\u0442\\u044c 2. | \\u041e\\u0431\\u0443\\u0447\\u0430\\u044e\\u0449\\u0438\\u0439 \\u043a\\u0443\\u0440\\u0441 \\u043f\\u043e \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435 iOS+Swift \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0439.\",\"headline\":\"Cursor AI \\u0432 iOS \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435. \\u041f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0435 &#171;\\u0424\\u043e\\u0442\\u043e \\u0441 Flickr.com&#187;. \\u0427\\u0430\\u0441\\u0442\\u044c 2.\",\"author\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/author\\\/tatiana-lornilovagmail-com\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/#person\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/wp-content\\\/uploads\\\/2024\\\/12\\\/Screenshot-2024-12-01-at-13.40.25.png\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#articleImage\",\"width\":2344,\"height\":1478},\"datePublished\":\"2024-12-01T18:24:23+00:00\",\"dateModified\":\"2024-12-03T08:38:46+00:00\",\"inLanguage\":\"ru-RU\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#webpage\"},\"articleSection\":\"Combine, Cursor AI, Swift, SwiftUI, \\u0418\\u0418 \\u0430\\u043b\\u0433\\u043e\\u0440\\u0438\\u0442\\u043c\\u044b, Cursor AI, Swift, SwiftUI, \\u0418\\u0441\\u043a\\u0443\\u0441\\u0441\\u0442\\u0432\\u0435\\u043d\\u043d\\u044b\\u0439 \\u0438\\u043d\\u0442\\u0435\\u043b\\u043b\\u0435\\u043a\\u0442\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/category\\\/swift\\\/#listItem\",\"name\":\"Swift\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/category\\\/swift\\\/#listItem\",\"position\":2,\"name\":\"Swift\",\"item\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/category\\\/swift\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#listItem\",\"name\":\"Cursor AI \\u0432 iOS \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435. \\u041f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0435 &#171;\\u0424\\u043e\\u0442\\u043e \\u0441 Flickr.com&#187;. \\u0427\\u0430\\u0441\\u0442\\u044c 2.\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#listItem\",\"position\":3,\"name\":\"Cursor AI \\u0432 iOS \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435. \\u041f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0435 &#171;\\u0424\\u043e\\u0442\\u043e \\u0441 Flickr.com&#187;. \\u0427\\u0430\\u0441\\u0442\\u044c 2.\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/category\\\/swift\\\/#listItem\",\"name\":\"Swift\"}}]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/#person\",\"name\":\"tatiana.kornilova@gmail.com\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#personImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/33ccc19059014d8a7849c3621afa2b66a5f3e50ac7291c91c30ff35df5747628?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"tatiana.kornilova@gmail.com\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/author\\\/tatiana-lornilovagmail-com\\\/#author\",\"url\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/author\\\/tatiana-lornilovagmail-com\\\/\",\"name\":\"tatiana.kornilova@gmail.com\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/33ccc19059014d8a7849c3621afa2b66a5f3e50ac7291c91c30ff35df5747628?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"tatiana.kornilova@gmail.com\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#webpage\",\"url\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/\",\"name\":\"Cursor AI \\u0432 iOS \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435. \\u041f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0435 \\u00ab\\u0424\\u043e\\u0442\\u043e \\u0441 Flickr.com\\u00bb. \\u0427\\u0430\\u0441\\u0442\\u044c 2. | \\u041e\\u0431\\u0443\\u0447\\u0430\\u044e\\u0449\\u0438\\u0439 \\u043a\\u0443\\u0440\\u0441 \\u043f\\u043e \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435 iOS+Swift \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0439.\",\"description\":\"\\u041c\\u044b \\u0438\\u0441\\u0441\\u043b\\u0435\\u0434\\u0443\\u0435\\u043c \\u043a\\u0430\\u043a \\u0440\\u0430\\u0431\\u043e\\u0442\\u0430\\u0435\\u0442 Cursor AI \\u043d\\u0430 \\u043f\\u0440\\u0438\\u043c\\u0435\\u0440\\u0435 \\u0441\\u043e\\u0437\\u0434\\u0430\\u043d\\u0438\\u044f iOS \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u044f \\u0441 \\u0432\\u044b\\u0431\\u043e\\u0440\\u043a\\u043e\\u0439 \\u0434\\u0430\\u043d\\u043d\\u044b\\u0445 \\u0441 \\u0440\\u0435\\u0441\\u0443\\u0440\\u0441\\u0430 \\u043f\\u0443\\u0431\\u043b\\u0438\\u0447\\u043d\\u044b\\u0445 \\u0444\\u043e\\u0442\\u043e\\u0433\\u0440\\u0430\\u0444\\u0438\\u0439 \\u043d\\u0430 Flickr.com.UI \\u044d\\u0442\\u043e\\u0433\\u043e iOS \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u044f \\u043f\\u0440\\u0435\\u0434\\u0441\\u0442\\u0430\\u0432\\u043b\\u044f\\u0435\\u0442 \\u0441\\u043e\\u0431\\u043e\\u0439 \\u0441\\u0442\\u0440\\u043e\\u043a\\u0443 \\u043f\\u043e\\u0438\\u0441\\u043a\\u0430 \\u0432\\u0432\\u0435\\u0440\\u0445\\u0443 \\u0438 \\u0441\\u0435\\u0442\\u043a\\u0443 Grid \\u043f\\u043e\\u0434 \\u043d\\u0435\\u0439 \\u0434\\u043b\\u044f \\u043e\\u0442\\u043e\\u0431\\u0440\\u0430\\u0436\\u0435\\u043d\\u0438\\u044f \\u043c\\u0438\\u043d\\u0438\\u0430\\u0442\\u044e\\u0440 \\u044d\\u0442\\u0438\\u0445 \\u0444\\u043e\\u0442\\u043e\\u0433\\u0440\\u0430\\u0444\\u0438\\u0439. \\u0412\\u044b \\u043c\\u043e\\u0436\\u0435\\u0442\\u0435 \\u043a\\u043b\\u0438\\u043a\\u043d\\u0443\\u0442\\u044c \\u043d\\u0430 \\u043b\\u044e\\u0431\\u0443\\u044e \\u0438\\u0437 \\u0444\\u043e\\u0442\\u043e\\u0433\\u0440\\u0430\\u0444\\u0438\\u0439 \\u0438 \\u043f\\u043e\\u043b\\u0443\\u0447\\u0438\\u0442\\u044c \\u043f\\u043e\\u0434\\u0440\\u043e\\u0431\\u043d\\u0443\\u044e \\u0438\\u043d\\u0444\\u043e\\u0440\\u043c\\u0430\\u0446\\u0438\\u044e \\u043e \\u043d\\u0435\\u0439: \\u041d\\u0430\\u0447\\u0430\\u043b\\u044c\\u043d\\u043e\\u0435 \\u0440\\u0435\\u0448\\u0435\\u043d\\u0438\\u0435 \\u044d\\u0442\\u043e\\u0439 \\u0437\\u0430\\u0434\\u0430\\u0447\\u0438,\",\"inLanguage\":\"ru-RU\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/author\\\/tatiana-lornilovagmail-com\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/author\\\/tatiana-lornilovagmail-com\\\/#author\"},\"datePublished\":\"2024-12-01T18:24:23+00:00\",\"dateModified\":\"2024-12-03T08:38:46+00:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/#website\",\"url\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/\",\"name\":\"\\u041e\\u0431\\u0443\\u0447\\u0430\\u044e\\u0449\\u0438\\u0439 \\u043a\\u0443\\u0440\\u0441 \\u043f\\u043e \\u0440\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0435 iOS+Swift \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0439.\",\"description\":\"\\u0420\\u0443\\u0441\\u0441\\u043a\\u0438\\u0439 \\u043d\\u0435\\u0430\\u0432\\u0442\\u043e\\u0440\\u0438\\u0437\\u043e\\u0432\\u0430\\u043d\\u043d\\u044b\\u0439 \\u043a\\u043e\\u043d\\u0441\\u043f\\u0435\\u043a\\u0442 \\u043b\\u0435\\u043a\\u0446\\u0438\\u0439 \\u0421\\u0442\\u044d\\u043d\\u0444\\u043e\\u0440\\u0434\\u0441\\u043a\\u043e\\u0433\\u043e \\u0443\\u043d\\u0438\\u0432\\u0435\\u0440\\u0441\\u0438\\u0442\\u0435\\u0442\\u0430 \\\" \\u0420\\u0430\\u0437\\u0440\\u0430\\u0431\\u043e\\u0442\\u043a\\u0430 iOS \\u043f\\u0440\\u0438\\u043b\\u043e\\u0436\\u0435\\u043d\\u0438\\u0439\\\" 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 , 2023,  2024,  2025  \\u0438 2026 \\u0433\\u0433., \\u0441\\u043e\\u043f\\u0440\\u043e\\u0432\\u043e\\u0436\\u0434\\u0430\\u0435\\u043c\\u044b\\u0439 \\u0440\\u0435\\u0448\\u0435\\u043d\\u0438\\u044f\\u043c\\u0438 \\u0437\\u0430\\u0434\\u0430\\u043d\\u0438\\u0439 \\u0438 \\u0434\\u043e\\u043f\\u043e\\u043b\\u043d\\u0435\\u043d\\u0438\\u044f\\u043c\\u0438, \\u0441\\u0432\\u044f\\u0437\\u0430\\u043d\\u043d\\u044b\\u043c\\u0438 \\u0441 \\u0430\\u0434\\u0430\\u043f\\u0442\\u0430\\u0446\\u0438\\u0435\\u0439 \\u043a\\u0443\\u0440\\u0441\\u043e\\u0432 \\u043a \\u043d\\u043e\\u0432\\u044b\\u043c \\u0432\\u0435\\u0440\\u0441\\u0438\\u044f\\u043c Swift, Objective-C \\u0438 iOS.\",\"inLanguage\":\"ru-RU\",\"publisher\":{\"@id\":\"https:\\\/\\\/bestkora.com\\\/IosDeveloper\\\/#person\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","description":"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,","canonical_url":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/","robots":"max-snippet:-1, max-image-preview:large, max-video-preview:-1","keywords":"cursor ai,ios application,xcode + cursorai,flickr.com,\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439,developer ios app,swift","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#article","name":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","headline":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 2.","author":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/author\/tatiana-lornilovagmail-com\/#author"},"publisher":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/#person"},"image":{"@type":"ImageObject","url":"https:\/\/bestkora.com\/IosDeveloper\/wp-content\/uploads\/2024\/12\/Screenshot-2024-12-01-at-13.40.25.png","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#articleImage","width":2344,"height":1478},"datePublished":"2024-12-01T18:24:23+00:00","dateModified":"2024-12-03T08:38:46+00:00","inLanguage":"ru-RU","mainEntityOfPage":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#webpage"},"isPartOf":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#webpage"},"articleSection":"Combine, Cursor AI, Swift, SwiftUI, \u0418\u0418 \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u044b, Cursor AI, Swift, SwiftUI, \u0418\u0441\u043a\u0443\u0441\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442"},{"@type":"BreadcrumbList","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper#listItem","position":1,"name":"Home","item":"https:\/\/bestkora.com\/IosDeveloper","nextItem":{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/#listItem","name":"Swift"}},{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/#listItem","position":2,"name":"Swift","item":"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/","nextItem":{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#listItem","name":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 2."},"previousItem":{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#listItem","position":3,"name":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 2.","previousItem":{"@type":"ListItem","@id":"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/#listItem","name":"Swift"}}]},{"@type":"Person","@id":"https:\/\/bestkora.com\/IosDeveloper\/#person","name":"tatiana.kornilova@gmail.com","image":{"@type":"ImageObject","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#personImage","url":"https:\/\/secure.gravatar.com\/avatar\/33ccc19059014d8a7849c3621afa2b66a5f3e50ac7291c91c30ff35df5747628?s=96&d=mm&r=g","width":96,"height":96,"caption":"tatiana.kornilova@gmail.com"}},{"@type":"Person","@id":"https:\/\/bestkora.com\/IosDeveloper\/author\/tatiana-lornilovagmail-com\/#author","url":"https:\/\/bestkora.com\/IosDeveloper\/author\/tatiana-lornilovagmail-com\/","name":"tatiana.kornilova@gmail.com","image":{"@type":"ImageObject","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/33ccc19059014d8a7849c3621afa2b66a5f3e50ac7291c91c30ff35df5747628?s=96&d=mm&r=g","width":96,"height":96,"caption":"tatiana.kornilova@gmail.com"}},{"@type":"WebPage","@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#webpage","url":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/","name":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","description":"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,","inLanguage":"ru-RU","isPartOf":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/#website"},"breadcrumb":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/#breadcrumblist"},"author":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/author\/tatiana-lornilovagmail-com\/#author"},"creator":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/author\/tatiana-lornilovagmail-com\/#author"},"datePublished":"2024-12-01T18:24:23+00:00","dateModified":"2024-12-03T08:38:46+00:00"},{"@type":"WebSite","@id":"https:\/\/bestkora.com\/IosDeveloper\/#website","url":"https:\/\/bestkora.com\/IosDeveloper\/","name":"\u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","description":"\u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442 \u043b\u0435\u043a\u0446\u0438\u0439 \u0421\u0442\u044d\u043d\u0444\u043e\u0440\u0434\u0441\u043a\u043e\u0433\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0430 \" \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439\" 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 , 2023,  2024,  2025  \u0438 2026 \u0433\u0433., \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0435\u0439 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a \u043d\u043e\u0432\u044b\u043c \u0432\u0435\u0440\u0441\u0438\u044f\u043c Swift, Objective-C \u0438 iOS.","inLanguage":"ru-RU","publisher":{"@id":"https:\/\/bestkora.com\/IosDeveloper\/#person"}}]},"og:locale":"ru_RU","og:site_name":"\u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. | \u0420\u0443\u0441\u0441\u043a\u0438\u0439 \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043d\u0441\u043f\u0435\u043a\u0442 \u043b\u0435\u043a\u0446\u0438\u0439 \u0421\u0442\u044d\u043d\u0444\u043e\u0440\u0434\u0441\u043a\u043e\u0433\u043e \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0438\u0442\u0435\u0442\u0430 &quot; \u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439&quot; 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021 , 2023,  2024,  2025  \u0438 2026 \u0433\u0433., \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0435\u0448\u0435\u043d\u0438\u044f\u043c\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u0439 \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f\u043c\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c\u0438 \u0441 \u0430\u0434\u0430\u043f\u0442\u0430\u0446\u0438\u0435\u0439 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a \u043d\u043e\u0432\u044b\u043c \u0432\u0435\u0440\u0441\u0438\u044f\u043c Swift, Objective-C \u0438 iOS.","og:type":"article","og:title":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","og:description":"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,","og:url":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/","article:published_time":"2024-12-01T18:24:23+00:00","article:modified_time":"2024-12-03T08:38:46+00:00","twitter:card":"summary","twitter:title":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2. | \u041e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0439 \u043a\u0443\u0440\u0441 \u043f\u043e \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435 iOS+Swift \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.","twitter:description":"\u041c\u044b \u0438\u0441\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 Cursor AI \u043d\u0430 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441 \u0432\u044b\u0431\u043e\u0440\u043a\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0435\u0441\u0443\u0440\u0441\u0430 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u043d\u0430 Flickr.com.UI \u044d\u0442\u043e\u0433\u043e iOS \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0431\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u0432\u0435\u0440\u0445\u0443 \u0438 \u0441\u0435\u0442\u043a\u0443 Grid \u043f\u043e\u0434 \u043d\u0435\u0439 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u0438\u043d\u0438\u0430\u0442\u044e\u0440 \u044d\u0442\u0438\u0445 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439. \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043a\u043b\u0438\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u0443\u044e \u0438\u0437 \u0444\u043e\u0442\u043e\u0433\u0440\u0430\u0444\u0438\u0439 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043d\u0435\u0439: \u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0438,"},"aioseo_meta_data":{"post_id":"16279","title":null,"description":null,"keywords":[{"label":"Cursor AI","value":"Cursor AI"},{"label":"iOS application","value":"iOS application"},{"label":"Xcode + CursorAI","value":"Xcode + CursorAI"},{"label":"Flickr.com","value":"Flickr.com"},{"label":"\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439","value":"\u0420\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439"},{"label":"Developer iOS app","value":"Developer iOS app"},{"label":"Swift","value":"Swift"}],"keyphrases":{"focus":{"keyphrase":"","score":0,"analysis":{"keyphraseInTitle":{"score":0,"maxScore":9,"error":1}}},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"Article","isEnabled":true},"graphs":[]},"schema_type":"default","schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"breadcrumb_settings":null,"limit_modified_date":false,"ai":null,"created":"2024-12-01 18:23:38","updated":"2026-02-22 20:12:55","seo_analyzer_scan_date":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/bestkora.com\/IosDeveloper\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/\" title=\"Swift\">Swift<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">&raquo;<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tCursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u00ab\u0424\u043e\u0442\u043e \u0441 Flickr.com\u00bb. \u0427\u0430\u0441\u0442\u044c 2.\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/bestkora.com\/IosDeveloper"},{"label":"Swift","link":"https:\/\/bestkora.com\/IosDeveloper\/category\/swift\/"},{"label":"Cursor AI \u0432 iOS \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435. \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 &#171;\u0424\u043e\u0442\u043e \u0441 Flickr.com&#187;. \u0427\u0430\u0441\u0442\u044c 2.","link":"https:\/\/bestkora.com\/IosDeveloper\/cursor-ai-%d0%b2-ios-%d1%80%d0%b0%d0%b7%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b5-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d1%84%d0%be%d1%82%d0%be-%d1%81-flickr-com-%d1%87\/"}],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/posts\/16279","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/comments?post=16279"}],"version-history":[{"count":4,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/posts\/16279\/revisions"}],"predecessor-version":[{"id":16321,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/posts\/16279\/revisions\/16321"}],"wp:attachment":[{"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/media?parent=16279"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/categories?post=16279"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bestkora.com\/IosDeveloper\/wp-json\/wp\/v2\/tags?post=16279"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}