弱引用似乎在Swift中不起作用,除非协议声明为@objc,这是我不希望在纯Swift应用程序中使用的。

这段代码给出了一个编译错误(weak不能应用于非类类型MyClassDelegate):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

我需要用@objc作为协议的前缀,然后它就可以工作了。

问:完成弱委托的“纯”Swift方式是什么?


当前回答

补充回答

我总是困惑于委托是否应该是弱的。最近,我了解了更多关于委托和何时使用弱引用的知识,因此,为了将来的观众,让我在这里补充一些要点。

The purpose of using the weak keyword is to avoid strong reference cycles (retain cycles). Strong reference cycles happen when two class instances have strong references to each other. Their reference counts never go to zero so they never get deallocated. You only need to use weak if the delegate is a class. Swift structs and enums are value types (their values are copied when a new instance is made), not reference types, so they don't make strong reference cycles. weak references are always optional (otherwise you would used unowned) and always use var (not let) so that the optional can be set to nil when it is deallocated. A parent class should naturally have a strong reference to its child classes and thus not use the weak keyword. When a child wants a reference to its parent, though, it should make it a weak reference by using the weak keyword. weak should be used when you want a reference to a class that you don't own, not just for a child referencing its parent. When two non-hierarchical classes need to reference each other, choose one to be weak. The one you choose depends on the situation. See the answers to this question for more on this. As a general rule, delegates should be marked as weak because most delegates are referencing classes that they do not own. This is definitely true when a child is using a delegate to communicate with a parent. Using a weak reference for the delegate is what the documentation recommends. (But see this, too.) Protocols can be used for both reference types (classes) and value types (structs, enums). So in the likely case that you need to make a delegate weak, you have to make it an object-only protocol. The way to do that is to add AnyObject to the protocol's inheritance list. (In the past you did this using the class keyword, but AnyObject is preferred now.) protocol MyClassDelegate: AnyObject { // ... } class SomeClass { weak var delegate: MyClassDelegate? }

进一步的研究

阅读下面的文章有助于我更好地理解这一点。他们还讨论了相关的问题,如无主关键字和闭包发生的强引用循环。

委托文件 快速文档:自动引用计数 “弱,强,无主,天哪!”- Swift参考指南 强,弱,和无主-整理ARC和Swift

相关的

如何在Swift中制作委托 iOS:如何在Swift中创建弱委托 Swift委托-何时在委托上使用弱指针

其他回答

苹果使用“NSObjectProtocol”而不是“class”。

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

这也适用于我,并删除了我在尝试实现自己的委托模式时所看到的错误。

补充回答

我总是困惑于委托是否应该是弱的。最近,我了解了更多关于委托和何时使用弱引用的知识,因此,为了将来的观众,让我在这里补充一些要点。

The purpose of using the weak keyword is to avoid strong reference cycles (retain cycles). Strong reference cycles happen when two class instances have strong references to each other. Their reference counts never go to zero so they never get deallocated. You only need to use weak if the delegate is a class. Swift structs and enums are value types (their values are copied when a new instance is made), not reference types, so they don't make strong reference cycles. weak references are always optional (otherwise you would used unowned) and always use var (not let) so that the optional can be set to nil when it is deallocated. A parent class should naturally have a strong reference to its child classes and thus not use the weak keyword. When a child wants a reference to its parent, though, it should make it a weak reference by using the weak keyword. weak should be used when you want a reference to a class that you don't own, not just for a child referencing its parent. When two non-hierarchical classes need to reference each other, choose one to be weak. The one you choose depends on the situation. See the answers to this question for more on this. As a general rule, delegates should be marked as weak because most delegates are referencing classes that they do not own. This is definitely true when a child is using a delegate to communicate with a parent. Using a weak reference for the delegate is what the documentation recommends. (But see this, too.) Protocols can be used for both reference types (classes) and value types (structs, enums). So in the likely case that you need to make a delegate weak, you have to make it an object-only protocol. The way to do that is to add AnyObject to the protocol's inheritance list. (In the past you did this using the class keyword, but AnyObject is preferred now.) protocol MyClassDelegate: AnyObject { // ... } class SomeClass { weak var delegate: MyClassDelegate? }

进一步的研究

阅读下面的文章有助于我更好地理解这一点。他们还讨论了相关的问题,如无主关键字和闭包发生的强引用循环。

委托文件 快速文档:自动引用计数 “弱,强,无主,天哪!”- Swift参考指南 强,弱,和无主-整理ARC和Swift

相关的

如何在Swift中制作委托 iOS:如何在Swift中创建弱委托 Swift委托-何时在委托上使用弱指针

您需要将协议的类型声明为AnyObject。

protocol ProtocolNameDelegate: AnyObject {
    // Protocol stuff goes here
}

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

使用AnyObject,你说只有类可以符合这个协议,而结构或枚举不能。

弱限定符仅适用于引用对象。除非在协议上添加@objc、AnyObject或类限定符,否则符合协议的对象可能不是引用对象。

因此,您需要这些限定符中的一个(建议使用AnyObject,因为预计不推荐使用class)。

顺便说一下,请注意,在你的类和属性中添加@objc有时是必需的,即使在“纯Swift”应用程序中也是如此。这与你的开发语言无关。它导致编译器以一种与Objective-C运行时兼容的方式构建代码,这对于某些操作系统接口(例如目标/动作和旧式键路径)是必需的。

protocol MyProtocol {
    func doSomething()
}

class MyClass: MyProtocol {
    func doSomething() {
        print("Doing something")
    }
}

var weakProtocol: Weak<MyProtocol>?
let myObject = MyClass()
weakProtocol = Weak(myObject)
weakProtocol?.doSomething() // Will print "Doing something"