Compiler-Fehler: Die Methode mit dem Objective-C-Selektor kollidiert mit der vorherigen Deklaration mit demselben Objective-C-Selektor

Ich beginne Swift zu lernen und habe die sehr guten Videovorlesungen der Stanford University auf YouTube verfolgt. Hier ist ein Link, wenn Sie interessiert sind oder es hilft (obwohl es nicht erforderlich ist, mein Problem zu verstehen):

Entwicklung von iOS 8 Apps mit Swift – 2. Mehr Xcode und Swift, MVC

Während ich den Vorlesungen folgte, kam ich zu einem Punkt, wo (soweit ich das beurteilen konnte) mein Code mit dem Code im Video identisch war, aber auf meinem System habe ich einen Compilererrors bekommen. Nach vielen Versuchen habe ich meinen Code auf zwei Beispiele reduzieren können, von denen einer einen Fehler erzeugt, der andere oder nicht, aber ich habe keine Ahnung, was den Fehler verursacht oder wie er getriggers werden kann.

Der Code, der den Fehler verursacht, ist:

import UIKit class BugViewController: UIViewController { func perform(operation: (Double) -> Double) { } func perform(operation: (Double, Double) -> Double) { } } 

Dies erzeugt den folgenden Compilererrors:

Methode ‘performe’ mit Objective-C-Selektor ‘perform:’ führt zu Konflikten mit früheren Deklarationen mit demselben Objective-C-Selektor

Durch einfaches Entfernen der Unterklasse von UIViewController kompiliert der Code:

 import UIKit class BugViewController { func perform(operation: (Double) -> Double) { } func perform(operation: (Double, Double) -> Double) { } } 

Einige andere Informationen, die relevant sein können oder nicht:

  • Ich habe kürzlich auf Yosemite aktualisiert.
  • Als ich Xcode installiert habe, hatte ich eine Beta-Version (Version 6.3 (6D543q)), weil (wenn ich mich richtig erinnere) diese Version für meine Version von OS X benötigt wurde.

Ich hoffe, dass das ein Fehler im Compiler ist, weil das sonst für mich keinen Sinn ergibt. Jede Hilfe wurde sehr dankbar angenommen!

Objective-C unterstützt das Überladen von Methoden nicht, Sie müssen einen anderen Methodennamen verwenden. Wenn Sie UIViewController geerbt haben, haben Sie NSObject geerbt und die class interoperabel zu Obj-C gemacht. Auf der anderen Seite unterstützt Swift das Überladen, deshalb funktioniert es, wenn Sie die inheritance entfernen.

Ich selbst nehme auch den Standford-Kurs, und auch hier blieb ich lange stecken, aber nach einigem Suchen habe ich etwas von hier gefunden: Xcode release notes und es wurde etwas erwähnt:

Swift 1.2 ist strikt gegen das typenbasierte Überladen von @objc-Methoden und -Initializern, etwas, das nicht von Objective-C unterstützt wird.

 // Has the Objective-C selector "performOperation:". func performOperation(op: NSOperation) { /* do something */ } // Also has the selector "performOperation:". func performOperation(fn: () -> Void) { self.performOperation(NSBlockOperation(block: fn)) } 

Dieser Code würde funktionieren, wenn er von Swift aufgerufen wird, könnte aber leicht abstürzen, wenn er von Objective-C aufgerufen wird. Um dieses Problem zu lösen, verwenden Sie einen Typ, der nicht von Objective-C unterstützt wird, um zu verhindern, dass der Swift-Compiler das Member der Objective-C-Laufzeit aussetzt:

  • Wenn es sinnvoll ist, markieren Sie das Mitglied als privat, um den Rückschluss auf @objc zu deaktivieren.
  • Andernfalls verwenden Sie einen Dummy-Parameter mit einem Standardwert, z. B .: _ nonobjc: () = (). (19826275)

Überschreibungen von Methoden, die Objective-C in privaten Unterklassen ausgesetzt sind, werden nicht als @objc bezeichnet, was zum Absturz des Swift-Compilers führt. Fügen Sie explizit das @objc-Attribut zu solchen überschreibenden Methoden hinzu. (19935352)

Symbole aus SDKs sind nicht verfügbar, wenn Sie Open Quickly in einem Projekt oder Arbeitsbereich verwenden, der Swift verwendet. (20349540)

Was ich getan habe, war einfach “privat” vor der Override-Methode wie folgt hinzuzufügen:

  private func performOperation(operation: Double -> Double) { if operandStack.count >= 1 { displayValue = operation(operandStack.removeLast()) enter() } } 

Wie bereits erwähnt, unterstützt ObjC kein Überladen von Methoden (zwei Methoden mit demselben Namen) und In swift 2 unter Xcode 7 gibt es zwei Möglichkeiten, um diese Art von Problemen zu lösen. Eine Möglichkeit besteht darin, die Methode mit dem folgenden Attribut umzubenennen: @objc(newNameMethod:)

 func methodOne(par1, par2) {...} @objc(methodTwo:) func methodOne(par1) {...} 

Eine weitere Möglichkeit, dieses Problem in Xcode 7+ zu lösen, besteht @nonobjc Attribut @nonobjc auf jede Methode, jeden Index oder Initialisierer anzuwenden

 func methodOne() {...} @nonobjc func methodOne() {...} 

Das Problem ist, dass UIViewController eine @objc class ist. Beim Erben von UIViewController ist BugViewController auch eine @objc class.

Das bedeutet, dass es den Regeln von Objective-C-Selektoren (dem Namen einer Methode) entsprechen muss. Die Methoden func perform(operation: (Double) -> Double) und func perform(operation: (Double, Double) -> Double) beide den gleichen Selektor @selector(perform:) . Das ist nicht erlaubt.

Um dies zu beheben, verwenden Sie verschiedene Namen: wie func perform1(operation: (Double) -> Double) und func perform2(operation: (Double, Double) -> Double) .


Ich denke, der beste Weg, um damit umzugehen, ist, Ihren perform() Methoden beschreibende Namen zu geben. Was machen diese Methoden? Wie ändern sie den Zustand des View-Controllers? Sehen Sie sich die anderen UIViewController Methoden an, um ein Gefühl für den Stil der Methodenbenennung zu erhalten, oder lesen Sie, UIViewController Methodennamen innerhalb einer class UIViewController und eindeutig sein sollten

Von https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html unter “Xcode 6.3 Release Notes” -> “Swift Language Changes” finden Sie

Swift erkennt nun Diskrepanzen zwischen Überladung und Übersteuerung im Swift-System und das effektive Verhalten, das über die Objective-C-Laufzeit beobachtet wird.

Ich habe denselben Fehler, weil ich zwei Methoden mit der gleichen Obj-C-Signatur habe:

 static func prepareForUpSyncing(obj : NSManagedObject!) -> Bool static func prepareForUpSyncing(objs : [NSManagedObject]!) -> Bool 

Ich wollte keinen von ihnen als @nonobjc wegen der Möglichkeit unvorhergesehener Konsequenzen zur Laufzeit markieren. (Jemand kann mich korrigieren, wenn es keine Möglichkeit gibt)

Getriggers wurde es durch die Verwendung der externen Parameternamensfunktion von Swift (ich habe den externen Namen wie den lokalen Namen gemacht) für die zweite Methode, die die Signatur der Obj-c-Methode effektiv ändert:

 static func prepareForUpSyncing(objs objs : [NSManagedObject]!) -> Bool {