正如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在
这里所说:
在对象层次结构中,子对象不应该维护对父对象的强引用。这是一个红旗,表明存在强引用循环。
所以无论是否泄漏,仍然要为您的delegate对象使用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
可以避免强引用循环
protocol MyStructProtocol : class { ... }
,那么你可以将代理设为weak
。请参见 https://dev59.com/aGAf5IYBdhLWcg3w_W9j#24104371。 - Rob