`awakeFromNib` and Approachable Concurrency

When attempting to compile an existing project with Swift 6, default isolation set to MainActor and approachable concurrency enabled, all awakeFromNib functions lead to the following compile error:

"Main actor-isolated instance method 'awakeFromNib()' has different actor isolation from nonisolated overridden declaration"

I've seen articles before approachable concurrency stating that one remedy is to wrap code within the function with MainActor.assumeIsolated{ }. However, that no longer addresses the error.

One combination of changes that removes the error is doing the following:

nonisolated override func awakeFromNib() {
    super.awakeFromNib()
    MainActor.assumeIsolated {
        ...
    }
}

Honestly, that's a mess. Long term, we are looking to remove all these functions, but does anyone have a better solution?

Answered by DTS Engineer in 853086022

awakeFromNib() is tricky because:

  • Technically, it can be called from any thread [1].
  • But in practice it’s always called on the main thread.
  • In Objective-C parlance it’s an informal protocol [2], which means you can’t use any of the Swift concurrency affordances based on formal protocols

Given that, the code you posted is probably the best you can do. And given “that’s a mess”, and the other problems with awakeFromNib() [3], I think it makes sense to move away from it where you can. keremerkan’s reply covers an approach that works in one specific circumstance, but there are lots of other approaches you can take.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Specifically, it’s call by the thread called the nib loading routine. In the vast majority of cases that’s the main thread, but that’s not an absolute requirement.

[2] It’s declare as a category an NSObject rather than using @protocol.

[3] Specifically, the initialisation order issue called out in the docs.

If this is a UITableViewCell, I have moved all code regarding a variable in awakeFromNib to the corresponding variable's didSet. If the variable is an @IBOutlet, didSet runs only once and works exactly like awakeFromNib.

Accepted Answer

awakeFromNib() is tricky because:

  • Technically, it can be called from any thread [1].
  • But in practice it’s always called on the main thread.
  • In Objective-C parlance it’s an informal protocol [2], which means you can’t use any of the Swift concurrency affordances based on formal protocols

Given that, the code you posted is probably the best you can do. And given “that’s a mess”, and the other problems with awakeFromNib() [3], I think it makes sense to move away from it where you can. keremerkan’s reply covers an approach that works in one specific circumstance, but there are lots of other approaches you can take.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Specifically, it’s call by the thread called the nib loading routine. In the vast majority of cases that’s the main thread, but that’s not an absolute requirement.

[2] It’s declare as a category an NSObject rather than using @protocol.

[3] Specifically, the initialisation order issue called out in the docs.

Agreed that moving away from awakeFromNib would be best here.

Thank you both!

`awakeFromNib` and Approachable Concurrency
 
 
Q