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)の特徴ではないでしょうか。