2011年1月
« 12月   3月 »
 12
3456789
10111213141516
17181920212223
24252627282930
31  
2011/01/16

iOSアプリの互換性を確保する その3

iOSアプリの互換性を確保する その1iOSアプリの互換性を確保する その2の続きです。

3)deprecatedとなったメソッドやプロパティの対応

今後廃止になる予定のメソッドやプロパティは、リファレンスにdeprecatedという記述がされて、アプリ内で使用している状態でビルドすると、警告が表示されます。

今すぐに使えなくなる訳では無いので、無理に修正しなくても大丈夫な場合もありますが、いつ無くなるのかも分からないし、動作がおかしい場合があります。

最新のiOSでdeprecatedとなったメソッドやプロパティは、何かしらの改善点があった為に、別のメソッドやプロパティが用意された上で、deprecatedという扱いになりますが、複数のバージョンのiOSで動作するアプリを作る場合は、最新のiOSでは新しいメソッド or プロパティで実装し、古いiOSでは当然新しいメソッドやプロパティは存在しないので、deprecatedとなっているメソッド or プロパティのまま使うような対応が必要になってきます。

どのように対応するかは、deprecatedとなったメソッドやプロパティの代わりに用意されたものが何かによって変わってきます。

代わりのクラス、メソッドが用意された場合は、iOSアプリの互換性を確保する その1iOSアプリの互換性を確保する その2に書いた方法で、新しいクラス、メソッドが有るかを確認し、有った場合は新しいクラスやメソッドを使い、無い場合は今まで通りdeprecatedとなっているメソッド、プロパティを使えばOKです。

プロパティについては、メソッドと同じやりかたでチェックできるます。

例えば、UIViewのcontentScaleFactorプロパティが存在するかをチェックする場合は、以下のようになります。(viewはUIViewクラスのインスタンス変数)

if( [view respondsToSelector:@selector(contentScaleFactor)] )
{
// contentScaleFactorプロパティが存在する。(iOS 4.0以降)
}

XCodeで「iPad Simulator 3.2」と「iPhone Simulator 4.2」など切り替えて実行してみると、正しくプロパティの存在をチェックできている事を確認できると思います。

これらの方法で、アプリが実行されているiOSのバージョンによって、新しい方法とdeprecatedとなった方法を切り分ければ、どちらでも動作するアプリが作れます。

ただ、旧iOSで実行するコードの部分とは言え、deprecated扱いになったメソッドやプロパティを使っている部分は残っているので、ビルド時に警告が出ます。

動作は問題無いと思いますが、気になる場合は、この部分も動的に参照/実行するようにすると、警告も表示されなくなります。

この場合、deprecatedとなったのが何か(メソッド/プロパティ)によってやり方が違います。

■id型で受け渡せる引数/戻り値のメソッド、id型で受け取れるプロパティの場合

NSObjectのperformSelectorメソッドで呼び出せます。
id result = [instance performSelector:@selector(メソッド名 or プロパティ名)];

引数を指定できる以下のメソッドもあります。
- (id)performSelector:(SEL)aSelector withObject:(id)anObject
- (id)performSelector:(SEL)aSelector withObject:(id)anObject withObject:(id)anotherObject

■上記の方法では対応できない場合

NSInvocationというクラスを使って対応します。

例えば、iOS 3.2でdeprecatedになったCLLocationのgetDistanceFromの場合は以下のようになります。

// メソッドのSignatureを取得
SEL sel = @selector(getDistanceFrom:);
NSMethodSignature *mySignature = [CLLocation instanceMethodSignatureForSelector:sel];

// 呼び出す対象や引数の指定
NSInvocation *myInvocation = [NSInvocation invocationWithMethodSignature:mySignature];
[myInvocation setArgument:&oldLocation atIndex:2];
[myInvocation setTarget:newLocation];
[myInvocation setSelector:sel];

// 呼び出し
[myInvocation invoke];

// 戻り値を取得
CLLocationDistance resultDistance;
[myInvocation getReturnValue:&resultDistance];

以上のような動的に参照を取得して呼び出すような対応を入れれば、deprecatedの警告も表示されないようになるかと思います。

deprecatedの警告がでるかでないかの違いだけで、直接呼び出しても、動的に参照を取得して呼び出しても、処理の内容については変わらないのでお好みで。

iOSアプリの互換性を確保する対応については、これで一旦終了です。


※iPhoneアプリ開発に関する投稿を今から始めるiPhoneアプリ開発にまとめました。

Comments are closed.