为什么关键字“弱”仅适用于类和类绑定协议类型


74

当我weak在Swift中声明变量时,有时会从Xcode收到错误消息:

“弱”仅可应用于类和类绑定协议类型

我只是想知道为什么关键字weak只能应用于类和类绑定的协议类型?背后的原因是什么?


8
weak仅与引用计数有关,并且仅对类进行引用计数

Answers:


70

weak是引用类型的限定符(与值类型相对,例如structs和内置值类型)。

引用类型使您可以对同一对象有多个引用。当最后一个强引用停止引用该对象时,该对象将被释放(弱引用不计算在内)。

另一方面,值类型是通过副本分配的。引用计数不适用,因此weak修饰符对它们没有意义。


128

发生此错误的一个常见原因是您已经声明了自己的协议,但是却忘记继承自AnyObject

protocol PenguinDelegate: AnyObject {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

如果您忘记继承,上面的代码将给您错误AnyObject。原因是weak仅对引用类型(类)有意义。因此,您可以通过清楚地指出PenguinDelegate用于类而不是值类型,来减轻编译器的紧张感。


1
从NSObjectProtocol继承的优点是什么?我自己的代表不这样做,我在使用中也没有遇到任何问题
Apostolos Apostolidis

3
@Apostolos弱引用仅在类中有效。通过从NSObjectProtocol继承,您向编译器保证该协议仅用于类(而不用于枚举等)。
文斯·奥沙利文

@ VinceO'Sullivan向编译器保证这样做的好处是什么?仅仅不继承就不容易NSObjectProtocol吗?对于一个,您不必处理添加weak修饰符。
yesthisisjoe

12
是的,它有效。但是你不知道为什么。weak是引用类型的限定符,对值类型没有意义,因为值类型在定义上不能弱。引用类型值类型可以采用协议。因此,您应该限制它只能由引用类型实现:protocol PenguinDelegate: class { }在这里,您要限制协议仅由NSObjectProtocols实现,而s也是引用类型,这就是它起作用的原因。
马丁

4
使用protocol PenguinDelegate: class不依赖于Objective-C运行时,但仍然可以解决问题。
Feuermurmel

63
protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

如果在协议后键入class,那么它也可以正常工作,并且看起来更适合NSObjectProtocol。


我觉得这与@dasblinkenlight的答案相结合将完全回答这个问题。dasblinkenlight解释了为什么显示错误消息,并解释了如何实现作为开发人员可能要做的事情。
stickj

14

好了,以防万一别人认为你有你的代码像我的一切正确,请确认您没有误更换了:通过=

这就是我所拥有的。这也给了我与上面相同的错误:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate = PenguinDelegate?
}

但是正确的方法是:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

class MyViewController: UIViewController {
    weak var delegate: PenguinDelegate?
}

你看得到差别吗?我花了一段时间才看到我有一个等号而不是冒号。另请注意,由于我已确定我的第一个错误似乎最有可能是真正的问题,因此我在同一行上确实遇到了其他错误:

-weak只能应用于类和类绑定协议类型

:-<


5

我发现在一种情况下,您甚至拥有类类型,但仍然收到此错误消息。

例如,

class MyVC: UIViewController {
   var myText: UITextView = {
      [weak self]
      let text = UITextView()
      // some codes using self
      return text
   }()
}

在此,UITextView从匿名块返回一个对象,作为的初始化var myText。我收到了相同类型的错误消息。要解决此问题,var必须将其标记为lazy

class MyVC: UIViewController {
   lasy var myText: UITextView = {
      [weak self]
      let text = UITextView()
      // some codes using self
      return text
   }()
}

2

weak适用于ARC(自动参考计数)。这意味着不添加参考计数。因此,它仅适用于Class。在Swift中,您将获得可选的安全性值。


1

我尝试捕获String和Array类型的属性以进行关闭。我收到这些错误:

“弱”仅可应用于类和类绑定的协议类型,而不能应用于“ [String]”

“弱”仅适用于类和类绑定的协议类型,不适用于“字符串”

我在操场上玩了一段时间,结果证明,捕捉自我足以应付这些类型的人。


1

在此处输入图片说明我正在迅速地将目标C类用于scrolView。我创建了该滚动视图的IBOutlet。在编译代码时,此错误开始显示。

因此,要解决此类问题,请在桥接标头中导入该类

导入“ YourClass.h”

我正在将Xcode 9.2与Swift 3.2一起使用



0

weak仅适用于引用类型,因此,如果您从struct(而不是class)进行调用,则Xcode将报告错误。


0
  1. 弱不适用于值类型。
  2. 弱者只出现在全班。

“弱”可以应用从类或类绑定协议类型继承的任何东西

  1. 类协议:协议ViewControllerDelegate:类{func getInformationk(value:String?)}
  2. NSObjectProtocol:

    协议ViewControllerDelegate:NSObjectProtocol {func getInformation(value:String?)}


你能解释更多吗?
Dieter Meemken
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.