iosuikitswift6

Swift 6 Error: "Call to main actor-isolated instance method in a synchronous nonisolated context"


I'm updating my code to Swift 6 and encountering the following error when calling a method from awakeFromNib():

Call to main actor-isolated instance method 'addContentView()' in a synchronous nonisolated context; this is an error in the Swift 6 language mode

The code below defines a custom UIView subclass, SegmentedHeaderView, that loads its view from a nib file. I call addContentView() in awakeFromNib() to set up the UI. Here’s my code:

class SegmentedHeaderView: UIView {
    
    @IBOutlet var contentView: UIView?
    // Other IBOutlet properties

    override func awakeFromNib() {
        super.awakeFromNib()
        addContentView() // Error occurs here
    }

    @MainActor
    func addContentView() {
        guard let view = loadViewFromNib() else { return }
        view.frame = self.bounds
        self.addSubview(view)
        contentView = view
    }
    
    func loadViewFromNib() -> UIView? {
        let nibName = "SegmentedHeaderView"
        let bundle = Bundle(for: type(of: self))
        let nib = UINib(nibName: nibName, bundle: bundle)
        return nib.instantiate(withOwner: self, options: nil).first as? UIView
    }
}

In Swift 6, it seems that awakeFromNib() is considered a nonisolated context, so calling @MainActor functions directly from it leads to this error.

What I've Tried

Using Task { @MainActor in ... }: I wrapped addContentView() in a Task to ensure it runs on the main actor, but this does break my UI.

override func awakeFromNib() {
    super.awakeFromNib()
    Task { @MainActor in
        addContentView()
    }
}

I have also tried to use MainActor.assumeIsolated, seems like working, but I am not sure whether it is a good solution or not.

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

Solution

  • Using MainActor.assumeIsolated is good solution because awakeFromNib is a UI related function so It will be surely run on Main Thread. Don't call addContentView in Task because it will run asynchronous