しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

SwiftでNSProxyを使った開発ができなくなってた

下記事で紹介したライブラリのSwift版を作りたかったけど挫折した話です。
このライブラリではNSProxyを使ってるんですがSwiftではできなくなっている事があって実装できませんでした。

llcc.hatenablog.com

上ライブラリでできる事

@interface SampleDefaults : LKUserDefaults
@property (strong, nonatomic) NSString* name;
@end

上のように宣言をしておけば下のようにUserDefaultsのデータを取得できます。
セットも同様にプロパティー形式アクセスできます。

defaults.registeredDefaults.name;

上記機能の実装方法

NSProxyというオブジェクトを使って実装しています。
Rubymethod_missingに近いものだと考えると分かりやすいかと思います。

registeredDefaultsSampleDefaultsインスタンスを返すように見えますが、実はLKUserDefaultsProxyというクラスのインスタンスを返します。
上の例ではregisteredDefaultsnameというプロパティーにアクセスしていますが、LKUserDefaultsProxyにはそんなプロパティーがないので普通はエラーが起きます。
しかしLKUserDefaultsProxyforwardInvocationというメソッドを実装しておけばエラー発生前にforwardInvocationを通るようになります。
そこでプロパティー名を取れるので、それを元にUserDefaultsへのセットや取得をしています。

Swiftでできなかったこと

NSInvocationというオブジェクトが使えなくなっていました。
forwardInvocationは引数がNSInvocationなのでforwardInvocationの実装自体できなくなっていました。

その他できない事

それとSwiftは型が違うクラスへの代入は落ちます。
下のような実装はObjective-cでは落ちなかったのですがSwiftでは使えません。

let a: String = UILabel() as! String

その為registeredDefaultsというメソッドが実はLKUserDefaultsProxyというクラスのインスタンスを返すという事もできなくなっていました。
Objective-cid型のようにどんなメソッドも送れるオブジェクトもないので事実上インスタンスの偽装ができなくなりました。
AnyObjectidに近そうだったのですがどんなメソッドも送れるわけではありませんでした。