{"id":36990,"date":"2022-09-09T15:29:40","date_gmt":"2022-09-09T19:29:40","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=36990"},"modified":"2022-09-10T08:40:15","modified_gmt":"2022-09-10T12:40:15","slug":"using-lazy-properties-for-views","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2022\/09\/09\/using-lazy-properties-for-views\/","title":{"rendered":"Using Lazy Properties for Views"},"content":{"rendered":"<p><a href=\"https:\/\/blog.steveasleep.com\/three-uikit-protips\">Steve Landey<\/a>:<\/p>\n<blockquote cite=\"https:\/\/blog.steveasleep.com\/three-uikit-protips\"><p>There are three patterns I use in most of my UIKit projects that I&rsquo;ve never seen anyone else talk about. I think they help readability a lot, so I&rsquo;m sharing them here[&#8230;]<\/p><p>[&#8230;]<\/p><p>Additionally, it&rsquo;s not great to use force-unwrapped optionals to store anything. But if we use <code>let<\/code> instead, then all views will be created at init time instead of in <code>loadView()<\/code>.<\/p><p>[&#8230;]<\/p><p>We can solve a lot of problems by moving all view creation to the bottom of the file and using <code>lazy var<\/code>.<\/p><\/blockquote>\n<p>The standard guidance is to use implicitly unwrapped optionals to reference views in a view controller, but I think <code>lazy<\/code> works much better. Aside from the delayed loading benefit, <code>lazy<\/code> lets you reference <code>self<\/code>, and thus other properties and helper methods, which you would not ordinarily be able to do from a Swift initializer. (The compiler does protect you from making circular references to other <code>lazy<\/code> properties.) And, because you are providing an initial value, the type of the property can be inferred.<\/p>\n<p>A downside is that there&rsquo;s no <code>lazy let<\/code>, so the compiler can&rsquo;t prevent you from accidentally mutating a variable that you meant to only set once. One way around this is to use a helper object with all the properties as <code>let<\/code> and to store <em>that<\/em> in the <code>var<\/code>, but I think the awkwardness this causes is worse than the problem it solves. Landey suggests:<\/p>\n<blockquote cite=\"https:\/\/blog.steveasleep.com\/three-uikit-protips\"><p>You can at least prevent multiple writes to <code>vars<\/code> at runtime by using this simple property wrapper, which throws an assertion failure in debug builds if you write to the property more than once. It&rsquo;s not as good as a compile-time guarantee, but it does double as inline documentation.<\/p><\/blockquote>\n<p>You can decide whether the protection is worth the noise. I&rsquo;m more interested in something like this to prevent write access to conceptually immutable properties except from tests. However, that is more relevant for model properties, which often use Core Data, and property wrappers don&rsquo;t work with <code>@NSManaged<\/code>. Core Data itself provides a&mdash;more verbose&mdash;out, though: you can still set a property with a <code>private<\/code> setter by key.<\/p>\n<p>Landey then recommends defining the properties at the top of the file and using helper functions at the bottom of the file to actually create the views. Personally, I prefer to see everything related to a property together at its declaration. If you use <code>lazy<\/code> and create the initial value right there, you can set up the whole property without having to repeat its name or type anywhere.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2022\/07\/13\/interfacebuilder-swift\/\">InterfaceBuilder.swift<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2017\/08\/31\/using-lazy-variables-to-work-around-swift-initialization-rules\/\">Using Lazy Variables to Work Around Swift Initialization Rules<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2016\/10\/18\/working-without-a-nib\/\">Working Without a Nib<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Steve Landey: There are three patterns I use in most of my UIKit projects that I&rsquo;ve never seen anyone else talk about. I think they help readability a lot, so I&rsquo;m sharing them here[&#8230;][&#8230;]Additionally, it&rsquo;s not great to use force-unwrapped optionals to store anything. But if we use let instead, then all views will be [&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":"2022-09-09T19:29:50Z","apple_news_api_id":"7f2fdb52-a64d-4d7c-9b09-1163ea57d7d4","apple_news_api_modified_at":"2022-09-10T12:40:18Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAA==","apple_news_api_share_url":"https:\/\/apple.news\/Afy_bUqZNTXybCRFj6lfX1A","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":[69,109,27,31,2078,30,2077,71,901],"class_list":["post-36990","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-cocoa","tag-coredata","tag-craft","tag-ios","tag-ios-15","tag-mac","tag-macos-12","tag-programming","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36990","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=36990"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36990\/revisions"}],"predecessor-version":[{"id":37009,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36990\/revisions\/37009"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=36990"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=36990"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=36990"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}