目标C如何从异步内部函数内部返回外部函数

时间:2018-09-30 17:04:04

标签: objective-c completionhandler

我想从异步内部函数内部的外部函数返回。 很快,我会为此目的使用完成处理程序,该处理程序会从函数中逸出。但是在目标c中,完成处理程序实际上不会从函数中返回:

我的功能如下:

-(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");
}

如果我要使用swift,我可以使用完成处理程序轻松地从内部函数内部的外部函数返回:

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:转义意味着像return语句一样从函数中返回。

2 个答案:

答案 0 :(得分:0)

更简单的是调用另一个告诉它已完成的函数。

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

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

}

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

答案 1 :(得分:0)

您似乎已经以不同的方式问了同样的问题两次,人们一直在帮助您。这并不是一个答案,因为我并不真正知道这个问题,但是希望这可以帮助您找到答案或提出不同的问题,以便人们可以为您提供帮助。

让我们从您的陈述开始:

  

转义意味着像return语句一样从函数中返回

,您已经在Swift中提到使用@escaping。虽然转义一词在某种语言中可能用来指代您所说的,但这根本不是Swift中的意思。

对它在Swift中的含义感到困惑是合理的,因为它实质上使程序员可能/应该用该语言看到隐藏的编译器优化。 Swift中的定义是:

  当将闭包作为参数传递给函数时,

闭包被称为转义一个函数,但在函数返回后被调用。声明一个将闭包作为其参数之一的函数时,可以在参数的类型前写@escaping,以指示允许转义闭包。

     

闭包可以逃脱的一种方法是将其存储在函数外部定义的变量中。例如,许多启动异步操作的函数都将闭包参数用作完成处理程序。该函数在开始操作后返回,但是直到操作完成后才调用闭包–闭包需要转义,稍后再调用。

     

Swift编程语言(Swift 4.2)

这告诉您@escaping影响闭包的存储和使用方式,而不影响闭包本身在调用时的实际作用。不论闭包是否标记为@escaping,调用闭包都会执行相同的操作。

继续,用于说明@escaping的示例与您所处的情况有关–您显然希望有一个方法,例如 A ,启动一个异步操作,例如* B **,将其传递给闭包,例如 C ,稍后调用该闭包将导致 A 返回。这是不可能的,因为 C 被入侵时,没有 A 的调用要返回。再次查看示例,重点添加:

  

闭包可以逃脱的一种方法是将其存储在函数外部定义的变量中。例如,许多启动异步操作的函数都将闭包参数用作完成处理程序。 函数在开始操作后返回,但是直到操作完成才调用闭包

A 启动 B 后,它会返回,直到调用 C 时调用 B 开头的> A 已返回。您显然是在要求不可能!

那你想做什么?

您的意图可能是使 A 及其开始于 B 的异步操作显示为单个 synchronous 单元,对于 A B 完成工作之前不返回。

在许多情况下,由于需要同步操作而包装了异步性,因此还有很多情况,人们试图这样做以使异步性更易于处理,但最终却破坏了异步性的所有好处。过程。进行这种包装通常看起来很简单。但是除非您对 GCD块模型信号量线程阻止死锁,它为陷入困境的人提供陷阱。

如果您的意图太过尝试包装异步性,那么更好的方法是采用异步性,在您的情况下,请弄清楚如何使闭包 C 达到被异步调用更长时所需的功能在您的方法 A 的相应调用终止并且不再存在之后。三十年前,异步是日常编程的深奥终结,而今天,它已成为其核心,您需要了解和使用它。

如果尝试拥抱异步之后,您确定自己有一种罕见的情况需要隐藏在同步包装中,请在SO上搜索异步信号量等,您应该找到解决方案。

如果您陷入了异步性的境地,或者实际上是在问完全不同的事情,请提出一个新问题,表明您已做/尝试过的事情,等等,无疑会有人帮助您接受下一步。

HTH