こう書いていたのを
@interface Person + (id)personWithName:(NSString *)name; @endこう書ける
@interface Person + (instancetype)personWithName:(NSString *)name; @end
instancetypeを使うことでコンパイラに戻り値の型を推論させて型チェックが行えるようになる。
例えば
@interface Sample : NSObject + (id)factory1; + (instancetype)factory2; @endこれを使ってこう書く
NSArray* s1 = [Sample factory1]; NSArray* s2 = [Sample factory2];するとコンパイラは s2の方でワーニング出す。s1は戻り値がidなので何にでも代入できるが、s2はinstancetypeにより型が特定できるのでNSArrayとの型の違いがコンパイラによって指摘されている。
Cocoaでも、例えば UICollectionViewLayoutAttributes などで使われ始めている。
UICollectionViewLayoutAttributes Class Reference
+ (instancetype)layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath
* * * *
この記事ではinstancetype使ったgenericsっぽい実装を紹介している。例えばその実装を使うと NSURLのコレクションをこんな感じで扱える。
NSURL <MapCollection> *sites = (id)[NSURL mapCollection]; [sites put:[NSURL URLWithString:@"http://www.jonmsterling.com/"] at:@"jon"]; [sites put:[NSURL URLWithString:@"http://www.nshipster.com/"] at:@"nshipster"]; NSURL *jonsSite = [sites at:@"jon"]; // => http://www.jonmsterling.com/sitesはNSURLのインスタンスではあるがNSURL型を保存するマップ型(NSDictionary)のコレクションとして使える。
この実装コードが下記ブログで解説されている。
実装はinstancetypeの利用の他、非形式プロトコル(NSObjectのカテゴリ)やメソッドフォワーディングを使い、型付けのされたコレクションを実現している。
先ほどのコードに続けてこんなコードも書ける。
NSString <MapCollection> *schemes = (id)sites.scheme.uppercaseString; /* => { jon: "HTTP://", reddit: "HTTP://", foam_repo: "GIT://" } */
??..正直最初見たときには目が点になった...。実装を見れば実現方法がわかるのだが非常に面白い。sitesはNSURLのコレクションで、その要素1つ1つに対して schemeとuppercaseStringのメソッドを投げて、その結果をNSStringのコレクションとして受け取っている。
instancetypeはコレクションからオブジェクトを取り出す箇所で使われている。
@protocol OrderedCollection <nsfastenumeration> - (instancetype)at:(NSUInteger)index; - (void)put:(id)object; @end @protocol MapCollection <nsfastenumeration> - (instancetype)at:(id)key; - (void)put:(id)object at:(id)key; @end
良い刺激になった。
(関連情報)instancetype
(関連情報)メソッドのフォワーディングは木下さんの記事がわかりやすい。実装を読み解くのに参考になる。
0 件のコメント:
コメントを投稿