-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[6.0][Concurrency] Implement a narrow carve out in the isolation override checking for NSObject.init()
.
#75749
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[6.0][Concurrency] Implement a narrow carve out in the isolation override checking for NSObject.init()
.
#75749
Conversation
override checking for `NSObject.init()` 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. This won't admit a runtime data-race safety hole, because dynamic isolation checks will be inserted in the @objc thunks under `DynamicActorIsolation`, and direct calls will enforce `@MainActor` as usual. (cherry picked from commit 0d5e598)
@swift-ci please test |
@hborla I fear this might also be occurring for other overridden methods of UIKit (maybe originally NS-) objects, such as viewWillAppear(), viewDidAppear() etc. |
I can't reproduce a failure by overriding |
Thanks for the response, @hborla
We'd previously assumed that subclassing the (for example) UICollectionViewCell carried @ MainActor with it. Are you saying that we should be marking the new class @ MainActor as well? |
The issue is that awakeFromNib is not a method defined on an AppKit/UIKit controller/view class, but as an extension of NSObject (since you can have an instance of pretty much any class in a xib file). See NSNibLoading.h. Now it would be nice if awakeFromNib was annotated to be a MainActor, since AFAIK that always happens on the main thread (when e.g. accessing the view property of a controller, which has to happen on the main actor). For myself I've "solved" the issue for now by wrapping the code in awakeFromNib into MainActor.assumeIsolated blocks. But that is not a long term solution (or would crash if awakeFromNib is actually called on another thread). |
Yeah. After Holly's response to both this and another line of enquiry regarding the same experience, I came up with the following code snippet, but it smells bad to me - even though its a trick we've been using since the ObjC days. If it works and there is no further changes to UIKit actor annotations, it's crying out for an Xcode macro. I've found other overriden functions being used in our UIKit objects that also have the same issue - eg. isEqual(_). override func awakeFromNib() {
guard Thread.isMainThread else {
DispatchQueue.main.sync(execute: awakeFromNib)
return
}
MainActor.assumeIsolated {
super.awakeFromNib()
doSomething()
}
} We're not even approaching Actors and async functionality yet. Swift 6 almost looks like it would be better starting again from scratch, the same way we did to move our code base from ObjC to Swift 3, 8 years ago. It's that or get stuck using Swift 5 functionality with the fear that we'll get left behind. |
This reverts ab9eab5. This was fixed in swiftlang/swift#75749 and included in Xcode 16.0.
Explanation: [6.0][Concurrency] Don't ignore mismatching isolation for overrides of Clang-imported superclass methods. #74238 added new data-race safety diagnostics for overriding the isolation of a superclass method that's imported from Objective-C. This started diagnosing
@MainActor
-isolated types that overrideNSObject.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. Standard opt-out tools likeMainActor.assumeIsolated
cannot be applied to things like stored property initialization andsuper.init()
, 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@MainActor
-isolated types.Scope: Only impacts isolated overrides of
NSObject.init()
.Issues: Swift 6 regression overriding initializers due to Swift Concurrency #75732, rdar://133349184
Original PRs: [Concurrency] Implement a narrow carve out in the isolation override checking for
NSObject.init()
. #75748Risk: Low; the only effect is removing warnings in complete concurrency checking / errors in Swift 6 mode. This carve-out won't admit a runtime data-race safety hole, because dynamic isolation checks will be inserted in the
@objc
thunks underDynamicActorIsolation
, and direct calls will enforce@MainActor
as usual.Testing: Added new tests.
Reviewers: TBD