如何在'pure' Swift中创建弱协议引用(没有@objc)

1szpjjfi  于 2023-01-19  发布在  Swift
关注(0)|答案(8)|浏览(122)

weak引用在Swift中似乎不起作用,除非protocol被声明为@objc,这在纯Swift应用中是不希望的。
此代码给出编译错误(weak不能应用于非类类型MyClassDelegate):

class MyClass {
  weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate {
}

我需要用@objc作为协议的前缀,这样它就可以工作了。
问:完成weakdelegate的“纯粹”快速方法是什么?

b0zn9rqh

b0zn9rqh1#

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

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

class SomeClass {
    weak var delegate: ProtocolNameDelegate?
}

使用AnyObject时,您会说只有类可以遵循此协议,而结构体或枚举则不能。

omvjsjqw

omvjsjqw2#

补充回答

委托是否应该是弱引用,我一直很困惑,最近我对委托有了更多的了解,什么时候使用弱引用,所以为了将来的读者,我在这里补充几点。

  • 使用weak关键字的目的是避免强引用循环(保留循环)。强引用循环发生在两个类示例对彼此有强引用时。它们的引用计数永远不会变为零,因此它们永远不会被释放。
  • 只有当委托是一个类时才需要使用weak,Swift结构体和枚举是值类型(当创建新示例时,它们的值会被复制),而不是引用类型,因此它们不会产生强 reference 循环。
  • weak引用始终是可选的(否则您将使用unowned),并且始终使用var(而不是let),以便在释放可选引用时可以将其设置为nil
  • 父类自然应该有一个对子类的强引用,因此不使用weak关键字,但是当子类需要一个对父类的引用时,它应该使用weak关键字使其成为弱引用。
  • weak应该在你需要引用一个你不拥有的类时使用,而不仅仅是一个引用其父类的子类。当两个非层次的类需要相互引用时,选择一个弱类。你选择的那个弱类取决于具体情况。更多信息请参见this question的答案。
    *一般来说,委托应该标记为weak,因为大多数委托引用的类不是它们自己的。当子级使用委托与父级通信时,这是绝对正确的。文档建议对委托使用弱引用。(但也请参见this。)
  • 协议可以用于reference types(类)和value types(结构体、枚举)。因此,在可能需要使委托弱的情况下,必须使其成为仅对象协议。方法是将AnyObject添加到协议的继承列表中。(过去使用class关键字,而不是AnyObject is preferred now。)
protocol MyClassDelegate: AnyObject {
    // ...
}

class SomeClass {
    weak var delegate: MyClassDelegate?
}

进一步研究

阅读下面的文章帮助我更好地理解了这一点,他们还讨论了一些相关的问题,比如unowned关键字和闭包中的强引用循环。

相关

2nbm6dog

2nbm6dog3#

AnyObject是Swift中使用弱引用的官方方式。

class MyClass {
    weak var delegate: MyClassDelegate?
}

protocol MyClassDelegate: AnyObject {
}

来自苹果:
若要防止强引用循环,应将委托声明为弱引用。有关弱引用的详细信息,请参阅类示例之间的强引用循环。将协议标记为仅限类以后将允许您声明委托必须使用弱引用。通过从AnyObject继承将协议标记为仅限类,如仅限类协议中所述。
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276

eufgjt7s

eufgjt7s4#

**更新:**看起来手册已经更新了,我提到的例子已经被删除了。参见上面对@flainez答案的编辑。
**Original:**使用@objc是正确的方法,即使你没有与Obj-C互操作。它确保你的协议被应用到类而不是枚举或结构。参见手册中的“检查协议一致性”。

8tntrjer

8tntrjer5#

弱限定符仅适用于引用对象。除非在协议上添加@objcAnyObjectclass限定符,否则符合协议的对象可能不是引用对象。
因此,您需要这些限定符中的一个(并且推荐使用AnyObject,因为class预计将被弃用)。
顺便说一下,注意有时候需要在类和属性中添加@objc,即使是在“纯Swift”应用程序中也是如此。这与开发语言无关。它使编译器以与Objective-C运行时兼容的方式构建代码,这是一些操作系统接口所必需的(例如target/action和旧式键路径)

3b6akqbq

3b6akqbq6#

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"
baubqpgj

baubqpgj7#

协议必须是AnyObject类的子类

示例如下

protocol NameOfProtocol: class {
   // member of protocol
    }
   class ClassName: UIViewController {
      weak var delegate: NameOfProtocol? 
    }
yizd12fk

yizd12fk8#

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

public protocol UIScrollViewDelegate : NSObjectProtocol {
   ...
}

这对我来说也很有效,并且消除了我在尝试实现自己的委托模式时看到的错误。

相关问题