如何从Objective-C中的异步内部函数内部返回外部函数
Posted
技术标签:
【中文标题】如何从Objective-C中的异步内部函数内部返回外部函数【英文标题】:How to return outer function from inside async inner function in Objective-C 【发布时间】:2018-09-30 17:04:04 【问题描述】:我想从内部异步内部函数中返回外部函数。 很快,我会为此目的使用完成处理程序,它会从函数中逃脱。但在 Objective-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语句一样。
【问题讨论】:
目前尚不清楚您在这里尝试做什么,特别是您使用术语 escaping 来表示什么。你暗示你知道如何在 Swift 中做你想做的事,如果你编辑你的问题(不要在 cmets 中这样做)并包含你的 Swift 版本的checkCompletionEscaping
并描述它的行为与 Objectove 有何不同,这将有所帮助- C 版。这将帮助人们帮助你。
@CRD 更新问题
您没有重现与 Objective-C 中相同的示例,不幸的是,您的 Swift 代码中的 @escaping
并不意味着“像 return 语句一样从函数返回”,而是完全不同的东西。您似乎在异步上下文中寻找类似 non-local goto 的东西,但我说 seem 因为您似乎在说您可以在 Swift 中做您想做的事情它缺乏这样的结构。所以要么我错过了明显的东西,要么你需要更清楚。搜索 SO 寻找关于等待异步函数结果的问题,这是一个常见的问题,你可能会找到你想要的。
这基本上是您几个小时前发布的previous question 的副本。请删除这两个问题之一并根据需要编辑另一个。
【参考方案1】:
更简单的方法是调用另一个告诉它已完成的函数。
-(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】:您似乎以不同的方式两次问了同一个问题,而人们却一直在帮助您。这不是一个答案,因为我真的不知道这个问题,但希望这可以帮助您找到答案或以不同的方式提出问题,以便人们可以帮助您。
让我们从你的陈述开始:
转义意味着从函数返回,就像 return 语句一样
你提到过在 Swift 中使用 @escaping
。虽然术语 escaping 可能在某些语言中用于指代您所说的内容,但它在 Swift 中根本不是这个意思。
混淆它在 Swift 中的含义是合理的,因为它本质上使可能/应该是隐藏的编译器优化对语言中的程序员可见。 Swift 中的定义是:
闭包被称为转义当闭包作为参数传递给函数时,但在函数返回后被调用。当您声明一个将闭包作为其参数之一的函数时,您可以在参数类型前写上
@escaping
,表示允许闭包转义。闭包可以逃逸的一种方法是将其存储在函数外部定义的变量中。例如,许多启动异步操作的函数将闭包参数作为完成处理程序。函数在开始操作后返回,但在操作完成之前不会调用闭包——闭包需要转义,稍后再调用。
Swift 编程语言 (Swift 4.2)
这告诉你@escaping
影响闭包的存储和使用方式,而不是闭包本身在调用时的实际作用。调用闭包时,无论是否标记为@escaping
,都会执行相同的操作。
继续,用于说明 @escaping
的示例与您的情况相关 - 您显然希望有一个方法,例如 A,启动异步操作,例如 *B **,给它传递一个闭包,比如 C,稍后调用它会导致 A 返回。这是不可能的,因为当 C 被入侵时,不会调用 A 来返回。再看例子,重点补充:
闭包可以逃逸的一种方法是将其存储在函数外部定义的变量中。例如,许多启动异步操作的函数将闭包参数作为完成处理程序。 函数开始操作后返回,但直到操作完成才调用闭包
在 A 启动 B 之后,它返回,当 C 被调用时,A 启动 B 已返回。你显然是在要求不可能的事!
那么你可能想做什么?
您的意图可能是使 A 和它启动的异步操作 B 显示为单个 同步 单元并为 A 在 B 完成工作之前不要返回。
很少在需要将异步包装为同步操作的情况下,还有更多的情况是人们试图这样做以使异步更易于处理,但最终破坏了异步的所有好处过程。做这样的包装通常看起来很简单;但除非你很好地掌握了GCD 块模型、信号量、线程、阻塞和死锁它为粗心的人设置了陷阱。
如果您的意图过于尝试包装异步性,那么更好的方法是接受它,在您的情况下,弄清楚如何让您的闭包 C 在异步调用更长的时间时执行所需的操作在您的方法 A 的相应调用终止并且不再存在之后。 30 年前,异步是日常编程的深奥结局,而今天它是其核心,您需要理解和使用它。
如果在尝试采用异步性之后,您决定遇到需要隐藏在同步包装器内的罕见情况之一,请在 SO 上搜索 异步、信号量 等等,你应该找到解决方案。
如果您遇到异步性,或者实际上是在问一些完全不同的问题,请提出一个新问题,展示您所做/尝试过的/等等,毫无疑问会有人帮助您下一步。
HTH
【讨论】:
“这不是这样的答案”,但已作为答案发布。 :D @GeneCode - 它超出了评论限制,只是一点点;-)以上是关于如何从Objective-C中的异步内部函数内部返回外部函数的主要内容,如果未能解决你的问题,请参考以下文章
如何从具有隐藏变量名称(参数前的_)或内部+外部(例如 foo(with bar:))的 Objective-C 调用 Swift 函数
node js - 当函数依赖于内部的异步函数时,如何从函数返回值
如何在同一框架内访问 Objective-C 中的内部 Swift 类?