Objective-Cスタイルガイド

論文投稿

ICWE(International Conference on Web Engineering)というものに論文を投稿することになった。スマートフォンアプリを扱った研究で、となると当然Objective-Cソースコードも掲載しなければならない。最近いくつかのiPhoneアプリを制作して、Objective-Cの扱いにも慣れてきているからこそ、今一度Objective-Cのスタイルガイドを確認しておく。参考にするのはもちろんGoogleのObjective-Cスタイルガイド

スタイルガイド

いくつか気になったところ、というか忘れそうなところを箇条書きにしておく。



スペース 対 タブ

スペースだけ使うこと。インデントはスペース2つにする。

ほぉ…。今までXcodeのデフォルト設定でやってたのでスペース4つだった。ここはC++と一緒らしい。Xcodeで[環境設定]→[インデント設定]→[スペースの代わりにタブを挿入]のチェックを外して、[インデントの幅]を2に設定。



メソッドの宣言と定義


パラメータが多すぎて1行に収まりきらないときには、1行につきパラメータを1つ書いてください。
複数行にわたるときには、パラメータの前にあるコロンで整列させてください。

これはやってた。コロンで整列。ただ、メソッド名が短くて第2パラメータのラベルが長いときにコロンで揃えられなくて困ってた。それに対する解答もあった。


最初のキーワードが他のキーワードよりも短いときには、以降の行を少なくともスペース4つでインデントしてください。
コロンで整列させる代わりに、キーワードの先頭で整列させても構いません。

なる。つまりこんな感じ。

- (void)short:(GTMFoo *)theFoo
    longKeyword:(NSRect)theRect
    evenLongerKeyword:(float)theInterval {
  ...
}

これはメソッド呼び出しの際も同様。



Objective-Cのメソッド名


アクセサメソッドは「取得しようしている」変数と同じ名前にするべきです。
"get" というプレフィックスを付けるべきではありません。

へぇ。なんでだろう。



変数名


インスタンス変数は大文字と小文字を組み合わせて、アンダースコアで終わるようにするべきです。

これは以前読んだ時から愛用(?)している。何か好きw

userNameTextField_


定数名(#define、enum、constなローカル変数など)は小文字 k で始めて、
大文字と小文字を組合せて単語を区切ります。

これもやってる。好き。



宣言のコメント


インタフェース、カテゴリ、プロトコルの宣言にはすべて、その目的と全体における位置付けを
説明するためのコメントを入れておくべきだ。

インターフェースの宣言にコメントを付けるというのはやっていなかった。これからは長く使うことになるコードを書くことになりそうなのでこういうところはしっかりしておこう。

// アプリケーションの起動終了の通知を処理する、NSApplication の Delegate。
// メインのアプリコントローラによって所有される。
@interface MyAppDelegate : NSObject {
  ...
}
@end



実装のコメント


コメント中に変数名やシンボルを引用するときには、引用符やシンボルをインラインで
指定するのではなく、垂直バー(縦棒)を使うこと。

今までコメントはあまり付けていなかったので初耳。こういうことらしい。引用符内引用符は2番目のように!

// Sometimes we need |count| to be less than zero.
// Remember to call |StringWithoutSpaces("foo bar baz")|



メンバ変数は @private にするべきだ

今までガン無視(^_^;) デフォルトはprotectedだって。

@interface MyClass : NSObject {
 @private
  id myInstanceVariable_;
}
// public accessors, setter takes ownership
- (id)myInstanceVariable;
- (void)setMyInstanceVariable:(id)theVar;
@end



生成時に autorelease するのが望ましい


一時的なオブジェクトを新しく生成するときには、そのメソッドの終わりの方で個別に release するのではなく、
オブジェクトの生成と同じ行で autorelease すること。
ほんの少し遅くなりますが、うっかり release を消してしまったり、release の前に return を入れたりして、
メモリリークが発生するのを防ぐことができます。

なんとなくautoreleaseはしない方針だったけど、確かに。オライリー本はここのところ曖昧だった気がする。

// 避けること(やむを得ないパフォーマンス上の理由がない限り)
MyController* controller = [[MyController alloc] init];
// ... リターンするかもしれないコード ...
[controller release];
// 望ましい
MyController* controller = [[[MyController alloc] init] autorelease];



autorelease してから retain する


オブジェクトの代入は、autorelease してから retain する、というパターンに従うこと。

nilかどうかチェックしてnot nilならreleaseということをしていた。Googleでは、「間違えにくいから」この方法を利用するようだ。ただし、ループの中でこの方法を使うと、autorelease poolがいっぱいになって効率が悪くなるが、このトレードオフは許容できるという考えとのこと。

- (void)setFoo:(GMFoo *)aFoo {
  [foo_ autorelease];  // もし |foo_| == |aFoo| なら、deallocしない
  foo_ = [aFoo retain]; 
}



セッタでは NSString をコピーする


NSString を引数に持つセッタは、受け取った文字列を必ず copy するべきだ。
文字列を retain するだけでは十分ではありません。
文字列をコピーしておけば、知らないうちに呼び出し元が文字列を変更するのを避けることができます。
NSMutableString ではなく NSString を受け取っているから大丈夫だ、と考えてはいけません。

retainしてました。今まで問題が発生したことはないけど、確かにretainした場合は参照先が同じなのでこういうことが起こりうる。

- (void)setFoo:(NSString *)aFoo {
  [foo_ autorelease];
  foo_ = [aFoo copy];
}



BOOL の落とし穴


通常の整数値を BOOL 型に変換するときには注意すること。YES と直接比較しないようにすること。

やってた…かも。通常の整数値をBOOLに変換するときは、YES or NOの値を返す三項オペレータを使うべし!また、BOOL値とYESの直接比較もNG!

// NG
BOOL great = [foo isGreat];
if (great == YES)
  // ... great!

// OK
BOOL great = [foo isGreat];
if (great)
  // ... great!



プロパティ


プロパティに対応するインスタンス変数名は、アンダースコア(_)で終わらなければなりません。
プロパティ名は、対応するインスタンス変数名から最後のアンダースコア(_)を取り除いたものにするべきです。

ややこしい…。今までプロパティ名もアンダースコア付けてた。



文字列には copy 属性を使うこと


NSStringプロパティには、必ず copy 属性を宣言するべきです。

上述のNSStringのセッタ問題に伴って。



大体これくらいかしら。よーしコード書くぞ!