##概要
ここ1年ぐらいiPad向けのアプリを作っていたのですが、その際にXcodeを使ってObjective-Cのソースをそれなりに奇麗に見えるように自分なりにあれこれ試行錯誤してきました。その結果を整理して晒してみたいと思います。
なお、Appleが「Cocoa向けコーディングガイドライン」という物を出していますので、基本的な部分はそちらが参考になると思います。
https://developer.apple.com/jp/devcenter/ios/library/japanese.html
(GoogleもObjective-Cのスタイルガイドを出していますが私は「なるほどそういう事もあるのかー」程度にしか読んでいません。)
コーディングルールについては古の時代から様々な派閥があって議論になりがちですが、最終的には自分が好きなスタイルに落ち着くかと思います。
そのヒントにでもなれば幸いです。
##現在の環境(2013/10/31)
- Xcode 5.0.1
- ARC ON
##インスタンス変数(メンバ変数)の書き方
古いXcodeではヘッダーファイルの@interface側に書くのが一般的でした。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
{
@private
int _a;
}
@end
しかし、現在は公開する必要の無いインスタンス変数は、mファイル側に書きます。
@implementation ViewController
{
int _a;
}
これでインスタンス変数を隠蔽できます。
ただ、パブリックにしたくはないけれどどうしても派生クラスでは使いたいというようなケースが出てしまった場合は、@protectedとしてヘッダーで変数を定義する事も有るかと思います。
##インスタンス変数の命名ルール
@implementation ViewController
{
UIView *_view;
UITabBarItem *_tabBarItem;
UINavigationItem *_navigationItem;
NSArray *_toolbarItems;
}
これ、UIViewController.hをほとんど拝借しているのですが、特徴を箇条書きします。
- 変数名には最初にアンダースコア(_)を付ける
- ポインタのアスタリスク(*)は右寄せ
- 変数名をタブで揃えない(Appleは揃えているが面倒くさいので)
- ローワーキャメルケース(英単語の頭文字を大きくするが、最初の文字だけ小文字)
- 複数形の場合は、Itemsなどと複数形の単語を使う
- 変数名にコメントは付けておいた方が良いが、明らかに判る場合は書かなくてもよい
- C++から移行してきた人にありがちなシステムハンガリアンは使わず、アプリケーションハンガリアン記法にする
プロパティの書き方
昔は@synthesizeを多用していた気がしますが、現在は省略できますので、滅多に@synthesizeしません。
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
// ホゲホゲを取得または設定します。
@property (nonatomic) int hogeHoge;
@end
- 命名ルールについてはアンダースコアが無いという事を除いてはインスタンス変数と同じ。
こうしてプロパティを宣言するだけで、int _hogeHogeというインスタンス変数が自動的に宣言されるようなので、必要であればmファイル側ではこちらを直接アクセスする事も可能です(readonlyの変数の初期化など)。ただ、直接アクセスすると当然ですがatomicなプロパティの同期処理が行われないはずなので、注意が必要です。
インスタンス変数(プロパティ)の初期化について
インスタンスを生成した時点でインスタンス変数はすべて0(nil)でクリアされるため、明示的に0にする必要が無い限りは、わざわざ代入式は書かないようにします。
ソースを区分けする
例えばデリゲートであったり、特定の処理をソースの一カ所にまとめて記述するときに、以下のように#pragma mark -
を使うと便利です。
#pragma mark - Operations
// 実行します。
- (void)execute
{
// 省略
}
// 処理を1つ元に戻します。
- (void)undo
{
// 省略
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// 省略
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 省略
}
このように#pragma mark -
を書いておき、Xcodeの右上の方をクリックすると...
以下のように各メソッドが区分けされて表示されるので、管理しやすくなると思います。
ちなみに#pragma mark
と書くとセパレータのみ表示され、#pragma mark AAA
と書くとセパレータ無しでAAAのみ太字で表示されます。
ヘッダーや実装部分における順序
なんとなくですが、ヘッダーは
- グローバルなenumや#define類(@interfaceの外)
- 独自のプロトコル類宣言
- インスタンス生成クラスメソッド類
- init系メソッド類
- プロパティやアクセッサ類
- 公開操作メソッド類
というような順序で並べておくと良いと思います。
mファイル側では、#pragma mark -
と組み合わせて
- ローカルなenumや#define類(@@implementationの外)
- インスタンス生成クラスメソッド類
- init系メソッド類
- dealloc
- プロパティやアクセッサ類の実装
- 公開操作メソッド類
- 非公開メソッド類
- デリゲート実装類
- イベントハンドラ類
というような順序で書くと良さそうです。
もちろん必要なものだけ記述します。
クラス名の命名ルール
基本的にはアッパーキャメルケース(パスカルケース)で書きます。
- UpperCamelCase
- PascalCase
略語(?)を使う場合は全部大文字で行きたいです。
(大文字が何文字まで許せるかは己次第です。)
- XMLParser
- MP3Encoder
既存のフレームワークのクラスから派生したクラスを作る場合は、それとなく親クラスの名前を入れます。
- UIView
- GraphView
- UIViewController
- TopMenuViewController
- AboutViewController
プロジェクト内でしか使わないクラスにはプリフィクスは付けません。
ただし、汎用ライブラリなど他所に出す場合には2〜3文字のプリフィクス(大文字)を付けます。
- TSGraphControl
- TSTileView
enum値の命名ルール
mファイル側にenumを書く場合はどうでもいいですが、ヘッダーファイルに書く必要が有る場合はグローバル宣言になってしまうため、名前が被らないようにプリフィクスを付けるようにしています。
typedef enum {
AnchorID_TopLeft = 1,
AnchorID_Top,
AnchorID_TopRight,
AnchorID_Right,
AnchorID_BottomRight,
AnchorID_Bottom,
AnchorID_BottomLeft,
AnchorID_Left,
} AnchorID;
アッパーキャメルケースとアンダースコア(_)を組み合わせて階層化しているのがミソです。
ちなみに公式のヘッダーファイルやGoogleのスタイルガイドで各enum名の最初にkを付けるのを見かけますが、華麗にスルーします。
※NS_ENUMマクロの利便性については、今のところ理解していませんのでもう少し経験値が溜まってから書きます。
イベントハンドラ、またはデリゲートのメソッド名について
ボタンが押された時に呼ばれるメソッドや、プロトコルを使ってデリゲートのメソッドを定義する時ですが、did(起こった後の処理)やwill(起こる前の処理)を使い分けて書くと、Cocoaっぽくなるのではないかと思います。
// キャンセルボタンが押された時に呼ばれます。
- (void)didCancelButtonTouch
{
}
// ステータス更新タイマーから呼ばれます。
- (void)didStatusTimer
{
}
// スライダーの値が変わった時に呼ばれます。
- (void)didSliderValueChange
{
}
// アイテムが変更される前に呼ばれます。
- (void)hogeView:(HogeView *)hogeView willChangeItem:(Item *)item;
// アイテムが変更された後で呼ばれます。
- (void)hogeView:(HogeView *)hogeView didChangeItem:(Item *)item;
コメントの書き方
師匠からのありがたい教え:
二週間後の自分は他人と思え。
趣味で一人で開発をしていても、仕事で多くの人と開発をしていても、コメントは重要です。
ただし変数名やクラス名においては、いちいち長たらしいコメントを書くよりは、一目でそれとわかるような変数名/クラス名を付けた方が美しいです。
実装部分(制御部分)においては、何をやっているかというコメントを書く事が多いかと思いますが、それとは別に、何故そうしたかという理由を書いておくと、後で役に立つ事が多いです。
また、会社で開発する場合は、ふざけたコメントや面白顔文字をコメントやエラーメッセージ類に入れるのは避けましょう。事故でそのまま製品(納品先)に紛れ込んだり、後でメンテナンス等でソースを読んだ他人がブチ切れる可能性があります。
// データベースからデータを(σ・Д・)σゲッツ!!
(追記)
この記事のコメント欄でご指摘を頂いたのですが(mono0926様ありがとうございました)、Xcode5からはプロパティやメソッドなどに対してJavaDoc風のコメントを書くと、QuickHelp(プロパティやメソッドなどをoption+クリックしたときに表示されるポップアップ)に説明文を表示できるようになったようです。
http://confusatory.org/post/63488534619/documentation-in-xcode-5
http://www.moongift.jp/2013/08/20130809-2/
こちらはもう少し経験値を積んでから最適な方法を模索していきたいと思います。
Visual StudioのC#もこの手のドキュメント補助機能がついていますが、実際に書いてみると引数や戻り値すべてを記述するのはなかなかの苦行です。なので、必要に迫られない限り、おそらく大抵の場合は一行さらっとコメントを書き、何か注意事項がある場合には詳しく書いておく、などという所に落ち着くのではないかと予想しています。
(おまけ)奇麗に見えるソース=読みやすいソース?
スタイルガイドなどを守ってソースが一見奇麗に見えても、ロジックがぐちゃぐちゃでは元も子も有りません。
ソースを奇麗に見せる事はあくまで読みやすいソースの第一歩だと思います。
最後に
何か間違っている箇所、説明不足な所や、他に知りたい箇所が有ればご連絡ください。
判る(狭い)範囲でお答えします。