Fixing Swift Actors and Delegate Error on Xcode 14

If you’ve updated Xcode to version 14 you might get an error about mutating actor-isolated property in your project. Let’s fix it.

Max Kalik
Better Programming

--

I’m not going to tell you again about Actors from scratch, what is it and how it works. Since Apple has introduced Swift 5.5 there are tons of cool articles about them. If you still don’t use actors then it’s time to take a look. I bet it will come a time when you will change some of your classes to actors.

This particular article is about a specific potential issue while using actors with delegates after updating Xcode with version 14. It sounds a bit trivial but I think it could be useful. Let’s get started.

Before Xcode 14

Let’s assume we have class SomeClass with a delegate:

SomeClass with delegate

And SomeViewModel — in there we going to use our SomeClass:

SomeView model with SomeClass

As you can see, we did a primitive manipulation by setting delegate to self and conforming view model with SomeClassDelegate.So, let’s print out some results from it.

let someViewModel = SomeViewModel()
someViewModel.start()
// Printed: some class did start

Ok. Now it’s time to refactor our class with an actor. How it could be (and maybe you have done it already in your project in this similar way):

In the same way, let’s use it in our view model. Of course, since we have a deal with an actor we need Tasks.

After

If you are still using Xcode 13 you probably won’t see any warnings in this implementation. But if you have updated already Xcode with version 14, most likely you will get this error:

Actor-isolated property ‘delegate’ can not be mutated from a non-isolated context

At first sight, it’s confusing, especially: “No async operations occur within await expression” when the delegate is an actor’s property. Also, it could be a question — if we await to change a property from outside, why do we see this message about isolation?

In reality, the errors both make sense and look weird a little bit. As we know — the base idea of the actors is to isolate properties. It means you cannot just update property from outside. So, probably, these errors teach us how to use actors properly and the updating of the property delegate should happen only inside of the actor SomeActor.

A reasonable solution is to add an additional method. This method will set the delegate with a new value.

setDelegate method

Inside of the Task in view model replace this:

// await someActor.delegate = self
await someActor.setDelegate(self)

Expected result:

let someViewModel = SomeViewModel()
someViewModel.start()
// Printed: some actor did start

Wrapping up

I wouldn’t write this article if the error wasn’t so unexpected. I see already some questions appear in Stackoverflow or in Swift discussions and I asked the same. If this actor-isolated property error is only about teaching us how to use actors properly, why can’t it be only a warning?

Thank you for reading.

Want to Connect?Don't hesitate to follow me on Twitter.I appreciate any suggestions or comments regarding my research and articles.

--

--