Obj-CのLightweight Generics

Xcode 7から使えるようになったObjective-Cの「Lightweight」Genericsですが、どうも公式のドキュメントが見つけられず（存在しない？）、今ひとつ構文がわからなかったので、Appleのヘッダを見たりネットの情報を漁ってみたりしたのを、自分なりにまとめました。

## Apple公式の情報
- [Xcode 7 Release Notes](https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc7_release_notes.html#//apple_ref/doc/uid/TP40001051-CH5-DontLinkElementID_144) ←ほんの少しだけ
- [WWDC 2015 Video: Swift and Objective-C Interoperability](https://developer.apple.com/videos/play/wwdc2015-401/) ←21:47〜 （コメントで教えてもらいました）

## ポイント

- クラスに対して利用可能。プロトコルやメソッドには利用できないっぽい。
- あくまでもコンパイル時の型チェック用。コンパイルされた結果は `id` になる。なお、型チェックに引っかかったときは警告が出る。
- `@interface` （ヘッダ側）で仮型引数が使える。 `@implement` の方（実装側）では使えない。
- クラスの定義時に必要に応じて共変性と反変性を指定する。

## Genericsのクラスを使う場合

`クラス名<型引数>` という構文ですが、型引数の部分はポインタになるので注意。
さらにそのクラスの型もポインタとして使うので、結局、 `クラス名<型 *> *` という形になります。
例えば、NSStringを要素に持つNSArrayなら次のように書きます。

```objc
NSArray<NSString *> *strings = @[@"Foo", @"Bar", @"Baz"];
NSString *first = [strings objectAtIndex:0];

```

なお、型引数付きで宣言したものと、型引数なしで宣言したものは警告なしに変換可能です。

```objc
NSArray<NSString *> *strings = ...;
NSArray *arrays = ...;
arrays = strings;  // OK
strings = arrays;  // OK
```

今までのコードやライブラリは型引数なしのまま、これから書くコードは型引数付きにして、というように混在させておいて、徐々に型引数ありへ移行させていくことができますね。一気に全部書きなおさなくていいのはありがたいです。

## Genericsを使ったクラスを作成する場合

ヘッダ側で `@interface クラス名<(variance) 仮型引数> : 親クラス` という形式で仮型引数を書きます。
(variance)は共変性と反変性の指定（後述）。仮型引数が複数ある場合は `<(variance) 仮型引数1, (variance) 仮型引数2>` というようにコンマで区切ります。

仮型引数名としては、Appleは `T` のような1文字ではなく、 `ObjectType` というのを好んで使っているようですが、別になんでもいいと思います。この仮型引数を、メソッドの引数や戻り値の型として使えます。
※仮型引数にはポインタの `*` は付けません。

こんな感じです。

```objc
@interface Queue<__covariant ObjectType> : NSObject

- (instancetype)initWithArray:(NSArray<ObjectType> *)array;

- (ObjectType)next;

@end
```

一方、実装側では仮型引数は使えません。仮型引数の部分は `id` に置き換えて実装します。
こんな感じです。

```objc
@implementation Queue

- (instancetype)initWithArray:(NSArray *)array {
    self = [super init];
    if (self) {
        _array = [array mutableCopy];
    }
    return self;
}

- (id)next {
    if ([self.array count] > 0) {
        id result = [self.array firstObject];
        [self.array removeObjectAtIndex:0];
        return result;
    } else {
        return nil;
    }
}

@end
```

## 共変性と反変性の指定

大雑把にいえば、継承関係のあるクラスをそれぞれGenericsの型引数に指定したものがある場合に、その一方をもう一方として利用できるかどうかの指定です。

例として、親クラス `Animal` とその派生クラス `Dog` があった場合に、

- `Hoge<Dog>` を `Hoge<Animal>` として利用してよいなら共変 → `__covariant` キーワードを指定
- `Hoge<Animal>` を `Hoge<Dog>` として利用してよいなら反変 → `__contravariant` キーワードを指定
- どちらでもないなら不変 → キーワードを何も付けない。

とします。

1つ前で例に挙げた `Queue` クラスは `__covariant` キーワードで共変性を指定してあるので、 `Queue<Dog>` を `Queue<Animal>` として利用できます。
もし、犬でも猫でもなんでもいいので動物が入ったキューを受け取って、 `next` で次の動物を取り出して処理する、というメソッドがあれば、そこに犬ばかり入ったキューを渡しても処理できるはずですね。

逆に、次の `Handler` クラスは反変性の指定の例です。

```objc
@interface Handler<__contravariant ObjectType> : NSObject

- (instancetype)initWithBlock:(void(^)(ObjectType))block;

- (void)handle:(ObjectType)obj;

@end
```

このクラスは `ObjectType` の扱い方を知っているクラスです。
`Handler<Dog>` なら `handle:` メソッドの引数に犬を渡すと何か処理を行います。
`Handler<Animal>` なら犬でも猫でも受け取って処理できます。

こちらは `__contravariant` で反変性を指定してあるので、 `Handler<Animal>` を `Handler<Dog>` として利用できます。つまり、犬を扱えるものが欲しいところに、動物なら何でも扱えるものを渡してもいいですよ、ということです。


## 感想

まだ使いこなせてないのですが、例えばメソッドの引数が今まで `NSArray` だったのが、 `NSArray<NSString *>` や `NSArray<NSNumber *>` のように書けるので、パッと見て何を渡せばいいかがわかるようになるだけでもうれしいと思いました。

ただ、プロトコルやメソッドにもGenericsが使えるともっと使えそうな気がするんですけど‥‥。惜しいなあ。