下記事で紹介したライブラリのSwift
版を作りたかったけど挫折した話です。
このライブラリではNSProxy
を使ってるんですがSwift
ではできなくなっている事があって実装できませんでした。
上ライブラリでできる事
@interface SampleDefaults : LKUserDefaults @property (strong, nonatomic) NSString* name; @end
上のように宣言をしておけば下のようにUserDefaults
のデータを取得できます。
セットも同様にプロパティー形式アクセスできます。
defaults.registeredDefaults.name;
上記機能の実装方法
NSProxy
というオブジェクトを使って実装しています。
Ruby
のmethod_missing
に近いものだと考えると分かりやすいかと思います。
registeredDefaults
はSampleDefaults
のインスタンスを返すように見えますが、実はLKUserDefaultsProxy
というクラスのインスタンスを返します。
上の例ではregisteredDefaults
のname
というプロパティーにアクセスしていますが、LKUserDefaultsProxy
にはそんなプロパティーがないので普通はエラーが起きます。
しかしLKUserDefaultsProxy
にforwardInvocation
というメソッドを実装しておけばエラー発生前にforwardInvocation
を通るようになります。
そこでプロパティー名を取れるので、それを元にUserDefaults
へのセットや取得をしています。
Swiftでできなかったこと
NSInvocation
というオブジェクトが使えなくなっていました。
forwardInvocation
は引数がNSInvocation
なのでforwardInvocation
の実装自体できなくなっていました。
その他できない事
それとSwift
は型が違うクラスへの代入は落ちます。
下のような実装はObjective-c
では落ちなかったのですがSwift
では使えません。
let a: String = UILabel() as! String
その為registeredDefaults
というメソッドが実はLKUserDefaultsProxy
というクラスのインスタンスを返すという事もできなくなっていました。
Objective-c
のid
型のようにどんなメソッドも送れるオブジェクトもないので事実上インスタンスの偽装ができなくなりました。
AnyObject
はid
に近そうだったのですがどんなメソッドも送れるわけではありませんでした。