webentwicklung-frage-antwort-db.com.de

Können Sie die Erweiterungen in Swift außer Kraft setzen oder nicht? (Compiler scheint verwirrt!)

Ich habe in Swift an einer iOS-Anwendung gearbeitet (die meisten davon wurden von Objective-C verschoben). Ich verwende Core Data und versuche, Erweiterungen zu verwenden, um Klassen, die automatisch aus meinem Modell generiert wurden, mit Funktionen zu erweitern. In Objective-C habe ich ohne weiteres eine Methode in einer Kategorie der Klasse A hinzugefügt und diese Methode in einer Kategorie der Klasse B (die von A stammt) überschreiben können, und ich hatte gehofft, dasselbe in Swift zu tun.

Seit einiger Zeit habe ich den folgenden Code in meinem Projekt (und das ist nur ein Beispiel), und obwohl ich die Funktionalität noch nicht verwendet habe, hat der Compiler beim Kompilieren dieses Codes gut funktioniert:

// From CellType.Swift -- NOTE: Imports from Foundation and CoreData
@objc(CellType)
class CellType: NSManagedObject {
    @NSManaged var maxUses: NSNumber
    @NSManaged var useCount: NSNumber
    // Other properties removed for brevity
}


// From SwitchCellType.Swift -- NOTE: Imports from Foundation and CoreData
@objc(SwitchCellType)
class SwitchCellType: CellType {
    @NSManaged var targetCellXIndex: NSNumber
    @NSManaged var targetCellYIndex: NSNumber
    @NSManaged var targetCellType: CellType
    // Other properties removed for brevity
}


// From CellTypeLogic.Swift -- NOTE: Imports from Foundation and CoreData
extension CellType
{
    var typeLabel : String { get { return "Empty"; } }
    func isEqualToType(otherCellType : CellType) -> Bool
    {
        return (self.typeLabel == otherCellType.typeLabel &&
            self.maxUses.isEqualToNumber(otherCellType.maxUses) &&
            self.useCount.isEqualToNumber(otherCellType.useCount));
    }
    // Code removed for brevity
}


// From SwitchCellTypeLogic.Swift -- NOTE: Imports from Foundation and CoreData
extension SwitchCellType    // YES, this compiles with the overrides!
{
    override var typeLabel : String { get { return "Switch"; } }
    override func isEqualToType(otherCellType : CellType) -> Bool
    {
        var answer = false;
        if let otherSwitchCellType = otherCellType as? SwitchCellType
        {
            answer = super.isEqualToType(otherCellType) &&
                self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) &&
                self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) &&
                self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType);
        }
        return answer;
    }
    // Code removed for brevity
}

Ich hoffe, dass ein freundlicher Swift-Experte bereits mein Problem sieht, aber hier habe ich herausgefunden, wie ich es herausgefunden habe: Kürzlich habe ich versucht, eine ähnliche Funktionalität hinzuzufügen, indem Methoden verwendet werden, die Parameter und/oder Rückgabewerte enthalten, die nicht in Typen eingebaut sind Fehler: Deklarationen in Erweiterungen können noch nicht überschrieben werden.

Um dieses Problem zu untersuchen, fügte ich einer meiner Swift-Dateien Folgendes hinzu und dachte, es würde sich gut kompilieren lassen:

class A
{
}

class B : A
{
}

extension A
{
    var y : String { get { return "YinA"; } }
}

extension B
{
    override var  y : String { get { return "YinB"; } }  // Compiler error (see below) -- What??
}

Zu meiner Überraschung erhielt ich den gleichen Compiler-Fehler (Deklarationen in Erweiterungen können noch nicht überschrieben werden). Was? Aber ich habe dieses Muster schon mehrmals ohne Compilerfehler verwendet.

Fragen: Gibt es bestimmte Regeln für das Überschreiben in Erweiterungen, so dass sie in einigen Fällen funktionieren sollten, in anderen Fällen jedoch nicht? Zweitens (und beunruhigender) warum scheint der Swift-Compiler so inkonsistent zu sein? Was fehlt mir hier? Bitte hilf mir, meinen Glauben an Swift wiederherzustellen.

UPDATE:

Wie in der richtigen Antwort von Martin R angegeben, scheint es, als könnten Sie Methoden in der aktuellen Version von Swift (1.1 über Xcode 6.1) überschreiben, sofern (1) nur von NSObject abgeleitete Klassen verwendet werden und (2) das Inout nicht verwenden Modifikator. Hier einige Beispiele:

class A : NSObject { }

class B : A { }

class SubNSObject : NSObject {}
class NotSubbed {}
enum SomeEnum { case c1, c2; }

extension A
{
    var y : String { get { return "YinA"; } }
    func f() -> A { return A(); }
    func g(val: SubNSObject, test: Bool = false) { }

    func h(val: NotSubbed, test: Bool = false) { }
    func j(val: SomeEnum) { }
    func k(val: SubNSObject, inout test: Bool) { }
}

extension B 
{
    // THESE OVERIDES DO COMPILE:
    override var  y : String { get { return "YinB"; } }
    override func f() -> A { return A(); }
    override func g(val: SubNSObject, test: Bool) { }

    // THESE OVERIDES DO NOT COMPILE:
    //override func h(val: NotSubbed, test: Bool = false) { }
    //override func j(val: SomeEnum) { }
    //override func k(val: SubNSObject, inout test: Bool) { }

}
33
FTLPhysicsGuy

Es scheint, dass das Überschreiben von Methoden und Eigenschaften in einer Erweiterung mit den aktuellen Swift (Swift 1.1/Xcode 6.1) nur für Objective-C-kompatible .

Wenn eine Klasse von NSObject abgeleitet ist, sind alle ihre Mitglieder automatisch verfügbarin Objective-C (wenn möglich, siehe unten). Also mit

class A : NSObject { }

ihr Beispielcode wird kompiliert und funktioniert wie erwartet. Ihre Codedatenerweiterung überschreibtwork, da NSManagedObject eine Unterklasse von NSObject ist.

Alternativ können Sie das @objc-Attribut für eine Methode oder Eigenschaft verwenden:

class A { }

class B : A { }

extension A
{
    @objc var y : String { get { return "YinA" } }
}

extension B
{
   @objc override var y : String { get { return "YinB" } }
}

Methoden, die in Objective-C nicht darstellbar sind, können nicht mit @objc Markiert und in einer Unterklassenerweiterung nicht überschrieben werden. Dies gilt beispielsweise für Methoden mit inout-Parametern oder Parametern eines enum-Typs.

38
Martin R

Ich habe das auf Xcode9 erlebt. Xcode zu schließen und wieder zu öffnen, hat für mich funktioniert. Wahrscheinlich ein Fehler im Compiler.

0
Vincent