{"id":36918,"date":"2022-09-04T11:34:18","date_gmt":"2022-09-04T15:34:18","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=36918"},"modified":"2022-09-04T11:34:18","modified_gmt":"2022-09-04T15:34:18","slug":"the-swiftui-render-loop","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2022\/09\/04\/the-swiftui-render-loop\/","title":{"rendered":"The SwiftUI Render Loop"},"content":{"rendered":"<p><a href=\"https:\/\/rensbr.eu\/blog\/swiftui-render-loop\/\">Rens Breur<\/a>:<\/p>\n<blockquote cite=\"https:\/\/rensbr.eu\/blog\/swiftui-render-loop\/\"><p>We will first look into a number of examples of such cases where it is useful to know how the SwiftUI render loop works. Then we will explore the render loop in more detail and ask questions such as: when exactly is the body of a SwiftUI view evaluated. Not &ldquo;when&rdquo; as in under what circumstances, but as in: at which point in time? Is a view always drawn on screen immediately after a body is evaluated? How related are body evaluation and screen rendering even? We sometimes use the word &ldquo;render&rdquo; for evaluating a body of a view, does that even make sense?<\/p>\n<p>[&#8230;]<\/p>\n<p>When it is not doing anything, a SwiftUI app will have an idle <code>CFRunLoop<\/code>. It will wait for events from an input source such as touches, network events, timers or a display refresh. In response to a touch, SwiftUI may call a Button's action handler. If we put a breakpoint inside that action handler, we will see <code>__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__<\/code> somewhere in the stack trace. This is because touch events are delivered from a type 0 input source.<\/p>\n<p>In response to an action that we perform in response to an event from in input source, we might update some <code>@State<\/code> variable in a view or call a function on an <code>@ObservedObject<\/code> that in turns causes its <code>objectWillChange<\/code> publisher to fire. In this case, the SwiftUI view is invalidated. This means that its body needs to be re-evaluated, but it would be inefficient to do that immediately. Maybe the same function that changed a <code>@State<\/code> variable will change another <code>@State<\/code> variable. Therefore, the body evaluation is scheduled to be executed later.<\/p>\n<\/blockquote>","protected":false},"excerpt":{"rendered":"<p>Rens Breur: We will first look into a number of examples of such cases where it is useful to know how the SwiftUI render loop works. Then we will explore the render loop in more detail and ask questions such as: when exactly is the body of a SwiftUI view evaluated. Not &ldquo;when&rdquo; as in [&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-04T15:34:20Z","apple_news_api_id":"2bfe2956-a670-4975-83e7-6b6cde181613","apple_news_api_modified_at":"2022-09-04T15:34:20Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AK_4pVqZwSXWD52ts3hgWEw","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":[689,31,2078,30,2077,71,1812],"class_list":["post-36918","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-core-animation","tag-ios","tag-ios-15","tag-mac","tag-macos-12","tag-programming","tag-swiftui"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36918","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=36918"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36918\/revisions"}],"predecessor-version":[{"id":36919,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/36918\/revisions\/36919"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=36918"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=36918"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=36918"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}