Deepak Sharma
Deepak Sharma

Reputation: 6585

Swift initializer call Dispatch Queue async

Is it wrong to call async from Swift object initializer such as this one

let serialQueue = DispatchQueue(label: "com.myApp.SerialQueue")
private let property1:Int?

public override init()
{
    super.init()
    /* Initialize properties */
    setupProperties()
    serialQueue.async { [unowned self] in
       self.nonBlockingSetup()
    }
}
private func setupProperties() {
    self.property1 = 1
}
private func nonBlockingSetup() {
    //Some non-blocking code that shouldn't run on main thread
}

Some people say async call is problematic before init returns. Need to know what Swift language says about it.

EDIT: Is there any difference if I modify the code as follows:

public override init()
{
    super.init()
    /* Initialize properties */
    setupProperties()
    callNonBlockingCodeAsync()
}

private func callNonBlockingCodeAsync() {
   serialQueue.async { [unowned self] in
       self.nonBlockingSetup()
    }
}

Upvotes: 0

Views: 1184

Answers (2)

Alfonso
Alfonso

Reputation: 8502

In general, a constructor should not do any meaningful work.

Having a constructor that executes code delayed (because it's async) will be unexpected for anyone using that class (quite possibly including you in 6 months), and can therefore lead to bugs. In such cases it's usually better to have a separate initialization method, which makes it clear to an api user that there is something more going on.

If you absolutely want to make sure the initialization method is called, I usually make the constructor private and add a class method for construction. Again this signals api users that there is something going on behind the scenes.

Upvotes: 1

Rahul Umap
Rahul Umap

Reputation: 2869

To answer your question, I tried out the simple example.

enter image description here

Errors are very much self explanatory, in the initialisation process dispatchQueue are capturing self reference right before it's actual initialisation.

You are running into the concurrency problem where initialisation of object is necessary before using it.

dispatchQueue uses closures to provide DispatchWorkItem and as you know closures captures values surrounding it's scope.

Update

One work around would be to give default values to your properties but I am not sure if that will help you.

Upvotes: 1

Related Questions