Warum kann das Schlüsselwort "schwach" nur auf Klassen- und klassengebundene Protokolltypen angewendet werden?


74

Wenn ich Variablen wie weakin Swift deklariere , erhalte ich manchmal die Fehlermeldung von Xcode:

'schwach' kann nur auf klassen- und klassengebundene Protokolltypen angewendet werden

Ich habe mich nur gefragt, warum das Schlüsselwort weaknur auf Klassen- und klassengebundene Protokolltypen angewendet werden kann. Was ist der Grund dafür?


8
weaknur relevant ist , auf einen Referenzzähler und nur Klassen sind Referenz gezählt
dan

Antworten:


68

weakist ein Qualifikationsmerkmal für Referenztypen (im Gegensatz zu Werttypen wie structs und integrierten Werttypen).

Mit Referenztypen können Sie mehrere Referenzen auf dasselbe Objekt haben. Das Objekt wird freigegeben, wenn die letzte starke Referenz nicht mehr darauf verweist (schwache Referenzen zählen nicht).

Werttypen hingegen werden kopiert zugewiesen. Die Referenzzählung gilt nicht, daher ist der weakModifikator bei ihnen nicht sinnvoll.


128

Ein häufiger Grund für diesen Fehler ist, dass Sie Ihr eigenes Protokoll deklariert haben, aber vergessen haben, von Folgendes zu erben AnyObject:

protocol PenguinDelegate: AnyObject {
    func userDidTapThePenguin()
}

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

Der obige Code gibt Ihnen den Fehler, wenn Sie vergessen haben, von zu erben AnyObject. Der Grund dafür ist, dass dies weaknur für Referenztypen (Klassen) sinnvoll ist. Sie machen den Compiler also weniger nervös, indem Sie klar angeben, dass das PenguinDelegate für Klassen und nicht für Werttypen bestimmt ist.


1
Was ist der Vorteil des Erbens von NSObjectProtocol? Meine eigenen Delegierten tun das nicht und ich habe keine Probleme bei meiner Verwendung festgestellt
Apostolos Apostolidis

3
@Apostolos Schwache Referenzen sind nur in Klassen gültig. Durch das Erben von NSObjectProtocol garantieren Sie dem Compiler, dass das Protokoll nur für Klassen (und nicht für Aufzählungen usw.) verwendet wird.
Vince O'Sullivan

@ VinceO'Sullivan Was ist der Vorteil, dies dem Compiler zu garantieren? Ist es nicht einfacher, einfach nicht zu erben NSObjectProtocol? Zum einen müssen Sie sich nicht mit dem Hinzufügen des weakModifikators befassen .
Yesthisisjoe

12
Ja, es funktioniert. Aber du weißt nicht warum. weakist ein Qualifikationsmerkmal für Referenztypen und macht bei Werttypen keinen Sinn, da Werttypen per Definition nicht schwach sein können. Ein Protokoll kann von Referenztypen und Werttypen übernommen werden. Sie sollten es also so einschränken, dass es nur durch Referenztypen implementiert wird: protocol PenguinDelegate: class { }Hier beschränken Sie das Protokoll so, dass es nur durch NSObjectProtocols implementiert wird , die ebenfalls Referenztypen sind. Aus diesem Grund funktioniert es.
Martin

4
Verwendung, protocol PenguinDelegate: classdie nicht von einer Objective-C-Laufzeit abhängt, aber dennoch das Problem löst.
Feuermurmel

63
protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

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

Wenn Sie class nach Ihrem Protokoll eingeben, funktioniert dies ebenfalls und scheint geeigneter zu sein als für NSObjectProtocol.


Ich denke, die Kombination aus diesem und der Antwort von @dasblinkenlight würde diese Frage vollständig beantworten. dasblinkenlight erklärte, warum die Fehlermeldung angezeigt wird und wie Sie das erreichen, was Sie als Entwickler wahrscheinlich versucht haben.
Stuckj

14

Nun, nur für den Fall, dass jemand anderes denkt, dass Sie wie ich alles richtig in Ihrem Code haben, überprüfen Sie, ob Sie das nicht versehentlich durch :ein ersetzt haben =.

Hier ist was ich hatte. Es gab mir auch den gleichen Fehler wie oben:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

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

Aber der richtige Weg ist:

protocol PenguinDelegate: class {
    func userDidTapThePenguin()
}

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

Sehen Sie den Unterschied? Es dauerte eine Weile, bis ich sah, dass ich anstelle eines Doppelpunkts ein Gleichheitszeichen hatte. Beachten Sie auch, dass ich andere Fehler für dieselbe Zeile erhalten habe, da ich entschieden hatte, dass mein erster Fehler am wahrscheinlichsten das eigentliche Problem ist:

- weakdarf nur auf klassen- und klassengebundene Protokolltypen angewendet werden

: - <


5

Ich finde in einem Fall heraus, dass Sie sogar einen Klassentyp haben, aber trotzdem diese Fehlermeldung erhalten.

Zum Beispiel,

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

Hier wird ein UITextViewObjekt aus einem anonymen Block als Initialisierung von zurückgegeben var myText. Ich habe die gleiche Art von Fehlermeldung erhalten. Um das Problem zu beheben, varmuss das gekennzeichnet sein als lazy:

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

2

weakist für ARC (Automatic Reference Counting). Es bedeutet, keinen Referenzzähler hinzuzufügen. Also funktioniert es nur für Class. In Swift erhalten Sie einen optionalen Wert für die Sicherheit.


1

Ich habe versucht, Eigenschaften vom Typ String und Array für einen Abschluss zu erfassen. Ich habe folgende Fehler erhalten:

'schwach' darf nur auf klassen- und klassengebundene Protokolltypen angewendet werden, nicht auf '[String]'

'schwach' darf nur auf klassen- und klassengebundene Protokolltypen angewendet werden, nicht auf 'String'

Ich habe eine Weile auf dem Spielplatz gespielt, und es stellte sich heraus, dass es für diese Typen ausreicht, sich selbst einzufangen.


1

Geben Sie hier die Bildbeschreibung einIch habe die objektive C-Klasse schnell für eine scrolView verwendet. Ich habe das IBOutlet dieser Bildlaufansicht erstellt. Und beim Kompilieren von Code wurde dieser Fehler angezeigt.

Um dieses Problem zu beheben, importieren Sie diese Klasse in Ihren Bridging-Header

"YourClass.h" importieren

Ich habe Xcode 9.2 mit Swift 3.2 verwendet



0

weakFunktioniert nur für den Referenztyp, sodass Xcode einen Fehler meldet, wenn Sie von struct(anstelle von class) anrufen .


0
  1. schwach ist nicht für Werttyp.
  2. schwach kommt nur für die Klasse ins Bild.

"schwach" kann alles anwenden, was von klassen- oder klassengebundenen Protokolltypen geerbt wird

  1. Klassenprotokoll: Protokoll ViewControllerDelegate: Klasse {func getInformationk (Wert: String?)}
  2. NSObjectProtocol:

    Protokoll ViewControllerDelegate: NSObjectProtocol {func getInformation (Wert: String?)}


Können Sie uns etwas mehr erklären?
Dieter Meemken
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.