Data Race Issue with Swift Actor

Viewed 106

I'm in the process of converting my code to using Swift concurrency and I'm running into an issue with Actor which I don't know how to fix it correctly.

Here is a simple actor:

actor MyActor {
    private var count = 0
    
    func increase() {
        count += 1
    }
}

In other places where I need to update the actor, I have to call its functions in concurrency context:

Task {
    await myActor.increase()
}

That's good. But what I don't understand is if the actor return the increase function as a closure like this:

actor MyActor {
    private var count = 0
    
    func increase() -> () -> Void {
        {
            print("START")
            self.count += 1
            print("END")
        }
    }
}

In other places, I can get a reference to the returned closure and call it freely in non-concurrency context:

class ViewController: UIViewController {
    let actor = MyActor()

    var increase: (() -> Void)?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Task {
            increase = await actor.increase()
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            let increase = self.increase
            
            DispatchQueue.concurrentPerform(iterations: 100) { _ in
                increase?()
            }
        }
    }
}

The above code print this to the output:

START
START
START
START
START
END
END
START
START
...

I'm not sure if I understand or use Actor correctly. Actor protects its state from data races, but in this case, it does not prevent that. Is it correct behavior? Is there a way to fix it?

0 Answers
Related