2011年6月19日日曜日

Objective-Cで気をつけるべき点

C++やJavaからObjective-Cを使うにあたって間違いやすい点や異なる点です。

同じオブジェクト指向言語といっても、言語によって慣習や考え方はかなり異なることがあります。
他の言語の慣習や考え方を持ち込むのは可読性を損ねるだけでなく、一貫性も損ねることとなるので言語の考え方や慣習はきちんと学ぶべきだと思います。


インスタンス変数はデフォルトはprotected
@privateを使うことでprivateにすることができます。publicも同様にできますが、カプセル化を阻害するのでもちろん推奨されていません。


メソッドはすべてpublic
ヘッダーファイルでプロトタイプ宣言してなくても、メッセージを送ると呼び出せますので、.mファイル側にだけ宣言していたとしてもprivateになったわけではありません。
Objective-C 2.0(iOS)であればクラスエクステンションを使うことで、ヘッダーファイルのほうにプロトタイプ宣言をしなくて済むのとクラスエクステンションを見るとどれがprivateメソッドなのか判定することができます。
privateメソッドに接頭語を付けて見分けるというのも合わせて使ったほうがいいかもしれません。
Extensions(The Objective-C Programming Language)

propertyのデフォルトはatomic
propertyはデフォルトはatomicになっているので無駄に排他制御がかかり性能に影響します。排他不要の場合はnonatomicを必ず書きましょう。

initでインスタンス変数はすべて0で初期化される
Javaと同様に初期化が自動でされるので、C++のようにコンストラクタで0で初期化する必要はありません。
Allocating and Initializing Objects(The Objective-C Programming Language)

nilのオブジェクトにメッセージを送っても無視されるだけでクラッシュはしない
C++のようにクラッシュ回避という意味でのnilチェックは不要です。nilチェックは通常ケースのハンドリングで使います。
Sending message to nil(The Objective-C Programming Language)

BOOLのYESは1とは限らないので、if文内での判定には使わないようにする。
BOOLはunsigned charと同じなので1以外の数が返ってくる恐れもあります。 == YES は避けたほうがよいです。

NSString,NSColor,NSURLはretainではなくcopyを使う
NSStringなどといった value objectsとよばれるオブジェクトにはcopyをつかったほうがよいそうです。
copyとして保持したり返したりするので不変であることが保証できるからのようです。
Value Objects and Copying(Memory Management Programming Guide)

string = value;
self.string = value;
は別物
全者は単なる代入ですが、後者はpropertyによって作られたアクセッサを使っています。後者だとpropertyの宣言によってただの代入だったりretainやcopyされたり排他がかかったりと動作が異なります。

delegateはretainしない
巡回参照による無限ループにはまらないようにdelegateはretainせず、参照だけを保持する。
Weak References to Objects(Memory Management Programming Guide)

メソッド名に接頭語は使わない。
doやdoesをつけるのも意味的な問題で推奨されていません。getも付けないのが慣習です。
General Rules(Coding Guidelines for Cocoa)

引数にキーワードをつける。
キーワードなしでもメソッドの宣言はできますが、キーワードをつける。
General Rules(Coding Guidelines for Cocoa)

プライベートメソッドは独自の接頭語をつけたほうがよい
知らないうちにオーバーライドしてしまうことを防ぐためと、プライベートメソッドを見分けやすくするために、接頭語をつける。ただしアンダーバーはAppleが使っているので独自のものを用意する。例えばBF_addObjectなど
Private Methods(Coding Guidelines for Cocoa)
Typographic Conventions(Coding Guidelines for Cocoa)

#defineは使わずenumもしくはconstを使う
C++と同じで#defineだとプリプロセッサで数値に置き換えられてしまうので、enum,constを使う。
Other types of constants(Coding Guidelines for Cocoa)

通常ケースのハンドリングでは例外は使わない。
JavaではFileNotFoundなど通常のハンドリングにも例外を使いますが、Objective-Cでは、配列外アクセスなどクラッシュするような場合など本当に例外な場合にのみ使います。
そのため、例外はテストなどのデバッグ期間でしか発生しないものでなければなりません。
Exceptions and Errors(Coding Guidelines for Cocoa)

名前空間はない
C++やJavaのように名前空間はありません。NSとか接頭語がついているのもそのためです。

ヘッダーファイルでの2重インクルードの防止は不要
CやC++ではヘッダーファイルの2重インクルードを避けるために#ifdefをヘッダーファイルにつけるのが慣習ですが、Objective-Cでは#importを使えば不要です。


余談ですが、Googleのガイドラインを見るとかなりがっちり決まってたので驚きました。
Objective-Cはフリーダムにかける方だと思うので複数人での開発であれば、Googleのように厳密に決めてやったほうがいいと思います。しかし、性能などとのトレードオフもあるので他のガイドラインをまるパクりではなく、プロジェクトにあったものを選択して採用すべきです。

参考資料
Cording Guidelines for Cocoa
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html

The Objective-C Programming Language
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html

Memory Management Programming Guide


Google Objective-C スタイルガイド(日本語訳)

0 件のコメント:

コメントを投稿