What's difference between `add(_)` and `add(_) async`? - swift

I don't understand what's the difference between add(_) and add(_) async method. Like the below code, the MyActor has two add methods and one of them uses async keyword. They can exist at the same time. If I comment out the second add method it will output AAAA. If both add methods exist at the same time, output "BBBBB"。
actor MyActor {
var num: Int = 0
func add(_ value: Int) {
print("AAAAA")
num += value
}
func add(_ value: Int) async {
print("BBBBB")
num += value
}
}
let actor = MyActor()
Task {
await actor.add(200)
print(await actor.num)
}
Supplementary:
With the second add method commented out, I defined let actor = MyActor() outside Task and I noticed the add method signed as add(_:). If move let actor = MyActor() inside Task the add method signed as add(_:) async

The difference emerges inside the actor, for example
actor MyActor {
func addSync(_ value: Int) {
}
func addAsync(_ value: Int) async {
}
func f() {
addSync(0)
}
func g() async {
addSync(0)
await addAsync(0)
}
}
In the actor method f and g you can call addSync synchronously. While outside the actor, you need always call an actor method with the await keyword as if the method is asynchronous:
func outside() async {
let actor = MyActor()
await actor.addSync(0)
}

Async in Swift allows for structured concurrency, which will improve the readability of complex asynchronous code. Completion closures are no longer needed, and calling into multiple asynchronous methods after each other is a lot more readable.
Async stands for asynchronous and can be seen as a method attribute making it clear that a method performs asynchronous work. An example of such a method looks as follows:
func fetchImages() async throws -> [UIImage] {
// .. perform data request
}
The fetchImages method is defined as async throwing, which means that it’s performing a failable asynchronous job. The method would return a collection of images if everything went well or throws an error if something went wrong.
How async replaces closure completion callbacks
Async methods replace the often seen closure completion callbacks. Completion callbacks were common in Swift to return from an asynchronous task, often combined with a Result type parameter. The above method would have been written as followed:
func fetchImages(completion: (Result<[UIImage], Error>) -> Void) {
// .. perform data request
}
Defining a method using a completion closure is still possible in Swift today, but it has a few downsides that are solved by using async instead:
You have to make sure yourself to call the completion closure in each possible method exit. Not doing so will possibly result in an app waiting for a result endlessly.
Closures are harder to read. It’s not as easy to reason about the order of execution as compared to how easy it is with structured concurrency.
Retain cycles need to be avoided using weak references.
Implementors need to switch over the result to get the outcome. It’s not possible to use try catch statements from the implementation level.
These downsides are based on the closure version using the relatively new Result enum. It’s likely that a lot of projects still make use of completion callbacks without this enumeration:
func fetchImages(completion: ([UIImage]?, Error?) -> Void) {
// .. perform data request
}
Defining a method like this makes it even harder to reason about the outcome on the caller’s side. Both value and error are optional, which requires us to perform an unwrap in any case. Unwrapping these optionals results in more code clutter which does not help to improve readability.

Related

What is the Swift concurrency equivalent to a promise–resolver pair?

With the PromiseKit library, it’s possible to create a promise and a resolver function together and store them on an instance of a class:
class ExampleClass {
// Promise and resolver for the top news headline, as obtained from
// some web service.
private let (headlinePromise, headlineSeal) = Promise<String>.pending()
}
Like any promise, we can chain off of headlinePromise to do some work once the value is available:
headlinePromise.get { headline in
updateUI(headline: headline)
}
// Some other stuff here
Since the promise has not been resolved yet, the contents of the get closure will be enqueued somewhere and control will immediately move to the “some other stuff here” section; updateUI will not be called unless and until the promise is resolved.
To resolve the promise, an instance method can call headlineSeal:
makeNetworkRequest("https://news.example/headline").get { headline in
headlineSeal.fulfill(headline)
}
The promise is now resolved, and any promise chains that had been waiting for headlinePromise will continue. For the rest of the life of this ExampleClass instance, any promise chain starting like
headlinePromise.get { headline in
// ...
}
will immediately begin executing. (“Immediately” might mean “right now, synchronously,” or it might mean “on the next run of the event loop”; the distinction isn’t important for me here.) Since promises can only be resolved once, any future calls to headlineSeal.fulfill(_:) or headlineSeal.reject(_:) will be no-ops.
Question
How can this pattern be translated idiomatically into Swift concurrency (“async/await”)? It’s not important that there be an object called a “promise” and a function called a “resolver”; what I’m looking for is a setup that has the following properties:
It’s possible for some code to declare a dependency on some bit of asynchronously-available state, and yield until that state is available.
It’s possible for that state to be “fulfilled” from potentially any instance method.
Once the state is available, any future chains of code that depend on that state are able to run right away.
Once the state is available, its value is immutable; the state cannot become unavailable again, nor can its value be changed.
I think that some of these can be accomplished by storing an instance variable
private let headlineTask: Task<String, Error>
and then waiting for the value with
let headline = try await headlineTask.value
but I’m not sure how that Task should be initialized or how it should be “fulfilled.”
Here is a way to reproduce a Promise which can be awaited by multiple consumers and fulfilled by any synchronous code:
public final class Promise<Success: Sendable>: Sendable {
typealias Waiter = CheckedContinuation<Success, Never>
struct State {
var waiters = [Waiter]()
var result: Success? = nil
}
private let state = ManagedCriticalState(State())
public init(_ elementType: Success.Type = Success.self) { }
#discardableResult
public func fulfill(with value: Success) -> Bool {
return state.withCriticalRegion { state in
if state.result == nil {
state.result = value
for waiters in state.waiters {
waiters.resume(returning: value)
}
state.waiters.removeAll()
return false
}
return true
}
}
public var value: Success {
get async {
await withCheckedContinuation { continuation in
state.withCriticalRegion { state in
if let result = state.result {
continuation.resume(returning: result)
} else {
state.waiters.append(continuation)
}
}
}
}
}
}
extension Promise where Success == Void {
func fulfill() -> Bool {
return fulfill(with: ())
}
}
The ManagedCriticalState type can be found in this file from the SwiftAsyncAlgorithms package.
I think I got the implementation safe and correct but if someone finds an error I'll update the answer. For reference I got inspired by AsyncChannel and this blog post.
You can use it like this:
#main
enum App {
static func main() async throws {
let promise = Promise(String.self)
// Delayed fulfilling.
let fulfiller = Task.detached {
print("Starting to wait...")
try await Task.sleep(nanoseconds: 2_000_000_000)
print("Promise fulfilled")
promise.fulfill(with: "Done!")
}
let consumer = Task.detached {
await (print("Promise resolved to '\(promise.value)'"))
}
// Launch concurrent consumer and producer
// and wait for them to complete.
try await fulfiller.value
await consumer.value
// A promise can be fulfilled only once and
// subsequent calls to `.value` immediatly return
// with the previously resolved value.
promise.fulfill(with: "Ooops")
await (print("Promise still resolved to '\(promise.value)'"))
}
}
Short explanation
In Swift Concurrency, the high-level Task type resembles a Future/Promise (it can be awaited and suspends execution until resolved) but the actual resolution cannot be controlled from the outside: one must compose built-in lower-level asynchronous functions such as URLSession.data() or Task.sleep().
However, Swift Concurrency provides a (Checked|Unsafe)Continuation type which basically act as a Promise resolver. It is a low-lever building block which purpose is to migrate regular asynchronous code (callback-based for instance) to the Swift Concurrency world.
In the above code, continuations are created by the consumers (via the .value property) and stored in the Promise. Later, when the result is available the stored continuations are fulfilled (with .resume()), which resumes the execution of the consumers. The result is also cached so that if it is already available when .value is called it is directly returned to the called.
When a Promise is fulfilled multiple times, the current behavior is to ignore subsequent calls and to return aa boolean value indicating if the Promise was already fulfilled. Other API's could be used (a trap, throwing an error, etc.).
The internal mutable state of the Promise must be protected from concurrent accesses since multiple concurrency domains could try to read and write from it at the same time. This is achieve with regular locking (I believe this could have been achieved with an actor, though).

What is the `nonisolated` keyword in Swift?

I recently came across the nonisolated keyword in Swift in the following code:
actor BankAccount {
init(balance: Double) {
self.balance = balance
}
private var balance: Double
nonisolated func availableCountries() -> [String] {
return ["US", "CA", "NL"]
}
func increaseBalance(by amount: Double) {
self.balance += amount
}
}
What does it do? The code compiles both with and without it.
The nonisolated keyword was introduced in SE-313. It is used to indicate to the compiler that the code inside the method is not accessing (either reading or writing) any of the mutable state inside the actor. This in turn, enables us to call the method from non-async contexts.
The availableCountries() method can be made nonisolated because it doesn't depend on any mutable state inside the actor (for example, it doesn't depend on the balance variable).
When you are accessing different methods or variables of an actor, from outside the actor, you are only able to do so from inside an asynchronous context.
Let's remove the nonisolated keyword from the availableCountries() method. Now, if we want to use the method, we are only allowed to do so in an async context. For example, inside a Task:
let bankAccount = BankAccount(balance: 1000)
override func viewDidLoad() {
super.viewDidLoad()
Task {
let availableCountries = await bankAccount.availableCountries()
print(availableCountries)
}
}
If we try to use the method outside of an async context, the compiler gives us errors:
However, the availableCountries() isn't using any mutable state from the actor. Thus, we can make it nonisolated, and only then we can call it from non async contexts (and the compiler won't nag).

Race condition in unit tests

I'm currently testing a number of classes that do network stuff like REST API calls, and a Realm database is mutated in the process. When I run all the different tests I have at once, race conditions appear (but of course, when I run them one by one, they all pass). How can I reliably make the tests pass?
I have tried to call the mentioned functions in a GCD block like this:
DispatchQueue.main.async {
self.function.start()
}
One of my tests are still failing, so I guess the above didn't work. I have enabled Thread Sanitizer and it reports, from time to time, that race conditions appear.
I can't post code, so I'm looking for conceptual solutions.
Typically some form of dependency injection. Be it an internally exposed var to the DispatchQueue, a default argument in a function with the queue, or a constructor argument. You just need some way to pass a test queue that dispatches the event when you need to.
DispatchQueue.main.async will schedule the block async to the callee on the main queue and therefore isn't guarenteed by the time you make an assertion.
Example (disclaimer: I'm typing from memory so it might not compile but it gives the idea):
// In test code.
struct TestQueue: DispatchQueue {
// make sure to impement other necessary protocol methods
func async(block: () -> Void) {
// you can even have some different behavior for when to execute the block.
// also you can pass XCTestExpectations to this TestQueue to be fulfilled if necessary.
block()
}
}
// In source code. In test, pass the Test Queue to the first argument
func doSomething(queue: DispatchQueue = DispatchQueue.main, completion: () -> Void) {
queue.async(block: completion)
}
Other methods of testing async and eliminating race conditions revolve around craftily fulfilling an XCTestExpectation.
If you have access to the completion block that is eventually invoked:
// In source
class Subject {
func doSomethingAsync(completion: () -> Void) {
...
}
}
// In test
func testDoSomethingAsync() {
let subject = Subject()
let expect = expectation(description: "does something asnyc")
subject.doSomethingAsync {
expect.fulfill()
}
wait(for: [expect], timeout: 1.0)
// assert something here
// or the wait may be good enough as it will fail if not fulfilled
}
If you don't have access to the completion block it usually means finding a way to inject or subclass a test double that you can set an XCTestExpectation on and will eventually fulfill the expectation when the async work has completed.

Swift #escaping and Completion Handler

I am trying to understand 'Closure' of Swift more precisely.
But #escaping and Completion Handler are too difficult to understand
I searched many Swift postings and official documents, but I felt it was still not enough.
This is the code example of official documents
var completionHandlers: [()->Void] = []
func someFunctionWithEscapingClosure(completionHandler: #escaping ()->Void){
completionHandlers.append(completionHandler)
}
func someFunctionWithNoneescapingClosure(closure: ()->Void){
closure()
}
class SomeClass{
var x:Int = 10
func doSomething(){
someFunctionWithEscapingClosure {
self.x = 100
//not excute yet
}
someFunctionWithNoneescapingClosure {
x = 200
}
}
}
let instance = SomeClass()
instance.doSomething()
print(instance.x)
completionHandlers.first?()
print(instance.x)
I heard that there are two ways and reasons using #escaping
First is for storing a closure, second is for Async operating purposes.
The following are my questions:
First, if doSomething executes then someFunctionWithEscapingClosure will executing with closure parameter and that closure will be saved in global variable array.
I think that closure is {self.x = 100}
How self in {self.x = 100} that saved in global variable completionHandlers can connect to instance that object of SomeClass ?
Second, I understanding someFunctionWithEscapingClosure like this.
To store local variable closure completionHandler to global variable 'completionHandlerswe using#escaping` keyword!
without #escaping keyword someFunctionWithEscapingClosure returns, local variable completionHandler will remove from memory
#escaping is keep that closure in the memory
Is this right?
Lastly, I just wonder about the existence of this grammar.
Maybe this is a very rudimentary question.
If we want some function to execute after some specific function. Why don't we just call some function after a specific function call?
What are the differences between using the above pattern and using an escaping callback function?
Swift Completion Handler Escaping & Non-Escaping:
Assume the user is updating an app while using it. You definitely want
to notify the user when it is done. You possibly want to pop up a box
that says, “Congratulations, now, you may fully enjoy!”
So, how do you run a block of code only after the download has been
completed? Further, how do you animate certain objects only after a
view controller has been moved to the next? Well, we are going to find
out how to design one like a boss.
Based on my expansive vocabulary list, completion handlers stand for
Do stuff when things have been done
Bob’s post provides clarity about completion handlers (from a developer point of view it exactly defines what we need to understand).
#escaping closures:
When one passes a closure in function arguments, using it after the function’s body gets executed and returns the compiler back. When the function ends, the scope of the passed closure exist and have existence in memory, till the closure gets executed.
There are several ways to escaping the closure in containing function:
Storage: When you need to store the closure in the global variable, property or any other storage that exist in the memory past of the calling function get executed and return the compiler back.
Asynchronous execution: When you are executing the closure asynchronously on despatch queue, the queue will hold the closure in memory for you, can be used in future. In this case you have no idea when the closure will get executed.
When you try to use the closure in these scenarios the Swift compiler will show the error:
For more clarity about this topic you can check out this post on Medium.
Adding one more points , which every ios developer needs to understand :
Escaping Closure : An escaping closure is a closure that’s called after the function it was passed to returns. In other words,
it outlives the function it was passed to.
Non-escaping closure : A closure that’s called within the function it was passed into, i.e. before it returns.
Here's a small class of examples I use to remind myself how #escaping works.
class EscapingExamples: NSObject {
var closure: (() -> Void)?
func storageExample(with completion: (() -> Void)) {
//This will produce a compile-time error because `closure` is outside the scope of this
//function - it's a class-instance level variable - and so it could be called by any other method at
//any time, even after this function has completed. We need to tell `completion` that it may remain in memory, i.e. `escape` the scope of this
//function.
closure = completion
//Run some function that may call `closure` at some point, but not necessary for the error to show up.
//runOperation()
}
func asyncExample(with completion: (() -> Void)) {
//This will produce a compile-time error because the completion closure may be called at any time
//due to the async nature of the call which precedes/encloses it. We need to tell `completion` that it should
//stay in memory, i.e.`escape` the scope of this function.
DispatchQueue.global().async {
completion()
}
}
func asyncExample2(with completion: (() -> Void)) {
//The same as the above method - the compiler sees the `#escaping` nature of the
//closure required by `runAsyncTask()` and tells us we need to allow our own completion
//closure to be #escaping too. `runAsyncTask`'s completion block will be retained in memory until
//it is executed, so our completion closure must explicitly do the same.
runAsyncTask {
completion()
}
}
func runAsyncTask(completion: #escaping (() -> Void)) {
DispatchQueue.global().async {
completion()
}
}
}
/*the long story short is that #escaping means that don't terminate the function life time until the #escaping closure has finished execution in the opposite of nonEscaping closure the function can be terminated before the closure finishes execution Ex:
*/
func fillData(completion: #escaping: () -> Void){
/// toDo
completion()
}
//___________________________
//The call for this function can be in either way's #escaping or nonEscaping :
fillData{
/// toDo
}
/* again the deference between the two is that the function can be terminated before finish of execution nonEscaping closure in the other hand the #escaping closure guarantees that the function execution will not be terminated before the end of #escaping closure execution. Hope that helps ***#(NOTE THAT THE CLOSURE CAN BE OF ANY SWIFT DATA TYPE EVEN IT CAN BE TYPEALIAS)*/

Swift Completion Block

I want to achieve the following :
In classB, to reload my database after adding 1 object. reloadDatabase() is called within the completionBlock.
In classB, reloadDatabase() will call getObjects() in classA to get the most updated list of database objects and pass to objectList in classB
Question: How do i ensure that whenever i call getObjectList() in classB, i will always get the most updated list? From my understanding, my objectList might not be update in reloadDatabase() block. I could be calling getObjectList() when reloadDatabase() haven't reach the completion block yet (objectList is still the old objectList).
I am pretty new to closures and blocks. Any guidance is greatly appreciated!
class classA: NSObject {
func addThisObject(object: RLMObject, completionBlock: () -> ())){
...
completionBlock()
}
func getObjects (completionBlock: ((list: [RLMObject]) -> ())){
var recordList = [RLMObject]()
...
completionBlock(list: recordList)
}
}
class classB: NSObject {
var objectList = [RLMObject]()
func addObject (object: RLMObject) {
classA().addThisObject(object, completionBlock: {() -> () in
self.reloadDatabase()
})
}
func reloadDatabase() {
classA().getObjects{(list) -> () in
self.objectList = list
}
}
func getObjectList() -> [RLMObject] {
return objectList
}
}
From your snippets it seems to me there is no asynchronous calls, so you won't be able to call getObjectList() before reloadDatabase() block. Closures are not asynchronous if you don't use them with something that is (e.g. GCD).
If you have asynchronous calls, but they are not in the snippets, then getObjectList() can be called while reloadDatabase() is being executed. Then you have few options:
Remove asynchronous calls
Use serial queue for your methods
Add boolean variable updateInProgress and check it in getObjectList() - how to do it
Ignore the fact that data may be outdated - it is correctness vs speed trade.
Let your database inform its clients that something changed
In your question, you don't say whether you'll be calling any of these functions from different threads. So when you call addObject() in classB, execution wouldn't even continue until the database has been reloaded and objectList was updated.
Using closures and blocks does not automatically imply that code will be executed on a different context.