如何存储闭包完成处理程序以供以后调用?

Posted

技术标签:

【中文标题】如何存储闭包完成处理程序以供以后调用?【英文标题】:How to store a Closure completion handler to call later? 【发布时间】:2014-09-05 21:09:41 【问题描述】:

我正在努力将这个 In-App Purchase tutorial 转换为 Swift,并在尝试保存完成处理程序时遇到了问题。我们需要存储这个完成处理程序,以便以后可以调用它。我无法弄清楚如何从参数中存储闭包的副本。具体来说,我认为我需要复制它,但 Xcode 声明该对象没有复制功能。

我是这样定义的:

typealias RequestProductsCompletionHandler = (success: Bool, products: NSArray) -> Void

在这里我为它声明一个属性:

var completionHandler: RequestProductsCompletionHandler?

这就是我需要将传入的完成处理程序存储到我的属性中的地方:

func requestProductsWithCompletionHandler(completionBlock: RequestProductsCompletionHandler) -> Void 
    //self.completionHandler = completionBlock.copy() //problem: RequestProductsCompletionHandler does not have a member named copy

这是 Obj-C 教程中的做法:

typedef void (^RequestProductsCompletionHandler)(BOOL success, NSArray * products);

RequestProductsCompletionHandler _completionHandler;

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler 
    _completionHandler = [completionHandler copy];

后来它是这样使用的:

_completionHandler(YES, skProducts);
_completionHandler = nil;

编辑:我已删除 .copy() 以防止错误(还必须使 NSArray 可选,以便以后可以将其设置为 nil )。我的问题是,如果不明确复制它,它会按预期工作吗?我不相信它会因为Apple stated closures are reference types。 这将存储对我不想做的原始闭包的引用。如何强制执行副本?

【问题讨论】:

【参考方案1】:

是的。它将按预期工作。

每当您调用requestProductsWithCompletionHandler 时,您都会创建一个闭包并将其传递给该函数。 正如您所提到的,当您设置 completionHandler 时,您实际上将其设置为对给定闭包的引用。

在 Objective C 中,要将块存储为 ivar,您必须复制一个块。这是因为一个块首先驻留在定义它的堆栈内存中。并将其复制到堆内存中以便可以使用

【讨论】:

我遇到了确切的问题,所以谢谢。在研究答案时,我在 Swift 文档中发现了这个:developer.apple.com/library/ios/documentation/Swift/Conceptual/…。我尝试添加 lazy 变量,但它给了我一个错误(变量没有初始化程序)。这会导致引用循环吗? @coopersita 如您提到的文档中所述,您应该为闭包定义“捕获列表”并指定“自我”是无主的。 [unowned self] in ... 谢谢@tsafrir,我也找到了这个***.com/questions/24320347/…

以上是关于如何存储闭包完成处理程序以供以后调用?的主要内容,如果未能解决你的问题,请参考以下文章

发出调用快速完成处理程序关闭的问题

Swift 闭包完成处理程序

iOS Swift 如何访问在完成处理程序闭包中创建的数据——在闭包之外

在 Swift 中遇到完成处理程序和闭包问题

Swift-使用完成处理程序更新闭包外的全局变量

如何存储用户的信息以供MySQL将来使用