{"id":46235,"date":"2024-12-20T16:53:05","date_gmt":"2024-12-20T21:53:05","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=46235"},"modified":"2024-12-20T16:53:05","modified_gmt":"2024-12-20T21:53:05","slug":"swift-concurrency-in-real-apps","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/12\/20\/swift-concurrency-in-real-apps\/","title":{"rendered":"Swift Concurrency in Real Apps"},"content":{"rendered":"<p><a href=\"https:\/\/forums.swift.org\/t\/swift-concurrency-in-real-apps\/73790\">Bryan Jones<\/a>:<\/p>\n<blockquote cite=\"https:\/\/forums.swift.org\/t\/swift-concurrency-in-real-apps\/73790\">\n<p>Consider this code, wherein we create a custom <code>NSTableColumn<\/code> that uses an image instead of a <code>String<\/code> as its header.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/github.com\/swiftlang\/swift\/pull\/75749\">Holly Borla<\/a> posted a fix that special-cases <code>NSObject.init()<\/code>:<\/p>\n<blockquote cite=\"https:\/\/github.com\/swiftlang\/swift\/pull\/75749\"><p>Now, overriding <code>NSObject.init()<\/code> within a <code>@MainActor<\/code>-isolated type is difficult-to-impossible, especially if you need to call an initializer from an intermediate superclass that is also <code>@MainActor<\/code>-isolated. Standard opt-out tools like <code>MainActor.assumeIsolated<\/code> cannot be applied to things like stored property initialization and <code>super.init()<\/code>, making the issue extremely difficult to work around. This is a major usability regression for programs that interoperate with Objective-C and make heavy use of <code>@MainActor<\/code>-isolated types.<\/p><p>[&#8230;]<\/p><p>I can&rsquo;t reproduce a failure by overriding <code>viewDidAppear<\/code> in a <code>@MainActor<\/code>-isolated subclass of <code>UIViewController<\/code>, but if this is happening for methods that are marked as <code>nonisolated<\/code> or otherwise aren&rsquo;t annotated with <code>@MainActor<\/code>, then that is a deliberate result of my original change. Overriding superclass methods and changing isolation does risk a data-race, which is why I made the original change. If you believe the superclass method is incorrectly annotated, that is a framework problem that you should report via Apple Feedback Assistant.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/www.massicotte.org\/awakefromnib\">Matt Massicotte<\/a> (<a href=\"https:\/\/mastodon.social\/@mattiem\/113091246217791363\">Mastodon<\/a>):<\/p>\n<blockquote cite=\"https:\/\/www.massicotte.org\/awakefromnib\"><p>(As it turns out, <code>UINib<\/code> actually <strong>is<\/strong> <code>MainActor<\/code>-isolated, while <code>NSNib<\/code> is not. There&rsquo;s one person out there somewhere maintaining a cross-platform app that uses nibs and this is going to make their life hell.)<\/p><p>The <em>whole point<\/em> of Nibs is to serialize <strong>UI<\/strong> components. That&rsquo;s literally the only reason it exists. And that doesn&rsquo;t work in Swift 6[&#8230;]<\/p><p>[&#8230;]<\/p><p>The compiler must honor the API contract of <code>awakeFromNib<\/code>. The framework maintainers have decided to not apply any isolation. The types and APIs aren&rsquo;t able to fully describe the concurrent behavior, but the developer knows what&rsquo;s actually going to happen at runtime.<\/p><p>This is a special-case of a very common issue and is <strong>exactly<\/strong> why dynamic isolation exists.<\/p>\n<p>[&#8230;]<\/p>\n<p>Some APIs, even really important ones that you use every day, just won&rsquo;t ever work well with Swift concurrency. I&rsquo;m certain some language changes could make things a little easier here and there. But, largely, these problematic APIs are going to be deprecated and replaced. It&rsquo;s happening with <a href=\"https:\/\/forums.swift.org\/t\/pitch-concurrency-safe-notifications\/73713\">Notifications<\/a> right now.<\/p><\/blockquote>\n\n<p><a href=\"https:\/\/mastodon.cloud\/@drewmccormack\/113091381508202882\">Drew McCormack<\/a>:<\/p>\n<blockquote cite=\"https:\/\/mastodon.cloud\/@drewmccormack\/113091381508202882\">\n<p>Pretty sure there are use cases for background threads. I think code for printing uses <code>NSView<\/code>, and usually involves a background op.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/layer8.space\/@teilweise\/113090172158934289\">Der Teilweise<\/a>:<\/p>\n<blockquote cite=\"https:\/\/layer8.space\/@teilweise\/113090172158934289\"><p>TIL: <code>awakeFromNib()<\/code> can be called more than once when objects are loaded from XIBs.<\/p><p>IDK, maybe that is something that should be mentioned in <a href=\"https:\/\/developer.apple.com\/documentation\/objectivec\/nsobject\/1402907-awakefromnib\">the documentation<\/a>.<\/p><\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/12\/19\/swiftuwhy\/\">SwiftUWhy<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/11\/26\/watch-out-for-counterintuitive-implicit-actor-isolation\/\">Watch Out for Counterintuitive Implicit Actor-Isolation<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/11\/18\/swift-concurrency-proposal-index\/\">Swift Concurrency Proposal Index<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/11\/07\/problematic-swift-concurrency-patterns\/\">Problematic Swift Concurrency Patterns<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/10\/01\/swift-concurrency-and-objective-c\/\">Swift Concurrency and Objective-C<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/09\/20\/unwanted-swift-concurrency-checking\/\">Unwanted Swift Concurrency Checking<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/09\/19\/swift-6\/\">Swift 6<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Bryan Jones: Consider this code, wherein we create a custom NSTableColumn that uses an image instead of a String as its header. Holly Borla posted a fix that special-cases NSObject.init(): Now, overriding NSObject.init() within a @MainActor-isolated type is difficult-to-impossible, especially if you need to call an initializer from an intermediate superclass that is also @MainActor-isolated. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2024-12-20T21:53:08Z","apple_news_api_id":"8c816f25-3929-4df7-8149-0f4e977d66c9","apple_news_api_modified_at":"2024-12-20T21:53:08Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AjIFvJTkpTfeBSQ9Ol31myQ","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,31,2586,30,2598,54,71,2200,901],"class_list":["post-46235","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-cocoa","tag-ios","tag-ios-18","tag-mac","tag-macos-15-sequoia","tag-objective-c","tag-programming","tag-swift-concurrency","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46235","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=46235"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46235\/revisions"}],"predecessor-version":[{"id":46236,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/46235\/revisions\/46236"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=46235"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=46235"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=46235"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}