waiting for a function to finish with completion handler fails - swift

I am trying to wait for an asynchronous function to finish before processing it's data (e.g. saving it to my database).
I have a function loadFacebookDetails() containing two tasks:
Loading Data from Facebook makeRequest()
Saving the Data to my Database saveAndProceed()
I need makeRequest() -> (asynchronous) to finish before handling the saving.
This is what I got so far:
I declared a typealias FinishedDownload = () -> ()
I created:
func makeRequest(completed: FinishedDownload){
.... // bunch of code
completed() // call that I completed my task at end of function
}
now I don't now how to call makeRequest in my loadFacebookDetails.
I also created this:
makeRequest { () -> () in
saveAndProceed()
}
and my saveAndProceed().
Does anyone now how to make this syntactical correct?

You should have something like :
func makeRequest(completion : ( ( Bool ) -> Void)){
//your stuff goes hre
completion(true)
//or
completion(false)
}
func saveAndProceed() {
//your stuff
}
func loadFacebookDetails() {
makeRequest { (hasSucceed) in
if hasSucceed {
saveAndProceed()
}else{
//handle Error
}
}
}

func makeRequest(url: String ,callback :#escaping (YourObject) -> Void , errorCallBack : #escaping (String) -> Void ){
// if finish or success
callback(objecttoSend);
// or if failed
errorCallBack(message)
}
and call it like this
makeRequest(url: "http://", callback: {(Object)in
// on ur first action
}, errorCallBack: {(error)in
// on ur second action
})

Related

Is there a way of using a completion handler passed through as an argument to detect when a long request is completed

I'm having trouble understanding how to use a closure to handle completed events when passing in a function as a parameter.
Here's a very contrived example:
class MessageService {
func sendMessage(s: String) {
print(s)
}
var messenger: Messenger {
createMessenger(completion: sendMessage(s:))
}
}
func createMessenger(completion: #escaping (String) -> Void) -> Messenger {
return Messenger { completion("This is a hardcoded message.") }
}
struct Messenger {
let sendMessage: () -> Void
init(sendMessage: #escaping () -> Void) {
self.sendMessage = sendMessage
}
}
let service = MessageService()
let messenger = service.messenger
messenger.sendMessage()
I want to find out when sendMessage is finished (if for example it was performing something like a network request), so is there a way of having a completion handler for sendMessage so that I could write something along the lines of:
messenger.sendMessage {
print("I finished sending a message!")
}
I've tried adding a completion handler like this in the service class:
func sendMessage(s: String, completion: #escaping () -> Void) {
MessageRequest(with: s) {
completion()
}
}
But things started getting very confusing when I'm trying to use the createMessenger method, because the above function has some crazy type of (String, () -> ()) -> () which I don't know how to handle. Any help would be greatly appreciated, thanks.
So, it sounds like what you want is an arbitrary Messenger type, whose creator tell it what action to do, and once the action is done, it invokes its caller's completion handler.
It helps if you use typealias with descriptive names to keep track of all the closures. And if you don't mind, I'll name it more generically as Agent:
struct Agent {
typealias Completion = () -> Void
typealias Action = (Completion) -> Void
private let action: Action
static func create(action: #escaping Action) -> Agent {
Agent(action: action)
}
func execute(_ completion: #escaping Completion) {
action(completion)
}
}
So, Agent can be created with an arbitrary action that accepts a completion handler to signal when it's done:
let agent = Agent.create { completion in
print("started executing action")
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { completion() }
}
agent.execute { print("done") }
Now, you can adapt it to your MessengerService class:
class MessageService {
func sendMessage(s: String) {
print(s)
}
var messenger: Agent {
Agent.create { completion in
sendMessage("This is a hardcoded message.")
completion()
}
}
}

How do I reverse a promise?

I'm using PromiseKit to handle flow through a process.
Prior, I did a similar app without promises but decided frick it I'm gonna try promises just because, well, why not?
So I'm throwing a back button in the mix as I did in the prior app. Only problem is, I'm not exactly sure how to handle "reversing" if you want to call it that.
So say I have a flow of
doSomething().then {
// do something else
}.then {
// do something else
}.done {
// wrap it up, boss
}.catch {
// you're an idiot, bud
}
Say I'm in the first or second part of the chain then and I want to go back up the chain - is this possible?
Is there a link y'all can give me that I can use to read up on how to do that?
I'm thinking I might have to restart the "chain", but then how would I step through the flow....WAIT (light bulb), I can programmatically fulfill the necessary promises with whatever the data is that initially was fulfilled with until I get to the point in the "chain" where I needed to go back to, right?
Advice D:?
You can always have a catch and a then on the same promise.
var somePromise = doSomething()
// first chain
somePromise.catch { error in
// handle error
}
// second chain from the same starting point
somePromise.then {
// do something else
}.then {
// do something else
}.catch {
// you can still catch the error here too
}
You're basically creating two promise chains from the same original promise.
No, you can not do that. Once you commit a promise, you can not reverse that. Because the chain is supposed to finish in the descending order, it's cumbersome to track the order in each .then block.
What you can do is, handle the internal logic responsible to fulfill or reject a promise and start the chain from the beginning.
func executeChain() {
doSomething().then {
// do something else
}.then {
// do something else
}.done {
// condition to
executeChain()
}.catch {
// you're an idiot, bud
}
}
func doSomething() -> Promise<SomeThing>{
if (condition to bypass for reversing) {
return .value(something)
}
// Normal execution
}
But if you can improve your question with an actual use case and code then it could help providing more suitable explanation.
No you can't but you can set order in array.
bar(promises: [foo1(), foo2(), foo3()])
func bar<T>(promises: [Promise<T>]) {
when(fulfilled: promises)
.done { _ in
// TODO
}
.catch { error in
// When get error reverse array and call it again
self.bar(promises: promises.reversed())
}
}
func foo1() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}
func foo2() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}
func foo3() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}
or alternatively
bar(foo1, foo2, foo3)
.done { _ in
// TODO
}
.catch { error in
print(error.localizedDescription)
self.bar(self.foo3, self.foo2, self.foo1)
.done { _ in
// TODO
}
.catch { error2 in
print(error2.localizedDescription)
}
}
func bar<T>(_ promise1: () -> Promise<T>,
_ promise2: #escaping () -> Promise<T>,
_ promise3: #escaping () -> Promise<T>) -> Promise<T> {
return Promise { seal in
promise1()
.then { _ in return promise2() }
.then { _ in return promise3() }
.done { model in
seal.fulfill(model)
}
.catch {
seal.reject($0)
}
}
}
func foo1() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}
func foo2() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}
func foo3() -> Promise<Void> {
return Promise { $0.fulfill(()) }
}

Swift: async execution in series + array of closures + escaping

I have a few async function which I'd like to run in series to avoid "callback hell" and simplify things I've written the following helper structure:
typealias AsyncCallback = (Bool) -> Void
typealias AsyncFunction = (AsyncCallback) -> Void
public struct AsyncHelpers {
public static func series(_ functions: [AsyncFunction], _ callback: #escaping AsyncCallback) {
var index = 0
var completed: AsyncCallback? = nil
completed = { success in
if success == false { callback(false); return }
index += 1
if index < functions.count {
functions[index](completed!)
return
}
callback(true)
}
functions[index](completed!)
}
}
AsyncHelpers.series([
{ callback in
// do async stuff
callback(true)
}, { callback in
// then do async stuff
callback(true)
}
]) { callback in
// when all completed
}
I can set the #escaping attribute for completion handler, but when I try to apply this attribute to [AsyncFunction] compilator fails with this error: "#escaping attribute only applies to function types". Should I mark these closured as escaping in other way, please?
What is lifecycle of index variable, can I use it inside completed closure without any problem?

Returning after calling completion handler, or return completion handler parameter?

I have a method that can be summed up to look like this:
func apply(username: String, email: String, password: String,
onDone: #escaping (_ error: Error?) -> ())
{
//Do async stuff
do
{
try asyncGood()
onDone(nil)
return
}
catch
{
onDone(error)
return
}
}
What's the difference between doing:
return onDone(error)
versus
onDone(error)
return
?
Does it just save an extra line of code? I don't see any difference between the two. Am I missing some fundamental aspect of asynchronous Swift programming?
In your opinion, should I always try to condense everything down such that onDone(...) only gets called once at the end?
Semantically, both cases are the same. You are basically saying:
return ()
Your method is declared to return (), and since the onDone closure also returns a (), you can say return onDone(error). The return types match.
However, I find writing them in 2 separate lines more readable:
// This clearly shows that you are doing 2 separate things
onDone(error) // call the completion handler
return // return
Or even omit the return!
onDone(error)
// there will be an implicit return at the end of the method.
Both are same. apply function return type is Void and onDone closure return type is also Void. So both are same.
return onDone(error)
or
onDone(error)
return
or you can just ignore return because return type is Void
onDone(error)
There is no difference. In fact, there is no need for return keyword at all.
For swift all the following declaration is equivalent:
func doNothing() {
}
func doNothing2() -> Void {
}
func doNothing3() -> () {
}
func doNothing4() {
return ()
}
func doNothing5() -> Void {
return ()
}
When you return () you return nothing. No return is exactly the same as return nothing. Functions returning Void may be equivalently used as following
doNothing()
var result = doNothing()
More, Void can also be used as a type parameter which is a very powerful feature:
func genericCall<T>(_ f: () -> T) -> T {
return f()
}
var result1 = genericCall { print("test") } // result1 is Void
var result2 = genericCall { return 5 } // result2 is Int
Answering your initial question, I would suggest to omit return at all
func doStuffAsync(_ callback: #escaping (Error?) -> Void) {
// Just an example. Could be any other async call.
DispatchQueue.main.async {
do {
try doStuff()
callback(nil)
}
catch {
callback(error)
}
}
}

Passing and storing closures/callbacks in Swift

I would like to do the following in swift code:
I have to call my api in order to update several items. So I call the api for each item asynchronously. Each api call executes a callback function when it's done. These callbacks decrease a counter, so that when the counter reaches 0 I know that all my api calls are completed. When the counter reaches 0 I would like to call a final callback function (once, when all calls are complete), in order to update my UI and so forth. This final callback is passes to my service in the beginning and stored in a class property for later execution.
Executable Playground source:
// Playground - noun: a place where people can play
class MyService
{
let api = MyApi()
var storedFinalCallback: () -> Void = { arg in }
var queue: Int = 0
func update(items: [String], finalCallback: () -> Void )
{
// Count the necessary API calls
queue = items.count
// Store callback for later execution
storedFinalCallback = finalCallback
for item in items {
// Call api per item and pass queueCounter as async callback
api.updateCall(item, callback: self.callback())
}
}
func callback()
{
queue--
// Execute final callback when queue is empty
if queue == 0 {
println("Executing final callback")
storedFinalCallback()
}
}
}
class MyApi
{
func updateCall(item: String, callback: ())
{
println("Updating \(item)")
}
}
let myItems: [String] = ["Item1", "Item2", "Item3"]
let myInstance: MyService = MyService()
myInstance.update(myItems, finalCallback: {() -> Void in
println("Done")
})
The problem is that with this code the final callback is called in the wrong order.
Apparently the callback function is already executed and not properly passed. However, this was the only way I was able to do it, without compiler errors.
Any help would be really appreciated - I have been stuck on this for two days now.
I finally found the working code:
// Playground - noun: a place where people can play
class MyService
{
let api = MyApi()
var storedFinalCallback: () -> Void = { arg in }
var queue: Int = 0
func update(items: [String], finalCallback: () -> Void )
{
// Count the necessary API calls
queue = items.count
// Store callback for later execution
storedFinalCallback = finalCallback
for item in items {
// Call api per item and pass queueCounter as async callback
api.updateCall(item, callback: self.callback)
}
}
func callback()
{
queue--
// Execute final callback when queue is empty
if queue == 0 {
println("Executing final callback")
storedFinalCallback()
}
}
}
class MyApi
{
func updateCall(item: String, callback: () -> Void)
{
println("Updating \(item)")
callback()
}
}
let myItems: [String] = ["Item1", "Item2", "Item3"]
let myInstance: MyService = MyService()
myInstance.update(myItems, finalCallback: {() -> Void in
println("Done")
})