インスタンス変数を@implementationブロックまたはクラス拡張に配置する機能は、iOSのすべてのバージョンおよび64ビットMac OSXプログラムで使用される「最新のObjective-Cランタイム」の機能です。
32ビットのMacOS Xアプリを作成する場合は、インスタンス変数を@interface宣言に含める必要があります。ただし、32ビットバージョンのアプリをサポートする必要はない可能性があります。OS Xは、5年以上前にリリースされたバージョン10.5(Leopard)以降、64ビットアプリをサポートしています。
したがって、最新のランタイムを使用するアプリのみを作成していると仮定しましょう。ivarをどこに置くべきですか?
オプション0 :(@interfaceしないでください)
まず、インスタンス変数を宣言に入れたくない理由を見てみましょう@interface。
インスタンス変数を@interface公開に入れると、実装の詳細がクラスのユーザーに公開されます。これにより、それらのユーザー(独自のクラスを使用している場合でも!)は、実装の詳細に依存するべきではないことになります。(これは、ivarを宣言するかどうかとは関係ありません@private。)
インスタンス変数をに@interface入れると、コンパイルに時間がかかり.mます。これは、ivar宣言を追加、変更、または削除するたびに、インターフェイスをインポートするすべてのファイルを再コンパイルする必要があるためです。
したがって、インスタンス変数をに入れたくありません@interface。どこに置けばいいの?
オプション2:@implementation中括弧なし(しないでください)
次に、オプション2「中括弧のブロックなしでiVarを@implementantionの下に置く」について説明しましょう。これはインスタンス変数を宣言しません!あなたはこれについて話している:
@implementation Person
int age;
NSString *name;
...
そのコードは2つのグローバル変数を定義します。インスタンス変数は宣言しません。
グローバル変数が必要な場合は、.mファイル内であっても、ファイル内でグローバル変数を定義する@implementationことは問題ありません。たとえば、すべてのインスタンスでキャッシュなどの状態を共有する必要があるためです。ただし、このオプションはivarを宣言しないため、このオプションを使用してivarを宣言することはできません。(また、実装にプライベートなグローバル変数は通常static、グローバル名前空間を汚染してリンク時エラーのリスクを回避するために宣言する必要があります。)
それはあなたのオプション1と3を残します。
オプション1:@implementation中括弧付き(Do It)
通常、オプション1を使用@implementationします。次のように、中かっこでメインブロックに配置します。
@implementation Person {
int age;
NSString *name;
}
これらをここに配置するのは、それらの存在を非公開に保ち、前述の問題を防止し、通常、クラス拡張に配置する理由がないためです。
では、いつオプション3を使用して、それらをクラス拡張に配置するのでしょうか。
オプション3:クラス拡張内(必要な場合にのみ実行)
それらをクラスと同じファイルのクラス拡張子に入れる理由はほとんどありません@implementation。@implementationその場合は、それらを入れた方がよいでしょう。
ただし、ソースコードを複数のファイルに分割するのに十分な大きさのクラスを作成する場合があります。カテゴリを使用してそれを行うことができます。たとえば、UICollectionView(かなり大きなクラスを)実装している場合、再利用可能なビュー(セルと補足ビュー)のキューを管理するコードを別のソースファイルに配置することを決定する場合があります。これらのメッセージをカテゴリに分類することで、これを行うことができます。
@interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
@end
@interface UICollectionView (ReusableViews)
- (void)registerClass:(Class)cellClass forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forCellWithReuseIdentifier:(NSString *)identifier;
- (void)registerClass:(Class)viewClass forSupplementaryViewOfKind:(NSString *)elementKind withReuseIdentifier:(NSString *)identifier;
- (void)registerNib:(UINib *)nib forSupplementaryViewOfKind:(NSString *)kind withReuseIdentifier:(NSString *)identifier;
- (id)dequeueReusableCellWithReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
- (id)dequeueReusableSupplementaryViewOfKind:(NSString*)elementKind withReuseIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath*)indexPath;
@end
これで、でメインUICollectionViewメソッドをUICollectionView.m実装でき、UICollectionView+ReusableViews.mで再利用可能なビューを管理するメソッドを実装できるようになりました。これにより、ソースコードがもう少し管理しやすくなります。
ただし、再利用可能なビュー管理コードには、いくつかのインスタンス変数が必要です。これらの変数はのメインクラス@implementationに公開する必要があるUICollectionView.mため、コンパイラはそれらを.oファイルに出力します。また、これらのインスタンス変数をのコードに公開してUICollectionView+ReusableViews.m、これらのメソッドがivarを使用できるようにする必要もあります。
ここでクラス拡張が必要です。reusable-view-managementivarをプライベートヘッダーファイルのクラス拡張子に入れることができます。
@interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
@end
このヘッダーファイルをライブラリのユーザーに出荷することはありません。これらのivarを表示する必要があるすべてのものがそれらを表示できるようUICollectionView.mにUICollectionView+ReusableViews.m、インポートするだけです。また、mainメソッドが再利用可能なビュー管理コードを初期化するために呼び出すメソッドを投入しました。私たちは、からそのメソッドを呼び出しますで、私たちはそれを実装します。init-[UICollectionView initWithFrame:collectionViewLayout:]UICollectionView.mUICollectionView+ReusableViews.m