Swift委托 - 在何时使用弱引用委托

10 浏览
0 Comments

Swift委托 - 在何时使用弱引用委托

有人能解释一下在Swift中什么时候使用弱引用来指向代理指针,什么时候不使用吗?为什么?

我理解如果你使用的协议没有定义为类,则不能,也不想使用弱引用来指向你的代理指针。

protocol MyStructProtocol{
    //whatever
}
struct MyStruct {
    var delegate: MyStructProtocol?
}

然而,当您的协议定义为类类型协议时,您想要将您的代理设置为弱引用指针吗?

protocol MyClassProtocol: class{
    //whatever
}
class MyClass {
    weak var delegate: MyClassProtocol?
}

我说的对吗?在Apple的Swift指南中,类协议示例没有使用弱引用分配,但是在我的测试中,如果我的代理没有弱引用,我会看到强引用循环。

admin 更改状态以发布 2023年5月20日
0
0 Comments

正如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将避免强引用循环。

0
0 Comments

通常情况下,你要把类协议设为 weak 来防止产生“强引用循环”(曾被称为“保留循环”)。(注意,现在我们通过将 AnyObject 协议加入协议的继承列表中来实现这一点;参见 仅类协议。我们不再使用 class 关键字。)不将委托设为 weak 并不意味着你 inherently 有一个强引用循环,只是表示你可能会有一个。

然而,在 struct 类型中,强引用循环的风险大大降低,因为 struct 类型不是“引用”类型,所以很难产生强引用循环。但是,如果委托对象是一个类对象,那么你可能需要把协议设为类协议,并将它设为弱引用。

在我看来,将类委托设为 weak 部分是为了减少强引用循环的风险。它也关乎所有权的问题。大多数委托协议都是指物体没有任何权利声称对委托的所有权,而只是物体提供了通知委托某些事情(或请求某些事情)的能力。例如,如果你想让一个视图控制器拥有一些文本字段委托方法,那么文本字段就没有权利声称对视图控制器拥有所有权。

0