インスタンス変数を@implementation
ブロックまたはクラス拡張に配置する機能は、iOSのすべてのバージョンおよび64ビットMacOSXプログラムで使用される「最新のObjective-Cランタイム」の機能です。
32ビットのMacOSXアプリを作成する場合は、インスタンス変数を@interface
宣言に含める必要があります。ただし、32ビットバージョンのアプリをサポートする必要はない可能性があります。OS Xは、5年以上前にリリースされたバージョン10.5(Leopard)以降、64ビットアプリをサポートしています。
したがって、最新のランタイムを使用するアプリのみを作成していると仮定しましょう。ivarをどこに置くべきですか?
オプション0:(@interface
しないでください)
まず、インスタンス変数を宣言に入れたくない理由を見ていきましょう。@interface
インスタンス変数を@interface
公開に入れると、実装の詳細がクラスのユーザーに公開されます。これにより、それらのユーザー(独自のクラスを使用している場合でも!)は、実装の詳細に依存する必要がなくなる可能性があります。(これは、ivarsを宣言するかどうかとは関係ありません@private
。)
インスタンス変数をに@interface
入れると、コンパイルに時間がかかります。これは、ivar宣言を追加、変更、または削除するたびに.m
、インターフェイスをインポートするすべてのファイルを再コンパイルする必要があるためです。
したがって、インスタンス変数をに入れたくありません@interface
。どこに置けばいいの?
オプション2:@implementation
中かっこなし(しないでください)
次に、オプション2「中括弧のブロックなしでiVarsを@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
(かなり大きなクラス)を実装している場合、再利用可能なビュー(セルと補足ビュー)のキューを管理するコードを別のソースファイルに配置することを決定する場合があります。これらのメッセージをカテゴリに分類することで、これを行うことができます。
// UICollectionView.h
@interface UICollectionView : UIScrollView
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, retain) UICollectionView *collectionViewLayout;
// etc.
@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-management ivarsをプライベートヘッダーファイルのクラス拡張子に入れることができます:
// UICollectionView_ReusableViewsSupport.h
@interface UICollectionView () {
NSMutableDictionary *registeredCellSources;
NSMutableDictionary *spareCellsByIdentifier;
NSMutableDictionary *registeredSupplementaryViewSources;
NSMutableDictionary *spareSupplementaryViewsByIdentifier;
}
- (void)initReusableViewSupport;
@end
このヘッダーファイルをライブラリのユーザーに出荷することはありません。これらのivarを表示する必要があるすべてのものがそれらを表示できるようUICollectionView.m
に、インポートするだけです。また、mainメソッドが再利用可能なビュー管理コードを初期化するために呼び出すメソッドをスローしました。からそのメソッドを呼び出し、で実装します。UICollectionView+ReusableViews.m
init
-[UICollectionView initWithFrame:collectionViewLayout:]
UICollectionView.m
UICollectionView+ReusableViews.m