Alessandro
Alessandro

Reputation: 4100

Swift function with both completion handler and return

How do I make so that a Swift function returns a value and has a completion handler at the same time? The idea is that the function first returns a provisional result, and then the final result. Something like:

func method(completion: (Int) -> ()) {
    return 2
    ... some processing ...
    completion(3)
}

let a:Int = method(completion: { (new) -> Void in
  a = new
})

Upvotes: 0

Views: 1172

Answers (2)

Rakesha Shastri
Rakesha Shastri

Reputation: 11243

You got it upside down. You have to use the completion handler for the intermediate results and the return for the final result. Once you call the return, the control comes out of the function.

func method(completion: (Int) -> ()) -> Int {
    completion(1)
    //
    //
    completion(2)
    //
    //
    return 3
}

And handle the result like this.

let a: Int = method(completion: { (new) -> Void in
    print(new)
})
print(a)

OR

Have two completion handlers instead.

func foo(provisionalCompletion: (Int) -> (), finalCompletion: (Int) -> ()) {
    provisionalCompletion(someValue)
    //
    //
    provisionalCompletion(someValue)
    //
    //
    finalCompletion(finalValue)
}

You can invoke it and handle the intermediate results and final results like this.

foo(completion: { (provisionalValue) in
    // Handle provisional value
}) { (finalValue) in
    // Handle final value
}

The second approach is more flexible, but also confusing sometimes. You have to be careful to call the final completion only when you have reached the final result. Or you could add a return after every final. But then again you have to make sure your final result is reached.

Upvotes: 1

rmaddy
rmaddy

Reputation: 318774

You are close. You need to kick off some background process (the whole point of a completion handler) and then do the return.

func method(completion: @escaping (Int) -> ()) -> Int {
    DispatchQueue.global().async {
        var x = 0
        for y in 0...10_000 {
            x += y
        }

        completion(3)
    }

    return 2
}

var aRes = 0
aRes = method(completion: { (new) -> Void in
    aRes = new
    print("2", aRes)
})
print("1", aRes)

This will result in:

1 2
2 3

with the second line appearing after a delay.

Note that you can't do:

var aRes = method(completion: { (new) -> Void in
    aRes = new
    print("2", aRes)
})

This results in an error "Variable used within its own initial value".

Upvotes: 1

Related Questions