web-dev-qa-db-fra.com

Pouvez-vous remplacer entre les extensions dans Swift ou non? (Le compilateur semble confus!)

Je travaille sur une application iOS dans Swift (une grande partie d’elle est déplacée d’Objective-C). J'utilise Core Data et j'essaie d'utiliser des extensions pour ajouter des fonctionnalités aux classes générées automatiquement à partir de mon modèle. Une chose que j’ai facilement faite dans Objective-C a été d’ajouter une méthode dans une catégorie de la classe A et de remplacer cette méthode dans une catégorie de la classe B (dérivée de A), et j’espérais faire de même dans Swift.

Depuis un moment, mon projet contient le code suivant (et ce n’est qu’un exemple), et bien que je n’ai pas encore utilisé la fonctionnalité, le compilateur a parfaitement fonctionné pour compiler ce code:

// 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
}

J'espère qu'un certain expert de Swift a déjà vu mon problème, mais voici comment j'ai découvert ceci: Récemment, j'ai essayé d'ajouter une fonctionnalité similaire en utilisant des méthodes qui ont des paramètres et/ou des valeurs qui ne sont pas des types intégrés, mais j'ai commencé à comprendre cela. erreur: les déclarations dans les extensions ne peuvent pas encore être remplacées.

Pour explorer ce problème, j’ai ajouté ce qui suit à l’un de mes fichiers Swift, pensant que la compilation serait parfaite:

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??
}

À ma grande surprise, j'ai reçu la même erreur de compilation (les déclarations dans les extensions ne peuvent pas encore être remplacées). Quoi? Mais j'ai déjà utilisé ce modèle plusieurs fois sans erreurs de compilation.

Questions: Premièrement, existe-t-il certaines règles relatives aux dépassements dans les extensions telles que dans certains cas, cela est supposé fonctionner mais que dans d’autres, ce n’est pas le cas? Deuxièmement (et plus déconcertant), pourquoi le compilateur Swift semble-t-il si inconsistant? Qu'est-ce que j'oublie ici? S'il vous plaît, aidez-moi à rétablir ma confiance en Swift.

METTRE À JOUR:

Comme indiqué dans la réponse correcte de Martin R, il semble que vous pouvez remplacer les méthodes de la version actuelle de Swift (1.1 via Xcode 6.1) tant qu'elles (1) impliquent uniquement des classes dérivées de NSObject et (2) n'utilisent pas l'inout modificateur. Voici quelques exemples:

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

Il semble que les méthodes et les propriétés de substitution d'une extension fonctionnent avec les méthodes et propriétés de Swift (Swift 1.1/Xcode 6.1) Current seulement. Compatible Objective-C

Si une classe est dérivée de NSObject, tous ses membres sont automatiquement disponiblesin Objective-C (si possible, voir ci-dessous). Donc avec

class A : NSObject { }

votre exemple de code est compilé et fonctionne comme prévu. Votre extension de données de code annulework car NSManagedObject est une sous-classe de NSObject.

Vous pouvez également utiliser l'attribut @objc pour une méthode ou une propriété:

class A { }

class B : A { }

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

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

Les méthodes qui ne sont pas représentables dans Objective-C ne peuvent pas être marquées avec @objc.__ et ne peuvent pas être remplacées dans une extension de sous-classe. Cela s'applique par exemple aux méthodes Ayant des paramètres inout ou des paramètres de type enum.

38
Martin R

J'ai vécu cela sur Xcode9. Fermer et rouvrir Xcode a fonctionné pour moi. Probablement un bug dans le compilateur.

0
Vincent