Swift委托 - 在何时使用弱引用委托
Swift委托 - 在何时使用弱引用委托
有人能解释一下在Swift中什么时候使用弱引用来指向代理指针,什么时候不使用吗?为什么?
我理解如果你使用的协议没有定义为类,则不能,也不想使用弱引用来指向你的代理指针。
protocol MyStructProtocol{ //whatever } struct MyStruct { var delegate: MyStructProtocol? }
然而,当您的协议定义为类类型协议时,您想要将您的代理设置为弱引用指针吗?
protocol MyClassProtocol: class{ //whatever } class MyClass { weak var delegate: MyClassProtocol? }
我说的对吗?在Apple的Swift指南中,类协议示例没有使用弱引用分配,但是在我的测试中,如果我的代理没有弱引用,我会看到强引用循环。
正如Rob所说:
这真的是一个关于“所有权”的问题。
这很正确。“强引用循环”就是关于正确获取所有权的问题。
在下面的例子中,我们没有使用weak var
。 然而,这两个对象都会释放。 为什么?
protocol UserViewDelegate: class { func userDidTap() } class Container { let userView = UserView() let delegate = Delegate() init() { userView.delegate = delegate } deinit { print("container deallocated") } } class UserView { var delegate: UserViewDelegate? func mockDelegatecall() { delegate?.userDidTap() } deinit { print("UserView deallocated") } } class Delegate: UserViewDelegate { func userDidTap() { print("userDidTap Delegate callback in separate delegate object") } }
用法:
var container: Container? = Container() container?.userView.mockDelegatecall() container = nil // will deallocate both objects
内存所有权图(没有循环)
+---------+container +--------+ | | | | | | | | | | | | v v userView +------------------> delegate
为了创建强引用循环,循环需要完整。 delegate
需要指向container
,但它没有。所以这不是一个问题。 但纯粹出于所有权原因,正如Rob在这里所说:
在对象层次结构中,子对象不应该维护对父对象的强引用。 这是一个警示,表示存在强引用循环。
因此,无论是泄漏问题,您仍应使用weak
来处理您的代理对象。
在下面的例子中,我们没有使用weak var
。结果,这两个类都不会被释放。
protocol UserViewDelegate: class { func userDidTap() } class Container: UserViewDelegate { let userView = UserView() init() { userView.delegate = self } func userDidTap() { print("userDidTap Delegate callback by Container itself") } deinit { print("container deallocated") } } class UserView { var delegate: UserViewDelegate? func mockDelegatecall() { delegate?.userDidTap() } deinit { print("UserView deallocated") } }
用法:
var container: Container? = Container() container?.userView.mockDelegatecall() container = nil // will NOT deallocate either objects
内存所有权图(有循环)
+--------------------------------------------------+ | | | | + v container userview ^ | | | | | +------+userView.delegate = self //container+------+
使用weak var
将避免强引用循环。
通常情况下,你要把类协议设为 weak
来防止产生“强引用循环”(曾被称为“保留循环”)。(注意,现在我们通过将 AnyObject
协议加入协议的继承列表中来实现这一点;参见 仅类协议。我们不再使用 class
关键字。)不将委托设为 weak
并不意味着你 inherently 有一个强引用循环,只是表示你可能会有一个。
然而,在 struct
类型中,强引用循环的风险大大降低,因为 struct
类型不是“引用”类型,所以很难产生强引用循环。但是,如果委托对象是一个类对象,那么你可能需要把协议设为类协议,并将它设为弱引用。
在我看来,将类委托设为 weak
部分是为了减少强引用循环的风险。它也关乎所有权的问题。大多数委托协议都是指物体没有任何权利声称对委托的所有权,而只是物体提供了通知委托某些事情(或请求某些事情)的能力。例如,如果你想让一个视图控制器拥有一些文本字段委托方法,那么文本字段就没有权利声称对视图控制器拥有所有权。