web-dev-qa-db-ja.com

AnyObjectに拡張機能を追加する方法はありますか?

Objective-Cでは、実行時に任意のキー/値のペアを任意のNSObjectに追加する機能を追加するNSObjectの非常に便利なカテゴリ(拡張、Swift用語))を作成しました。可変ディクショナリをオブジェクトにアタッチするオブジェクト。次に、そのディクショナリとの間でキーと値のペアを取得/設定するgetメソッドとsetメソッドを提供します。コードは数行です。

これにより、システムによって作成されたオブジェクトを含む、実行時に任意のキーと値のペアを任意のオブジェクトにアタッチできます。それが鍵です。システムフレームワークがオブジェクトを返し、それに値を付加できるようにする必要がある場合があります。

このトリックにより、新しいインスタンス変数を持つカテゴリを作成することもできます。 (実際にはそうではありませんが、カテゴリ内のオブジェクトに新しい状態変数を追加できます。)

Swift 1.2では、これは不可能です。理由は次のとおりです。

  • Swiftには、Objective-CのNSObjectのようなすべてのオブジェクトの基本クラスがありません。プロトコルであるAnyObjectを使用します。
  • Swift 1.2では、プロトコルの拡張は許可されていません。

Swift 1.2の下でこれをあきらめなければなりませんでした。

しかし、Swift 2ではプロトコルの拡張が可能です。「これで、キーと値のペアをAnyObjectに追加できる拡張機能を追加できるようになりました!」と思いました。

喜びはありません。

AnyObjectの拡張機能を作成しようとすると、次のようになります。

extension AnyObject: AssociatedObjectProtocol

エラーメッセージが表示されます

「AnyObject」プロトコルは拡張できません

ああ!とても近いですが、違います。言語はAnyObjectの拡張を明示的に禁止しているようです。これはなぜですか、それを回避する方法はありますか?

NSObjectで自分のカテゴリを頻繁に使用することはありませんが、使用すると命の恩人になります。 Swiftのトリックバッグに追加したいと思います。

Objective-Cの場合と同じようにNSObjectに追加できますが、これはNSObjectから継承したオブジェクトに対してのみ機能することを意味し、ネイティブSwiftクラスでは機能しません。

15
Duncan C

残念ながら、あなたが望むのとまったく同じことをする回避策は存在しません。したがって、デフォルトの実装を追加するための拡張機能を備えたプロトコルを作成することをお勧めします。

protocol A: AnyObject {}

// in Swift you would rather use this
protocol A: class {}

// add default implementations
extension A {
    func aMethod() {
        // code
    }
}

// Example
class B: A {}

// use the method
B().aMethod()

このアプローチでは、すべてのクラスがこのプロトコルに自動的に準拠するわけではありません(ただし、クラスのみがこのプロトコルに準拠できます)。したがって、それらを自分で適合させる必要があります。これをあまり使用しないので、これは合理的な解決策になります。

13
Qbyte

@Qbyteの答えに沿って、NSObjectがプロトコルに準拠していることを宣言することは、Cocoa/UIKit/Foundationユニバース全体のほぼすべてのクラスがその機能を継承することを意味します。

protocol MyProtocol {
    func doSomething()
}

extension MyProtocol {
    func doSomething() {
        print("This is me, doing something.")
    }
}

extension NSObject: MyProtocol { }

Appleのフレームワーククラスの99%をMyProtocolに適合させました。 MyProtocolから継承するか、単に準拠することで、独自のクラスをNSObjectに準拠させることができます。

6
Aaron Rasmussen