Objective-C
iOS
iOSDay 3

Objective-CのLightweight Genericsに使われる__kindofとは何か

More than 1 year has passed since last update.

最近のObjecitive-CにもSwiftに併せて細かな変更や機能追加がされており、NSArrayやNSDictionaryなどコンテナが保持する型を指定するLightweight Genericsが追加されたことも記憶に新しいですが、その他にも__kindofを型に指定するアノテーションが追加されていました。

2016年、Objective-Cのコードをまだまだ保守していく皆さんのために、今回はこの__kindofについて軽くまとめておきます。


はじめに結論

まず結論から書いておきます。今北産業です。

NSArray *array1;                   // 何が入ってるかわからん

NSArray<_kindof UIView *> *array2; // UIViewとそのサブクラス入ってる
NSArray<UIView *> *array3; // UIViewしか入ってないもんね


  • add/setは何でもできるが「取り出すときにどうすべきか」で警告される。


  • __kindofを使わずに<UIView *>の場合はサブクラスでさえ入ってないという解釈のコードである

  • 戻り値にも__kindofが指定できるので、UITableViewCellやUIViewControllerなど継承して利用することが頻繁に行われるクラスには指定してインターフェースをより細かく作りこむことが出来る


Lightweight Genericsに__kindofを使うとどうなる?

そもそも__kindofがないと何が問題なのかを明確にするため、まず__kindofを使わずにArrayを作る

NSMutableArray<UIView *> *array = @[].mutableCopy;

それに対して要素を次のように2つ追加する。UIViewとUIImageView

[array addObject:[[UIView alloc] init]];

[array addObject:[[UIImageView alloc] init]];

これらをそれぞれ次のように取り出す

UIView *first = array[0];       // もちろんこれは何も問題ない

UIImageView *second = array[1]; // 警告される

ここでarray[1]をUIImageViewに代入しようとすると警告される。

以上をわざわざスクリーンキャプチャで見せると次のような感じ

スクリーンショット 2015-11-22 10.19.24.png

Lightweight Genericsを使ってコンテナに何が入っているかを明確にしたいが、実際はサブクラスが含まれている場合に警告されるようになっている。当然、キャストすれば警告はなくなるが、__kindofはサブクラスが入っていることを許可するために使われる。

NSMutableArray<__kindof UIView *> *array = @[].mutableCopy;

[array addObject:[[UIView alloc] init]];
[array addObject:[[UIImageView alloc] init]];
UIView *first = array[0]; // もちろんこれは何も問題ない
UIImageView *second = array[1]; // 警告されなくなる!!

しかし、まだ、__kindofの魅力はこんなもんじゃない


戻り値に__kindofを使うとどうなる?

もちろんメソッドの戻り値にkindofを使うことも出来る。具体的にはUITableViewで頻繁に使う次のメソッドの戻り値にはすでに `kindof` が使われている(Xcode7.1.1で確認)。

- (__kindof UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier

forIndexPath:(NSIndexPath *)indexPath;

(そう、つまりみなさんはすでに__kindofを使っていたのだ!!ΩΩΩ<な、なんだってー)

このインターフェースを見ると、再利用キューに保持されていた様々なUITableViewCellの派生クラスを取り出せるということが分かるし、実際にキャストする必要性がないということも分かりやすい(idを戻り値とするよりずっと分かりやすい)。


参考URL

https://developer.apple.com/videos/play/wwdc2015-401/

http://stackoverflow.com/questions/31399208/ios-kindof-nsarray