Swift委托 - 何时在委托上使用弱指针

时间:2015-05-05 14:58:34

标签: swift delegates weak-references

有人可以解释何时以及何时不使用“弱”'分配给Swift中的委托指针,为什么?

我的理解是,如果你使用一个未定义为类的协议,你就不能也不想将你的委托指针分配给弱。

protocol MyStructProtocol{
    //whatever
}

struct MyStruct {
    var delegate: MyStructProtocol?
}

但是,当您的协议被定义为类类型协议时,您是否想要将您的委托设置为弱指针?

protocol MyClassProtocol:Class{
    //whatever
}

class MyClass {
    weak var delegate: MyClassProtocol?
}

我说错了吗?在Apple的快速指南中,类协议示例并没有使用弱分配,但在我的测试中,如果我的代表没有被弱引用,我会看到强大的参考周期。

4 个答案:

答案 0 :(得分:41)

您通常会将类协议(使用class关键字定义)设置为弱,以避免出现“强参考周期”(以前称为“保留周期”)的风险。如果没有让代表弱,并不意味着你本身就有一个强大的参考周期,而只是你可以拥有一个。

但是,对于struct类型,由于struct类型不是“引用”类型,因此强大的参考周期风险会大大减少,因此创建强引用周期更加困难。但是如果委托对象是一个类对象,那么你可能希望使协议成为类协议并使其变弱。

在我看来,让班级代表变弱只会部分地减轻强参考周期的风险。这真的是一个“所有权”的问题。大多数委托协议都是这样的情况:有问题的对象没有业务声明对委托的所有权,而仅仅是有关对象提供了向委托人通知某事(或请求某些东西)的能力。

答案 1 :(得分:7)

代表应该(编辑:一般)总是弱。

让我们说ba的代表。现在a delegate属性为b

如果您希望在b消失后c发布

如果c拥有对bc解除分配的强引用,则您希望bc取消分配。但是,在a中使用强委托属性,b永远不会被取消分配,因为a强烈要求b。使用弱引用时,只要b失去c的强引用,b就会在c deallocs时释放。{/ p>

通常这是预期的行为,这就是您希望使用weak属性的原因。

答案 2 :(得分:0)

罗布说:

  

这真的是“所有权”问题

是真的。 “强大的参考周期”就是正确地拥有所有权。

在下面的示例中,我们不使用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,但不是。所以这不是问题。但纯粹出于所有权原因,正如罗布所说here

  

在对象层次结构中,子对象不应维护对对象的强引用。那是一个红色标记,表示参考周期很强

因此,无论是否泄漏,仍应将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将避免强大的参考周期

答案 3 :(得分:-4)

protocol MyDelegate: class {
// ...
}
class MyViewController: UIViewController {
    weak var delegate: MyDelegate? 
}