web-dev-qa-db-ja.com

Swiftかどうかで拡張機能間でオーバーライドできますか?(コンパイラーは混乱しているようです!)

私はiOSアプリケーションでSwift(Objective-Cから移動されています)。CoreDataを使用し、拡張機能を使用してクラスに機能を追加しようとしています。 Objective-Cで簡単にしたことの1つは、クラスAのカテゴリにメソッドを追加し、クラスA(Aから派生)のカテゴリでそのメソッドをオーバーライドすることでした。同じことを望んでいましたスイフトで。

しばらくの間、プロジェクトに次のコードがあります(これはほんの一例です)。この機能はまだ使用していませんが、コンパイラはこのコードのコンパイルにうまく機能しました。

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

うまくいけば、ある種のSwift専門家はすでに私の問題を見ていますが、ここで私はそれを見つけた方法です:最近、そうではないパラメーターや戻り値を持つメソッドを使用して同様の機能を追加しようとしました組み込み型ですが、このエラーが発生し始めました:拡張機能の宣言はまだオーバーライドできません。

この問題を調査するために、次のコードをSwiftファイルに追加しました。

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

驚いたことに、同じコンパイラエラーを受け取りました(拡張機能の宣言はまだオーバーライドできません)。何?しかし、私は既にコンパイラエラーなしでそのパターンを数回使用しました。

質問:最初に、拡張機能のオーバーライドに関する特定のルールがあります。ある場合には機能するはずですが、そうでない場合はありますか? 2番目の(そしてより混乱させる)なぜSwiftコンパイラーはとても矛盾していますか?ここで何が欠けていますか?Swiftへの信頼を取り戻すのを手伝ってください。

更新:

Martin Rの正解に記されているように、NSObjectから派生したクラスのみを使用する限り、Swift(Xcode 6.1を介して1.1)の現在のバージョンのメソッドをオーバーライドできます(2)inout修飾子を使用しないでください。例をいくつか示します。

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

拡張機能のメソッドとプロパティのオーバーライドは、現在のSwift(Swift 1.1/Xcode 6.1)でObjective-C互換メソッドとプロパティに対してのみ機能するようです。

クラスがNSObjectから派生している場合、そのすべてのメンバーはObjective-Cで自動的に利用可能です(可能であれば、以下を参照)。だから

class A : NSObject { }

サンプルコードがコンパイルされ、期待どおりに動作します。 NSManagedObjectNSObjectのサブクラスであるため、Code Data拡張機能が機能をオーバーライドします。

または、メソッドまたはプロパティに@objc属性を使用できます。

class A { }

class B : A { }

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

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

Objective-Cで表現できないメソッドは、@objcでマークできず、サブクラス拡張でオーバーライドできません。たとえば、inoutパラメーターまたはenum型のパラメーターを持つメソッドに適用されます。

38
Martin R

Xcode9でこれを経験しました。 Xcodeを閉じて再度開くとうまくいきました。おそらくコンパイラのバグ。

0
Vincent