アウトレットコレクションを使う
見たことがあるけど使ったことがない機能のひとつ「Outlet Collection」。
iOS4.0以降で使用可能になったアウトレットコレクションの簡単な解説です。
この記事は Xcode 4.5.2 & iPhone 6.0 Simulator の環境で確認しています。
アウトレットコレクションとは?
部品(アウトレット)をアウトレットコレクションに接続することで、接続した部品を配列コレクションで管理できる機能です。乱暴に書くと「指定したUI部品のオブジェクトをNSArrayにぶっ込む作業をInterface Builderが半自動でやってくれる機能」です。
(コードでUI部品を動的に生成してコレクションクラスで管理してるのをIBを使ってできる感じ)
どんなときに使うの?
部品が配列コレクションに格納されているので、高速列挙などでループを回してすべての要素(部品)にアクセスするといった用途。
全要素のプロパティを一括変更したりする場合に便利。
ここからはアウトレットコレクションの作り方と使い方について説明します。
アウトレットコレクションの作成
通常のアウトレットの作成と同じ手順で、部品からヘッダーのinterface部に線を引っ張ってアウトレットの宣言と接続を行います。この操作でアウトレットコレクション用のプロパティが作られるとともに、線を引っ張った部品がコレクションに接続されます。
設定は以下の通り。
Connection:Outlet Collectionを指定する
Name:任意のプロパティ名を入力する
Type:アウトレットコレクションに格納するオブジェクトのクラス名を指定する。デフォルトでは接続した部品のクラス名が入ります。
Connectボタンを押すと以下のようにアウトレットコレクションのプロパティ宣言が挿入され、部品との接続も行われます。
@property (strong, nonatomic) IBOutletCollection(UIButton) NSArray *controlls;
Typeで入力したクラス名がIBOutletCollectionに続くカッコ内に挿入されていますが、この記述により、Typeで指定されたクラス(およびサブクラス ※1)のオブジェクトのみアウトレットコレクションに接続できる、という制限がIB側で行われるようです。Typeにid型を指定すればどんな部品でも接続できるようになります。
そのあとにNSArrayオブジェクト型の変数宣言が続きます(※2)。
ちなみにIBOutletCollectionはUINibDeclarations.hで以下のように定義されています。IBOutletと同様にIBがアウトレットコレクションとして認識するために使っているだけだと思われます。
#ifndef IBOutletCollection
#define IBOutletCollection(ClassName)
#endif
アウトレットコレクションへの接続方法
2つ目以降の部品は先に作ってあるアウトレットコレクションに接続する(線を引っ張る)だけです。
ひとつの部品を複数のアウトレットに接続できるように、ひとつの部品を複数のアウトレットコレクションに接続することも可能です。
コード内でアウトレットコレクションを利用する
プロパティ宣言を見てわかる通り、アウトレットコレクションの実体はNSArrayのため配列コレクション操作で部品のオブジェクトを取得し、そのオブジェクトに対して何らかの操作を行います。
以下のアウトレットコレクションがある場合に、接続されている部品すべてをDisableにするコード例です。
@property (strong, nonatomic) IBOutletCollection(UIControl) NSArray *controlls;
for (UIControl* control in self.controlls) {
control.enabled = NO;
}
まとめ
- アウトレットコレクションはアウトレットが格納された配列コレクションである
- コレクション要素として格納されている部品のプロパティを一括設定する場合などに適している
Disable用のアウトレットコレクション、入力フィールドを持つ部品のアウトレットコレクションというように用途別に作るのも良いかもしれませんね。
■※1
リファレンスでIBOutletCollectionをみると、
This macro takes an optional ClassName parameter. If specified, Interface Builder requires all objects added to the array to be instances of that class. For example, to define a property that stores only UIView objects, you could use a declaration similar to the following:
@property (nonatomic, retain) IBOutletCollection(UIView) NSArray *views;
とあり、IBOutletCollectionのClassNameパラメータで指定されたオブジェクトしか受け付けないような記述ですが、実際はサブクラスも接続可能です。
■※2
リファレンスを見ると、IBOutletCollection(ClassName) は NSArrayかNSMutableArray の前に置けとあるので、NSMutableArray に置き換えるのは大丈夫だと思います。mutable/immutableの違いなのでコードから配列の要素を変更(追加/削除など)するかどうかで選択すればOK。
Identifier used to qualify a one-to-many instance-variable declaration so that Interface Builder can synchronize the display and connection of outlets with Xcode. You can insert this macro only in front of variables typed as NSArray or NSMutableArray.