正如罗布所说:
这真的是一个“所有权”的问题
这是非常真实的。“强大的参考周期”就是要获得所有权。
在下面的示例中,我们没有使用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
将避免强引用循环