Chr*_*sco 12 delegates closures ios swift
我正在使用网络请求类,我担心崩溃.例如,在将回调方法传递给函数时,使用闭包非常简单:
// some network client
func executeHttpRequest(#callback: (success: Bool) -> Void) {
// http request
callback(true)
}
// View Controller
func reload() {
networkClient.executeHttpRequest() { (success) -> Void in
self.myLabel.text = "it succeeded" // NOTE THIS CALL
}
}
Run Code Online (Sandbox Code Playgroud)
但是,由于应该执行回调的进程是异步的,当回调与容器类元素(在本例中是一个UIKit
类)交互时,它可能容易在类似的情况下崩溃
因此,当回调最终被触发时,self.myLabel.text
可能会导致崩溃,因为self
引用的View Controller 可能已经被释放.
到这一点.我是对的还是在内部快速实施某些内容以便永远不会发生这种情况?
如果我是正确的,那么当代理模式派上用场时,就像代理变量一样weak references
,这意味着,如果取消分配,它们不会保留在内存中.
// some network client
// NOTE this variable is an OPTIONAL and it's also a WEAK REFERENCE
weak var delegate: NetworkClientDelegate?
func executeHttpRequest() {
// http request
if let delegate = self.delegate {
delegate.callback(success: true)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意self.delegate
,由于它是a weak reference
,它将指向nil
View Controller(实现NetworkClientDelegate
协议的人)是否被释放,并且在这种情况下不调用回调.
我的问题是:闭包有什么特别的东西,使它们成为类似于这个场景的好选择,而不是回到委托模式?如果提供闭包的例子(由于nil指针而不会导致崩溃)将会很好.谢谢.
Cou*_*per 14
因此,当回调最终被触发时,self.myLabel.text可能会导致崩溃,因为自己所引用的View Controller可能已经被释放.
如果self
已导入的盖,很强的借鉴意义,可以保证self
将不会直到闭合已经执行完毕被释放了.也就是说,当调用闭包时,视图控制器仍处于活动状态 - 即使此时视图不可见.语句self.myLabel.text = "it succeeded"
将被执行,但即使标签不可见,也不会崩溃.
但是,有一个微妙的问题可能导致在某些情况下崩溃:
假设,闭包具有对视图控制器的最后且唯一的强引用.闭包完成,随后被取消分配,这也释放了对视图控制器的最后一个强引用.这不可避免地会调用dealloc
视图控制器的方法.该dealloc
方法将在将执行闭包的同一线程上执行.现在,视图控制器是一个UIKit
对象,必须保证发送到该对象的所有方法都将在主线程上执行.所以,IFF dealloc
实际上会在其他一些线程上执行,你的代码可能会崩溃.
一种合适的方法需要"取消"一个异步任务,当它被"关闭"时,视图控制器不再需要该结果.当然,这需要取消您的"任务".
为了减轻前一种方法的一些问题,在定义闭包时,可能会捕获视图控制器的弱引用而不是强引用.这不会阻止异步任务运行完成,但在完成处理程序中,您可以检查视图控制器是否仍然存活,并且如果它不再存在则只是挽救.
并且,如果你需要在一些可能在某个任意线程上执行的闭包中"保留"UIKit对象,请注意这可能是最后一个强引用,并确保在主线程上释放最后一个强引用.
编辑:
我的问题是:闭包有什么特别的东西,使它们成为类似于这个场景的好选择,而不是回到委托模式?
我想说,在许多用例中,闭包是"更好"的方法:
代理更容易出现循环引用而不是闭包之类的问题(因为它们由对象"拥有",并且此对象可能被捕获为委托中的变量).
闭包作为完成处理程序的经典用例还改进了代码的"局部性",使其更易于理解:您说明在调用任务的语句之后任务完成时会发生什么 - 无论可能需要多长时间.
闭包与常规"函数"的巨大优势在于闭包在定义时捕获整个"上下文".也就是说,它可以引用变量并在定义时将它们"导入"闭包 - 并在执行时使用它,无论何时发生,以及在定义时间的原始"堆栈"消失时已经.