pragma markによるメソッドの分類
この記事は、pragma markを最初にコピペする事でクラス実装の抜けや漏れを防ぐ方法の紹介です。
コメントと同じく機械側には無くても良いが、プログラマ側に実装すべきメソッドを思い出しやすくします。
最初にpragma mark のリストをコピペする
クラスを作成すると、.hと.mに以下のコードをコピペします。
#pragma mark - class methods
#pragma mark - init methods
#pragma mark - dealloc
#pragma mark - NSCopying, hash, isEqual:
#pragma mark - NSCoding methods
#pragma mark - restorableState methods
#pragma mark - life cycle methods
#pragma mark - action methods
#pragma mark - event handling methods
#pragma mark - drawing methods
#pragma mark - delegate/datasource methods
#pragma mark - accessor methods (in pairs)
#pragma mark - Utility methods
あとは、メソッドを書いてゆくだけです。
メリットは、以下の2点です。
- 次に書くべきメソッドを思い出しやすい。
人間は穴埋め問題の様に場所が決まっていると、何をすれば良いかが思い出しやすい。
- コードのブラウズ時に検索や移動がやりやすい。
メソッドの分類毎に、”mark -“の文字列があるので、”⌘F mark -“と”⌘G”で分類の間を移動できる。
Note
今まで私は”ハイフン”行と”分類名”行で2行に分けて記述していました。 しかし、先ほど試した結果1行でも問題なくXCodeが動作しました。 ですので、今後は1行で記述するつもりです。
次は、それぞれの分類に何を書いているかの説明です。
pragma mark - class methods
クラスメソッドを書く場所。
[NSDocument autosavesInPlace]などのクラス特有の性質を示すメソッドやインスタントイニシャライザを書く。
例:
+ (BOOL) autosavesInPlace;
+ (NSURL*) fileURLWithPath:(NSString*) path;
pragma mark - init methods
イニシャライザを書く場所。
引数が少ないメソッドを上の方に、引数の多いメソッドをしたの方に書く様に気をつける事。
書くときはすこし手間が増えるが、コードを読むときに流れが上から下になるので分かりやすくなる。
Objective-Cのイニシャライザでは最も引数の多いメソッドが、指定イニシャライザ になるので、必然的に上記の様になる。
例:
- (instancetype) init;
- (instancetype) initFileURLWithPath:(NSString *)path;
pragma mark - dealloc
deallocを書く場所。
各種プロパティをnilに戻す事や、KVOの停止、Notificationの受信の停止など。
例:
- (void) dealloc;
pragma mark - NSCopying, hash, isEqual:
オブジェクトのコピーや同一性に関わるメソッドの実装を書く場所。
MVCで言うところのViewクラスやControllerクラスでは必要ありませんが、逆にmodelクラスに相当するクラスの場合は実装はほぼ必須です。
例:
- (id) copyWithZone:(NSZone *)zone;
- (id) mutableCopyWithZone:(NSZone *)zone;
- (BOOL) isEqual:(id)object;
- (NSUInteger) hash;
pragma mark - NSCoding methods
シリアライズ化メソッドを書く場所。
Cut&PasteやDrag&Drop、ファイル保存の実装にはNSCodingのメソッドを使うと簡単になる。
例:
- (void)encodeWithCoder:(NSCoder *)aCoder;
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder;
pragma mark - restorableState methods
状態保存関係のコードを書く場所。
クラスメソッドであるが[NSResponder (NSRestorableState) restorableStateKeyPaths]もここに書く。
例:
+ (NSArray *)restorableStateKeyPaths;
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder;
- (void) restoreStateWithCoder:(NSCoder *)coder;
pragma mark - life cycle methods
オブジェクトのライフサイクルのコードを書く場所。
ViewControllerやWindowControllerのライフサイクルに関するメソッドを書きます。 場合によっては、delegateやnotificationに分類される様なメソッドも書きます。
例:
- (void)awakeFromNib;
// windowControllerの場合
- (void)windowWillLoad;
- (void)windowDidLoad;
// ViewControllerの場合
- (void)viewDidLoad;
- (void)viewWillAppear;
- (void)viewDidAppear;
- (void)viewWillDisappear;
- (void)viewDidDisappear;
// NSApplicationDelegateの場合
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
- (void)applicationWillTerminate:(NSNotification *)aNotification;
pragma mark - action methods
IBActionのメソッドを書く場所。
ユーザーが実行できるコマンドの単位になる、IBAction系のメソッドを書く。
また、enable/disableを制御するためのcanAction系のメソッドも一緒に書いておくと楽。 ライブラリcontrolEnablerを使用すると良い。 validateuserinterfaceitem(7)
例:
- (IBAction) anAction:(id)sender; // action
- (BOOL) canAnAction:(id)sender; // actionを呼出すボタンの有効無効を制御
pragma mark - event handling methods
イベント処理のメソッドをこの場所に書く。
NSResponderのサブクラスでない場合でも、KVOの監視メソッドや、Notificationの受信メソッドをイベント処理と考えて、この場所に書いておくと楽。
例:
// KVOの監視メソッド
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context;
// なんらかのnotificationのレシーバー
- (void) nanikanoNotificationNoReciver:(NSNotification *)aNotification;
// キーダウンイベントを処理したり
- (void)keyDown:(NSEvent *)event;
pragma mark - drawing methods
描画系のメソッドを書く場所。
NSViewのサブクラスしか関係ないが、当然まとめておくと楽。
例:
- (void)drawRect:(NSRect)dirtyRect;
pragma mark - delegate/datasource methods
他の分類には分けられない、delegateメソッドやdatsourceメソッドを書く場所。
例:
// NSSpliterViewのdelegate
- (void)splitViewWillResizeSubviews:(NSNotification *)notification;
- (void)splitViewDidResizeSubviews:(NSNotification *)notification;
pragma mark - accessor methods (in pairs)
アクセッサとKVCに関連するものを書く。
依存関係の記述の”keyPathsForValuesAffectingプロパティ名”クラスメソッドもここに書く。 インデックス付きアクセッサパターンのメソッドもここにまとめます。
例:
+ (NSSet *)keyPathsForValuesAffectingObject
- (id) object
- (void) setObject:(id)inObject
pragma mark - Utility methods
その他のユーティリティメソッドを書く。例は特になし。
参考文献
元ネタは、ヒレガス本かその前後のはずだがググっても出てこない。