HIGについては知っていますが (これは非常に便利です!)、Objective-C を作成するとき、具体的には Cocoa (または CocoaTouch) を使用するときにどのようなプログラミング手法を使用しますか?
33 に答える
私がやり始めたことがいくつかありますが、標準ではないと思います。
1) With the advent of properties, I no longer use "_" to prefix "private" class variables. After all, if a variable can be accessed by other classes shouldn't there be a property for it? I always disliked the "_" prefix for making code uglier, and now I can leave it out.
2) Speaking of private things, I prefer to place private method definitions within the .m file in a class extension like so:
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass
Why clutter up the .h file with things outsiders should not care about? The empty () works for private categories in the .m file, and issues compile warnings if you do not implement the methods declared.
3) .m ファイルの先頭、@synthesize ディレクティブのすぐ下に dealloc を配置しました。dealloc は、クラスで考えたいことのリストの一番上にあるべきではありませんか? これは、iPhone のような環境では特に当てはまります。
3.5) 表のセルでは、パフォーマンスのためにすべての要素 (セル自体を含む) を不透明にします。これは、すべてに適切な背景色を設定することを意味します。
3.6) NSURLConnection を使用する場合、原則としてデリゲート メソッドを実装することをお勧めします。
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
return nil;
}
ほとんどの Web 呼び出しは非常に特異であり、特に Web サービス呼び出しの場合は、キャッシュされた応答が必要なルールよりも例外です。示されているようにメソッドを実装すると、応答のキャッシュが無効になります。
また興味深いのは、Joseph Mattiello からの iPhone 固有のヒント (iPhone メーリング リストで受け取ったもの) です。他にもありますが、これらは私が考えた最も一般的に役立つものでした (応答で提供された詳細を含めるために、オリジナルからいくつかのビットがわずかに編集されていることに注意してください)。
4) CoreLocation を使用する場合など、必要な場合にのみ倍精度を使用してください。定数を「f」で終了して、gcc がそれらを float として格納するようにしてください。
float val = someFloat * 2.2f;
これは、実際に double である可能性がある場合に最も重要someFloat
です。ストレージの「val」で精度が失われるため、混合モードの数学は必要ありません。浮動小数点数は iPhone のハードウェアでサポートされていますが、単精度ではなく倍精度演算を行うにはまだ時間がかかる場合があります。参考文献:
古い携帯電話では、計算は同じ速度で動作すると思われますが、レジスターには double よりも多くの単精度コンポーネントを含めることができるため、多くの計算では単精度の方が高速になります。
5) プロパティを として設定しますnonatomic
。これらはatomic
デフォルトであり、合成時に、マルチスレッドの問題を防ぐためにセマフォ コードが作成されます。あなたの 99% はおそらくこれについて心配する必要はなく、非アトミックに設定すると、コードの肥大化がはるかに少なくなり、メモリ効率が向上します。
6) SQLite は、大規模なデータ セットをキャッシュする非常に高速な方法です。たとえば、マップ アプリケーションはそのタイルを SQLite ファイルにキャッシュできます。最も高価な部分はディスク I/O です。大きなブロック間BEGIN;
で送信することにより、多くの小さな書き込みを回避します。COMMIT;
たとえば、新しい送信ごとにリセットされる 2 秒のタイマーを使用します。有効期限が切れると、COMMIT を送信します。、これにより、すべての書き込みが 1 つの大きなチャンクになります。SQLite はトランザクション データをディスクに保存し、この Begin/End ラッピングを行うことで、多数のトランザクション ファイルの作成を回避し、すべてのトランザクションを 1 つのファイルにグループ化します。
また、メイン スレッド上にある場合、SQL は GUI をブロックします。非常に長いクエリがある場合は、クエリを静的オブジェクトとして保存し、別のスレッドで SQL を実行することをお勧めします。クエリ文字列のデータベースを変更するものはすべて@synchronize() {}
ブロックでラップしてください。短いクエリの場合は、便宜上、メイン スレッドにそのまま残します。
ドキュメントは古くなっているように見えますが、SQLite の最適化に関するその他のヒントはここにあります。
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
不明な文字列をフォーマット文字列として使用しないでください
メソッドまたは関数がフォーマット文字列引数を取る場合は、フォーマット文字列の内容を制御できることを確認する必要があります。
たとえば、文字列をログに記録する場合、文字列変数を唯一の引数として次のように渡しますNSLog
。
NSString *aString = // get a string from somewhere;
NSLog(aString);
これに伴う問題は、文字列にフォーマット文字列として解釈される文字が含まれている可能性があることです。これにより、誤った出力、クラッシュ、およびセキュリティの問題が発生する可能性があります。代わりに、文字列変数をフォーマット文字列に置き換える必要があります。
NSLog(@"%@", aString);
別の環境で慣れ親しんでいるものではなく、標準的な Cocoa の命名規則とフォーマット規則および用語を使用してください。そこには多くの Cocoa 開発者がいます。その中の別の開発者があなたのコードで作業を開始したときに、他の Cocoa コードと見た目や感じが似ていれば、はるかに親しみやすくなります。
すべきこととすべきでないことの例:
id m_something;
オブジェクトのインターフェイスで宣言して、それをメンバー変数またはフィールドと呼ばないでください。something
その名前にまたはを使用し、それをインスタンス変数_something
と呼びます。- getter に名前を付けないでください
-getSomething
。適切な Cocoa 名はただ-something
. - セッターに名前を付けないでください
-something:
。そのはず-setSomething:
- メソッド名には引数が散在し、コロンが含まれます。で
-[NSObject performSelector:withObject:]
はありませんNSObject::performSelector
。 - メソッド名、パラメーター、変数、クラス名などでは、アンダーバー (アンダースコア) ではなくインターキャップ (CamelCase) を使用します。
- クラス名は大文字で始まり、変数名とメソッド名は小文字で始まります。
何をするにしても、Win16/Win32 スタイルのハンガリー語表記を使用しないでください。Microsoft でさえ、.NET プラットフォームへの移行でそれをあきらめました。
IBアウトレット
歴史的に、アウトレットのメモリ管理は不十分でした。現在のベスト プラクティスは、アウトレットをプロパティとして宣言することです。
@interface MyClass :NSObject {
NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end
プロパティを使用すると、メモリ管理のセマンティクスが明確になります。また、インスタンス変数合成を使用すると、一貫したパターンが提供されます。
LLVM/Clang 静的アナライザーを使用する
注: Xcode 4 では、これは IDE に組み込まれています。
Clang Static Analyzerを使用して、当然のことながら、Mac OS X 10.5 で C および Objective-C コード (まだ C++ はありません) を分析します。インストールして使用するのは簡単です:
- このページから最新バージョンをダウンロードしてください。
- コマンドライン
cd
から、プロジェクト ディレクトリへ。 - 実行し
scan-build -k -V xcodebuild
ます。
(いくつかの追加の制約などがあります。特に、プロジェクトを「デバッグ」構成で分析する必要があります。詳細については、 http://clang.llvm.org/StaticAnalysisUsage.htmlを参照してください。ただし、多かれ少なかれです。要するに。)
その後、アナライザーは一連の Web ページを生成し、コンパイラーが検出できない可能性のあるメモリ管理やその他の基本的な問題を示します。
これは地味ですが便利なものです。自分自身をデリゲートとして別のオブジェクトに渡す場合は、そのオブジェクトのデリゲートをリセットしてからdealloc
.
- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}
これを行うことで、これ以上デリゲート メソッドが送信されないようにすることができます。エーテルに消えようdealloc
としているとき、誤ってこれ以上メッセージが送信されないようにする必要があります。self.someObject は別のオブジェクト (シングルトンまたは自動解放プールなど) によって保持される可能性があることを覚えておいてください。フェアゲームです。
この習慣を身につけると、デバッグが面倒な多くの奇妙なクラッシュから解放されます。
同じ原則が Key Value Observation と NSNotifications にも適用されます。
編集:
さらに防御的に、次のように変更します。
self.someObject.delegate = NULL;
の中へ:
if (self.someObject.delegate == self)
self.someObject.delegate = NULL;
@ケンデル
それ以外の:
@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end
使用する:
@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end
Objective-C 2.0 の新機能。
クラス拡張については、Apple の Objective-C 2.0 Reference で説明されています。
「クラス拡張機能を使用すると、プライマリ クラスの @interface ブロック内以外の場所で、クラスに必要な追加の API を宣言できます」
したがって、それらは実際のクラスの一部であり、クラスに加えて (プライベート) カテゴリではありません。微妙だが重要な違い。
自動解放を避ける
通常(1)はその存続期間を直接制御できないため、自動解放されたオブジェクトは比較的長期間存続し、アプリケーションのメモリフットプリントを不必要に増加させる可能性があります。デスクトップではこれはほとんど重要ではないかもしれませんが、より制約のあるプラットフォームでは、これは重大な問題になる可能性があります。したがって、すべてのプラットフォームで、特により制約のあるプラットフォームでは、自動解放されたオブジェクトにつながるメソッドの使用を避けることがベストプラクティスと見なされ、代わりにalloc/initパターンを使用することをお勧めします。
したがって、ではなく:
aVariable = [AClass convenienceMethod];
可能な場合は、代わりに次を使用する必要があります。
aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];
新しく作成されたオブジェクトを返す独自のメソッドを作成する場合、Cocoaの命名規則を利用して、メソッド名の前に「new」を付けることで、オブジェクトを解放する必要があることをレシーバーに通知できます。
したがって、代わりに:
- (MyClass *)convenienceMethod {
MyClass *instance = [[[self alloc] init] autorelease];
// configure instance
return instance;
}
あなたは書くことができます:
- (MyClass *)newInstance {
MyClass *instance = [[self alloc] init];
// configure instance
return instance;
}
メソッド名は「new」で始まるため、APIのコンシューマーは、受信したオブジェクトを解放する責任があることを認識しています(たとえば、NSObjectControllerのnewObject
メソッドを参照してください)。
(1)独自のローカル自動解放プールを使用して制御できます。詳細については、「プールの自動解放」を参照してください。
これらのいくつかはすでに言及されていますが、頭のてっぺんから考えられるのは次のとおりです。
- KVO 命名規則に従います。現在 KVO を使用していなくても、私の経験では、多くの場合、将来的にも有益です。また、KVO またはバインディングを使用している場合は、物事が想定どおりに機能することを知る必要があります。これは、アクセサー メソッドとインスタンス変数だけでなく、対多関係、検証、依存キーの自動通知なども対象としています。
- プライベート メソッドをカテゴリに入れます。インターフェイスだけでなく、実装も同様です。プライベート メソッドと非プライベート メソッドの間に概念的な距離を置くことは良いことです。すべてを .m ファイルに含めます。
- バックグラウンド スレッド メソッドをカテゴリに入れます。同上。メイン スレッドに何があり、何がメイン スレッドにないかを考えるときは、明確な概念上の障壁を維持するのが良いことがわかりました。
- を使用し
#pragma mark [section]
ます。通常、私は独自のメソッド、各サブクラスのオーバーライド、および情報または正式なプロトコルによってグループ化します。これにより、探しているものに正確にジャンプすることがはるかに簡単になります。同じトピックで、似たようなメソッド (テーブル ビューのデリゲート メソッドなど) をグループ化します。 - private メソッドと ivar の前に _ を付けます。私はその見た目が好きで、たまたまプロパティを意味するときに ivar を使用する可能性は低くなります。
- init と dealloc で mutator メソッド / プロパティを使用しないでください。それが原因で悪いことが起こったことは一度もありませんが、オブジェクトの状態に応じて何かを行うようにメソッドを変更すると、ロジックがわかります。
- IBOutlets をプロパティに入れます。私は実際にこれをここで読んだだけですが、私はそれを始めようとしています. メモリの利点に関係なく、スタイル的には (少なくとも私には) 優れているようです。
- 絶対に必要でないコードを書くことは避けてください。これは、必要なときに ivar を作成し
#define
たり、データが必要になるたびに配列をソートする代わりに配列をキャッシュしたりするなど、実際には多くのことをカバーしています。これについて私が言えることはたくさんありますが、肝心なのは、必要になるまで、またはプロファイラーが指示するまでコードを書かないことです。長期的には、物事を維持するのがずっと簡単になります。 - 始めたことを終わらせる。未完成でバグのあるコードを大量に持つことは、プロジェクトを死に至らしめる最も早い方法です。適切なスタブ メソッドが必要な場合は、
NSLog( @"stub" )
内部に配置するか、追跡したい方法でそれを示します。
単体テストを作成します。他のフレームワークでは難しいかもしれないCocoaで多くのことをテストできます。たとえば、UIコードを使用すると、通常、物事が正常に接続されていることを確認し、使用時に機能することを信頼できます。また、状態を設定し、デリゲートメソッドを簡単に呼び出してテストできます。
また、内部のテストを作成する際に、パブリックメソッドとプロテクトメソッドとプライベートメソッドの可視性が妨げられることもありません。
ゴールデン ルール: もしあなたならalloc
、あなたrelease
!
更新:ARCを使用していない限り
Java/C#/C++/etc であるかのように Objective-C を記述しないでください。
Java EE Web アプリケーションの作成に慣れているチームが、Cocoa デスクトップ アプリケーションを作成しようとしているのを見たことがあります。あたかも Java EE Web アプリケーションであるかのように。AbstractFooFactory と FooFactory と IFoo と Foo が飛び交い、本当に必要なのは Foo クラスと Fooable プロトコルだけでした。
これを行わないようにすることの一部は、言語の違いを真に理解することです。たとえば、Objective-C クラス メソッドはインスタンス メソッドと同じように動的にディスパッチされ、サブクラスでオーバーライドできるため、上記の抽象ファクトリおよびファクトリ クラスは必要ありません。
DebuggingMagicページをブックマークしてください。これは、ココアのバグの原因を見つけようとしているときに壁に頭をぶつけたときの最初のストップになるはずです。
たとえば、後でクラッシュを引き起こしているメモリを最初に割り当てた方法を見つける方法を説明します(アプリの終了時など)。
私が今、初心者カテゴリアホリズムと呼ぶことに決めたものを避けるようにしてください. Objective-C の初心者がカテゴリを発見すると、彼らはしばしば暴走し、存在するすべてのクラスに有用な小さなカテゴリを追加します ( 「なに? 数値をローマ数字に変換するメソッドを追加して NSNumber をロックオン!」 )。
これをしないでください。
2ダースの基本クラスの上に数十個の小さなカテゴリ メソッドが散りばめられていなければ、コードは移植性が高くなり、理解しやすくなります。
ほとんどの場合、コードを合理化するためにカテゴリ メソッドが必要だと本当に思っている場合、そのメソッドを再利用することは決してないでしょう。
カテゴリ メソッドの名前空間を指定していない限り (そして、まったく正気でない ddribin 以外に誰が?)、他の危険性もあります。Apple、プラグイン、またはアドレス空間で実行されている他の何かも同じカテゴリを定義する可能性があります。わずかに異なる副作用を持つ同じ名前のメソッド....
わかった。警告を受けたので、「この部分を実行しないでください」を無視してください。しかし、極度の自制を行使してください。
ユーザーが望むように文字列を並べ替える
ユーザーに提示する文字列を並べ替えるときは、単純なcompare:
方法を使用しないでください。localizedCompare:
代わりに、またはなどのローカライズされた比較方法を常に使用する必要がありますlocalizedCaseInsensitiveCompare:
。
詳細については、文字列の検索、比較、および並べ替えを参照してください。
世界のサブクラス化に抵抗します。Cocoa では、他のフレームワークではサブクラス化によって行われる多くのことが、委譲と基礎となるランタイムの使用を通じて行われます。
たとえば、Java では無名*Listener
サブクラスのインスタンスを頻繁に使用し、.NET ではEventArgs
サブクラスを頻繁に使用します。Cocoa ではどちらも行わず、代わりに target-action が使用されます。
宣言されたプロパティ
通常、すべてのプロパティに対して Objective-C 2.0 の Declared Properties 機能を使用する必要があります。public でない場合は、クラス拡張に追加します。宣言されたプロパティを使用すると、メモリ管理のセマンティクスがすぐに明確になり、dealloc メソッドを簡単に確認できます。プロパティ宣言をグループ化すると、それらをすばやくスキャンして、dealloc メソッドの実装と比較できます。
プロパティを「非アトミック」としてマークしないようにする前に、十分に検討する必要があります。The Objective C Programming Language Guideが指摘しているように、プロパティはデフォルトでアトミックであり、かなりのオーバーヘッドが発生します。さらに、単にすべてのプロパティをアトミックにするだけでは、アプリケーションがスレッドセーフになるわけではありません。もちろん、'nonatomic' を指定せずに独自のアクセサ メソッドを (合成するのではなく) 実装する場合は、それらをアトミックな方法で実装する必要があることに注意してください。
Think about nil values
As this question notes, messages to nil
are valid in Objective-C. Whilst this is frequently an advantage -- leading to cleaner and more natural code -- the feature can occasionally lead to peculiar and difficult-to-track-down bugs if you get a nil
value when you weren't expecting it.
NSAssert とその仲間を使用します。私は常に nil を有効なオブジェクトとして使用しています...特に nil にメッセージを送信することは、Obj-C では完全に有効です。ただし、変数の状態を本当に確認したい場合は、NSAssert と NSParameterAssert を使用すると、問題を簡単に追跡できます。
シンプルだけど忘れがちなこと。仕様によると:
一般に、同じセレクター (同じ名前) を持つ異なるクラスのメソッドは、同じ戻り値と引数の型も共有する必要があります。この制約は、動的バインディングを許可するためにコンパイラによって課されます。
この場合、同じ名前のセレクターはすべて、たとえ異なるクラスであっても、同一の戻り値/引数の型を持つと見なされます。簡単な例を次に示します。
@interface FooInt:NSObject{}
-(int) print;
@end
@implementation FooInt
-(int) print{
return 5;
}
@end
@interface FooFloat:NSObject{}
-(float) print;
@end
@implementation FooFloat
-(float) print{
return 3.3;
}
@end
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
id f1=[[FooFloat alloc]init];
//prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
NSLog(@"%f",[f1 print]);
FooFloat* f2=[[FooFloat alloc]init];
//prints 3.3 expectedly as the static type is FooFloat
NSLog(@"%f",[f2 print]);
[f1 release];
[f2 release]
[pool drain];
return 0;
}
Leopard (Mac OS X 10.5) 以降を使用している場合は、Instruments アプリケーションを使用してメモリ リークを見つけて追跡できます。Xcode でプログラムをビルドしたら、[実行] > [パフォーマンス ツールで開始] > [Leaks] を選択します。
アプリにリークが見られなくても、オブジェクトを長時間保持している可能性があります。Instruments では、これに ObjectAlloc インストゥルメントを使用できます。Instruments ドキュメントで ObjectAlloc インストゥルメントを選択し、View > Detail を選択してインストゥルメントの詳細を表示します (まだ表示されていない場合) (横にチェックマークが付いている必要があります)。ObjectAlloc 詳細の「Allocation Lifespan」の下で、「Created & Still Living」の横にあるラジオ ボタンを選択していることを確認します。
アプリケーションの記録を停止するたびに、ObjectAlloc ツールを選択すると、アプリケーション内のまだ生きている各オブジェクトへの参照が「# Net」列にいくつあるかが表示されます。独自のクラスだけでなく、NIB ファイルの最上位オブジェクトのクラスも確認してください。たとえば、画面にウィンドウがなく、まだ生きている NSWindow への参照が表示される場合は、コードでそれを解放していない可能性があります。
dealloc でクリーンアップします。
これは、特に忘れがちなことの 1 つです。時速 150 マイルでコーディングする場合。常に、常に、常にdeallocで属性/メンバー変数をクリーンアップしてください。
私は Objc 2 属性を(新しいドット表記で) 使用するのが好きなので、これによりクリーンアップが簡単になります。多くの場合、次のように単純です。
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
これにより、解放が処理され、属性が NULL に設定されます (これは防御的プログラミングと見なされます。dealloc のさらに下にある別のメソッドがメンバー変数に再度アクセスする場合に備えて - まれですが、発生する可能性があります)。
10.5 で GC がオンになったため、これはそれほど必要なくなりましたが、作成した他のリソースをクリーンアップする必要がある場合があります。代わりに finalize メソッドでそれを行うことができます。
これらのコメントはすべて素晴らしいものですが、しばらく前に公開されたGoogle の Objective-C スタイル ガイドについて誰も言及していないことに本当に驚いています。彼らは非常に綿密な仕事をしたと思います。
また、準関連トピック (より多くの応答の余地があります!):
NSWindowController と NSViewController が管理する NIB ファイルの最上位オブジェクトを解放することを忘れないでください。
NIB ファイルを手動でロードする場合、NIB の最上位オブジェクトを使い終わったら、そのオブジェクトを解放する必要があります。
初心者が使用するかなり明白なものの 1 つは、コードに Xcode の自動インデント機能を利用することです。別のソースからコピーして貼り付けている場合でも、コードを貼り付けたら、コードのブロック全体を選択して右クリックし、そのブロック内のすべてを再インデントするオプションを選択できます。
Xcode は実際にそのセクションを解析し、ブラケット、ループなどに基づいてインデントします。行ごとにスペース バーやタブ キーを押すよりもはるかに効率的です。
変数とプロパティ
1/ ヘッダーをクリーンに保ち、実装を隠す ヘッダー
にインスタンス変数を含めないでください。プライベート変数は、プロパティとしてクラス継続に入れられます。パブリック変数は、ヘッダーでパブリック プロパティとして宣言します。読み取り専用にする場合は、readonly として宣言し、クラス継続で readwrite として上書きします。基本的に、変数はまったく使用せず、プロパティのみを使用しています。
2/ プロパティにデフォルト以外の変数名を付けます。例:
@synthesize property = property_;
理由 1: 「自分」を忘れることによるエラーをキャッチします。プロパティを割り当てるとき。理由 2: 私の実験によると、Instruments の Leak Analyzer には、デフォルト名のリーク プロパティを検出するのに問題があります。
3/ プロパティに対して保持または解放を直接使用しないでください (または非常に例外的な状況でのみ)。あなたの dealloc では、それらに nil を割り当てるだけです。保持プロパティは、保持/解放を単独で処理するためのものです。たとえば、セッターがオブザーバーを追加または削除していないかどうかはわかりません。変数は、セッターとゲッター内でのみ直接使用する必要があります。
ビュー
1/ 可能であれば、すべてのビュー定義を xib に入れます (例外は通常、動的コンテンツとレイヤー設定です)。時間を節約し (コードを書くよりも簡単です)、簡単に変更でき、コードをきれいに保ちます。
2/ ビューの数を減らしてビューを最適化しようとしないでください。サブビューを追加したいという理由だけで、 xib の代わりに UIImageView をコードに作成しないでください。代わりに UIImageView を背景として使用してください。ビュー フレームワークは、何百ものビューを問題なく処理できます。
3/ IBOutlets は、常に保持する (または強力にする) 必要はありません。ほとんどの IBOutlets はビュー階層の一部であるため、暗黙的に保持されることに注意してください。
4/ viewDidUnload のすべての IBOutlets を解放する
5/ dealloc メソッドから viewDidUnload を呼び出します。暗黙的に呼び出されるわけではありません。
メモリー
1/ 作成時にオブジェクトを自動解放します。多くのバグは、リリース コールを 1 つの if-else ブランチに移動するか、return ステートメントの後に移動することによって発生します。autorelease ではなく release は、例外的な状況でのみ使用する必要があります。たとえば、実行ループを待機していて、オブジェクトを早期に自動解放したくない場合などです。
2/ オーソマティック参照カウントを使用している場合でも、retain-release メソッドがどのように機能するかを完全に理解する必要があります。保持リリースを手動で使用することは、ARC よりも複雑ではありません。どちらの場合も、リークと保持サイクルについて考慮する必要があります。大規模なプロジェクトや複雑なオブジェクト階層では、retain-release を手動で使用することを検討してください。
コメント
1/ コードを自動文書化します。すべての変数名とメソッド名は、それが何をしているかを示す必要があります。コードが正しく書かれている場合 (これには多くの練習が必要です)、コード コメントは必要ありません (ドキュメント コメントとは異なります)。アルゴリズムは複雑になる可能性がありますが、コードは常に単純でなければなりません。
2/ コメントが必要な場合があります。通常、明らかでないコードの動作またはハッキングを説明します。コメントを書かなければならないと感じたら、まずコードを書き直して、コメントが不要になるようにします。
インデント
1/ インデントを増やしすぎない。メソッド コードのほとんどは、メソッド レベルでインデントする必要があります。ネストされたブロック (if、for など) は可読性を低下させます。ネストされたブロックが 3 つある場合は、内側のブロックを別のメソッドに入れるようにしてください。4 つ以上のネストされたブロックは使用しないでください。メソッド コードの大部分が if 内にある場合は、if 条件を否定します。例:
if (self) {
//... long initialization code ...
}
return self;
if (!self) {
return nil;
}
//... long initialization code ...
return self;
C コード、主に C 構造体を理解する
Obj-C は、C 言語上の軽い OOP レイヤーにすぎないことに注意してください。C の基本的なコード構造 (列挙型、構造体、配列、ポインターなど) がどのように機能するかを理解する必要があります。例:
view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);
以下と同じです:
CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;
などなど
独自のコーディング標準ドキュメントを管理し、頻繁に更新します。バグから学ぶようにしてください。バグが作成された理由を理解し、コーディング標準を使用してバグを回避しようとします。
私たちのコーディング標準は現在約 20 ページあり、Java コーディング標準、Google Obj-C/C++ 標準、および独自の追加が混在しています。コードを文書化し、標準の標準インデント、空白、空白行を適切な場所に使用するなど。
最初に Cocoa プログラミングを始めたとき、私はこれを見落としていたことを知っています。
NIB ファイルに関するメモリ管理の責任を理解していることを確認してください。ロードした NIB ファイルの最上位オブジェクトを解放する責任があります。この件に関するAppleのドキュメントを読んでください。
すべての GCC 警告を有効にしてから、Apple のヘッダーによって定期的に発生する警告を無効にして、ノイズを減らします。
また、Clang 静的分析を頻繁に実行します。「静的アナライザーの実行」ビルド設定を使用して、すべてのビルドに対して有効にすることができます。
単体テストを作成し、ビルドごとに実行します。
より機能的に。
Objective-C はオブジェクト指向言語ですが、Cocoa フレームワークは関数型スタイルを意識しており、多くの場合関数型スタイルで設計されています。
可変性の分離があります。不変クラスをプライマリとして使用し、可変オブジェクトをセカンダリとして使用します。たとえば、主に NSArray を使用し、必要な場合にのみ NSMutableArray を使用します。
純粋な関数があります。それほど多くはありませんが、多くのフレームワーク API は純粋な関数のように設計されています。
CGRectMake()
やなどの関数を見てくださいCGAffineTransformMake()
。明らかに、ポインター形式の方が効率的です。ただし、ポインターを使用した間接引数は、副作用なしでは提供できません。可能な限り純粋に構造を設計します。偶数状態のオブジェクトを分離します。値を他のオブジェクトに渡す場合-copy
の代わりに使用します。-retain
共有状態は、他のオブジェクトの値への突然変異に静かに影響を与える可能性があるためです。したがって、副作用がゼロになることはありません。オブジェクトの外部からの値がある場合は、それをコピーします。そのため、共有状態をできるだけ最小限に設計することも重要です。
ただし、不純な関数の使用も恐れないでください。
遅延評価あり。
-[UIViewController view]
プロパティのようなものを参照してください。オブジェクトの作成時にビューは作成されません。view
呼び出し元が最初にプロパティを読み取るときに作成されます。UIImage
実際に描画されるまでロードされません。この設計のような多くの実装があります。この種の設計はリソース管理には非常に役立ちますが、遅延評価の概念を知らなければ、それらの動作を理解するのは容易ではありません。閉鎖があります。可能な限り C ブロックを使用します。これにより、生活が大幅に簡素化されます。ただし、使用する前にブロックメモリ管理についてもう一度読んでください。
セミオートGCあり。NSAutoreleasePool。
-autorelease
プライマリを使用します。-retain/-release
本当に必要な場合は手動セカンダリを使用してください。(例: メモリの最適化、明示的なリソースの削除)
私が見た Apple 提供のサンプルは、App デリゲートをグローバル データ ストア、一種のデータ マネージャーとして扱っていました。それは頭がおかしい。シングルトンを作成し、App デリゲートでインスタンス化することもできますが、App デリゲートをアプリケーション レベルのイベント処理以上のものとして使用しないでください。このブログ エントリの推奨事項に心から賛同します。このスレッドは私をひっくり返しました。
deallocメソッドでのみプロパティを解放します。プロパティが保持しているメモリを解放したい場合は、単に nil に設定してください:
self.<property> = nil;
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass