Objective C How to return outer function from inside async inner function

天涯浪子 提交于 2019-12-08 12:35:50

问题


I want to return from outer function from inside async inner function. In swift, I would have used completion handler for this purpose which would escape from function. But in objective c, completion handler won't actually return from function:

My function looks like this:

-(void)chosenFrom:(NSDictionary<NSString *,id> *)info{

    [self asyncCode:info withCompletion:^(NSData *imageData) {
        if(imageData) {
             // I want to return from  chosenFrom function ***inside here.***
        }
    }];

// This is to illustrate  completion handler don't escape
[self checkCompletionEscaping:^(NSString * lad) {
    NSLog(@"Check me %@", lad);// It would print all 3 lines below.
}];
}

-(void) checkCompletionEscaping:(void(^)(NSString * lad)) completion {
completion(@"Hello"); // completion handler should've escaped from func.
completion(@"Shivam");
completion(@"How are you");
}

If i were to use swift, i could have easily returned from outer function from inside inner fucntion using completion handler:

private func getHistoryKeys(searchterm: String, completion: @escaping () -> ()) {
  let url = PubmedAPI.createEsearchURL(searchString: searchterm)
  let task = session.dataTask(with: url) { (data, response, error) in
   if let error = error {
      completion() // This would work as return
   } else {
      completion() // Same as return
   }
  }
 task.resume()
}

PS: escaping means returning from function just like return statement.


回答1:


Easier is just to call another function that tells it's completed.

-(void)chosenFrom:(NSDictionary<NSString *,id> *)info{

    [self asyncCode:info withCompletion:^(NSData *imageData) {
        if(imageData) {
             [self completedAsync:imageData];
        }
    }];

}

-(void)completedAsync:(NSData*) imageData {
  // do your thang.
}



回答2:


It seems you've asked the same question twice in different ways and people are stuck helping you. This isn't an answer as such, as I don't really know the question, but hopefully this might either help you find the answer or ask the question differently so people can help you.

Let's start with your statement:

escaping means returning from function just like return statement

and you've referred to using @escaping in Swift. While the term escaping might be used in some language to refer to what you say it is not what it means in Swift at all.

It is reasonable to be confused over what it means in Swift, as it essentially makes what could/should be a hidden compiler optimisation visible to the programmer in the language. The definition in Swift is:

A closure is said toescape a function when the closure is passed as an argument to the function, but is called after the function returns. When you declare a function that takes a closure as one of its parameters, you can write @escaping before the parameter's type to indicate that the close is allowed to escape.

One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn't called until the operation is completed – the closure needs to escape, to be called later.

The Swift Programming Language (Swift 4.2)

What this is telling you is that @escaping affects how the closure may be stored and used, not what the closure itself actually does when called. When invoked a closure does the same operations regardless of whether it is marked as @escaping or not.

Moving on, the example used to illustrate @escaping has relevance to what appears to be your situation – you apparently wish to have a method, say A, initiate an asynchronous operation, say *B**, passing it a closure, say C, which when invoked later will cause A to return. That is impossible as when C is invade there is no invocation of A to return from. Look at the example again, emphasis added:

One way that a closure can escape is by being stored in a variable that is defined outside the function. As an example, many functions that start an asynchronous operation take a closure argument as a completion handler. The function returns after it starts the operation, but the closure isn't called until the operation is completed

After A has started B it returns, by the time C is invoked the invocation of A which started B has already returned. You are apparently asking for the impossible!

So what might be you trying to do?

Your intent might be to make A and the asynchronous operation it starts B appear as a single synchronous unit and for A not to return until B has done its work.

There are rare cases when wrapping asynchronicity as synchronous operations is required, and many more cases where people attempt to do it to make asynchronicity easier to handle but who end up destroying all the benefits of asynchronicity in the process. To do such wrapping often looks deceptively simple; but unless you have a good grasp of the GCD block model, semaphores, threads, blocking and deadlock it holds traps for the unwary.

If your intent is too try to wrap asynchronicity the better route is to embrace it instead, in your case figure out how to make your closure C do what is needed when it has been called asynchronously longer after the corresponding invocation of your method A has terminated and is no more. Thirty years ago asynchronicity was the esoteric end of day-to-day programming, today it is at its core, you need to understand and use it.

If after trying to embrace asynchronicity you decide you have one of those rare cases when it needs to hidden inside of a synchronous wrapper do a search on SO for asynchronous, semaphore etc. and you should find a solution.

If you get stuck with asynchronicity, or are actually asking about something completely different, ask a new question, show what you've done/tried/etc., and someone will undoubtedly help you take the next step.

HTH



来源:https://stackoverflow.com/questions/52578822/how-to-write-escaping-completion-handler-in-objective-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!