Edited at

Swiftで既存のクラスに新たにプロパティを追加する方法

More than 5 years have passed since last update.


Swiftで既存のクラスに新たにプロパティを追加する方法

Objective-Cでも使えていましたランタイムAPI(俗にいう黒魔術)を使う事で、Swiftでも動的にプロパティを追加することが可能です。

Runtime API Reference URL


https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html


使用するランタイムAPIの関数


  • objc_setAssociatedObject(object: AnyObject!, key: CConstVoidPointer, value: AnyObject!, policy: objc_AssociationPolicy)


    引数で受け取ったオブジェクトに対して、動的に引数のプロパティをセットします


     


    【object : AnyObject!】


    動的にプロパティを追加したい対象オブジェクト


     


    【key : CConstVoidPointer】


    プロパティにアクセスするためのセレクタのポインタ、Objective-Cと違い文字列をポインタにするとクラッシュ します


     


    【policy : objc_AssociationPolicy】


    UIntに変換して指定することで属性を指定します


  • objc_getAssociatedObject(object: AnyObject!, key: CConstVoidPointer) -> AnyObject!


    引数で受け取ったオブジェクトから、動的に引数のプロパティを取得します


     


    【object: AnyObject!】


    動的にプロパティを取得したい対象オブジェクト


     


    【key : CConstVoidPointer】


    プロパティにアクセスするためのセレクタのポインタ、Objective-Cと違い文字列をポインタにするとクラッシュ します



objc_AssociationPolicyについて

上記でも説明しましたがobjc_AssociationPolicyはUInt型に変換する必要があります。その理由としては定義を見れば分かります。

typealias objc_AssociationPolicy = UInt

以下AssociationPolicyの種類


  • OBJC_ASSOCIATION_ASSIGN

  • OBJC_ASSOCIATION_RETAIN_NONATOMIC

  • OBJC_ASSOCIATION_COPY_NONATOMIC

  • OBJC_ASSOCIATION_RETAIN

  • OBJC_ASSOCIATION_COPY


使用例

AクラスのオブジェクトにStringのプロパティである「hoge」を動的に追加してみます

class A {

var hogeSelector = Selector("hoge")

// プロパティを動的にセットします
func setHoge(hoge : String) {
objc_setAssociatedObject(
self,
&hogeSelector,
hoge,
UInt(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}

// プロパティを動的に取得します
func hoge()->String! {
if let hoge = objc_getAssociatedObject(
self,
&hogeSelector
) as? String
{
return hoge
}
return nil
}
}

動的に追加したプロパティにアクセスします

var a = A()

a.setHoge("swift")
println( a.hoge() ) //-> swift


おわりに

SwiftでもObjective-Cと全く同じランタイムAPIが用意されているため、他にもSwizzlingやClosureからのIMP生成などの処理も可能です。


本来設計がしっかりしていれば使う事はないですが、この柔軟性こそがSwift(Objective-C)の特徴ではないでしょうか。