{"id":38313,"date":"2023-01-27T15:58:46","date_gmt":"2023-01-27T20:58:46","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=38313"},"modified":"2023-01-31T09:41:19","modified_gmt":"2023-01-31T14:41:19","slug":"swiftui-in-timing-app","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2023\/01\/27\/swiftui-in-timing-app\/","title":{"rendered":"SwiftUI in timing.is App"},"content":{"rendered":"<p><a href=\"https:\/\/blog.timing.is\/swiftui-production-experience-problems-solutions-performance-tips\/\">Bardi Golriz<\/a>:<\/p>\n<blockquote cite=\"https:\/\/blog.timing.is\/swiftui-production-experience-problems-solutions-performance-tips\/\">\n<p>It took a few hours to fall in love with SwiftUI. So much so that we instantly decided to abandon a cross-platform codebase and go fully native on iOS. [&#8230;] Towards the latter stages of development, we even re-considered our decision to go with it. At the end, we didn&rsquo;t drop it for a couple of reasons. We were too deep into the process. Being a bootstrapped operation that was already severely behind schedule, we couldn&rsquo;t afford to restart. But this wasn&rsquo;t why. Despite the regular friction, we still <em>loved<\/em> it. Because like any commitment, you must let the majority rule. It was <em>fun<\/em> at least 51% of the time. But let&rsquo;s talk about the &lt;= 49% that wasn&rsquo;t.<\/p>\n<p>[&#8230;]<\/p>\n<p>[<code>ScrollView<\/code>] was the control that we wrestled with the most. An infinite scroll is expected in a calendar app. Executing this was relatively straightforward, but only moving forward in time. Because trying to load items on demand scrolling up resulted in a noticeable jitter. <a href=\"https:\/\/stackoverflow.com\/questions\/65614647\/infinite-vertical-scrollview-both-ways-add-items-dynamically-at-top-bottom-tha\">I asked on StackOverflow, and 2k views since, it&rsquo;s apparent there&rsquo;s no native approach that works<\/a>. I actually raised this in a WWDC lab with a SwiftUI engineer last year, and their recommendation was to 1) create a <code>LazyVStack<\/code> with a ridiculously large data set in both directions and 2) scroll to today <code>onAppear<\/code>. A creative workaround, except unfortunately <code>scrollTo<\/code> behaves unreliably inside a <code>LazyVStack<\/code>. It would usually not even come close to the intended target, occassionally missed it by a little, and rarely correctly.<\/p>\n<p>[&#8230;]<\/p>\n<p>Views will refresh unnecessarily. And in a calendar with an infinite scroll, this will lead to noticeable slowdowns. You&rsquo;re always literally one <code>@Published<\/code> property away from triggering one.<\/p>\n<p>[&#8230;]<\/p>\n<p>Finally, in case I forget again, remember an <code>@EnvironmentObject<\/code> will trigger a view update even if the view has no reference to any of its properties. An inexpensive way to determine unnecessary redraws is by setting the background colour of a view to <code>Color.random<\/code>, <a href=\"https:\/\/twitter.com\/steipete\/status\/1379483193708052480?lang=en\">a clever trick<\/a> by <a href=\"https:\/\/twitter.com\/steipete\">Peter Steinberger<\/a>.<\/p>\n<p>[&#8230;]<\/p>\n<p>when you are editing an entry, we want the title field&rsquo;s cursor position to be at the beginning. But, alas, not possible.<\/p>\n<\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/04\/19\/swiftui-performance-tips\/\">SwiftUI Performance Tips<\/a><\/li>\n<\/ul>\n\n<p id=\"swiftui-in-timing-app-update-2023-01-30\">Update (2023-01-30): See also: <a href=\"https:\/\/news.ycombinator.com\/item?id=34556370\">Hacker News<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>Bardi Golriz: It took a few hours to fall in love with SwiftUI. So much so that we instantly decided to abandon a cross-platform codebase and go fully native on iOS. [&#8230;] Towards the latter stages of development, we even re-considered our decision to go with it. At the end, we didn&rsquo;t drop it for [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2023-01-27T20:58:49Z","apple_news_api_id":"9423db5a-a86a-4e34-99bb-11b4d862df6a","apple_news_api_modified_at":"2023-01-31T14:41:23Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/AlCPbWqhqTjSZuxG02GLfag","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[31,2185,26,71,901,1812,2334],"class_list":["post-38313","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-ios","tag-ios-16","tag-iosapp","tag-programming","tag-swift-programming-language","tag-swiftui","tag-timing-is"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/38313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=38313"}],"version-history":[{"count":3,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/38313\/revisions"}],"predecessor-version":[{"id":38332,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/38313\/revisions\/38332"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=38313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=38313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=38313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}