web-dev-qa-db-ja.com

Objective-CおよびCocoaを作成するときに使用するベストプラクティスは何ですか?

HIG (これは非常に便利です!)については知っていますが、Objective-Cを書くとき、より具体的にはCocoa(またはCocoaTouch)を使用するときは、どのプログラミング手法を使用しますか。

346
pixel

私が標準であるとは思わないことを始めたいくつかのことがあります:

1)プロパティの出現により、「_」を使用して「プライベート」クラス変数をプレフィックスすることはなくなりました。結局のところ、他のクラスが変数にアクセスできる場合、そのプロパティはありませんか?私はコードをよりくするために「_」プレフィックスを常に嫌っていましたが、今では省略できます。

2)プライベートなことについて言えば、プライベートメソッド定義を.mファイル内のクラス拡張のように配置することを好みます。

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

部外者が気にするべきではないもので.hファイルを混乱させるのはなぜですか? empty()は、.mファイルのプライベートカテゴリで機能し、宣言されたメソッドを実装しない場合、コンパイル警告を発行します。

3).synthディレクティブのすぐ下の.mファイルの先頭に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;

これは、someFloatが実際にdoubleである場合に最も重要であり、ストレージの「val」の精度が失われるため、混合モードの数学は必要ありません。 iPhoneのハードウェアでは浮動小数点数がサポートされていますが、単精度ではなく倍精度の計算を行うにはさらに時間がかかる場合があります。参照:

古い携帯電話では、計算は同じ速度で動作すると思われますが、レジスタには単精度よりも倍精度のコンポーネントを使用できるため、多くの計算では単精度が高速になります。

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);
110
mmalc

別の環境で慣れ親しんでいるものではなく、標準のCocoa命名およびフォーマットの規則と用語を使用します。そこにはare多くのCocoa開発者がいて、別の開発者があなたのコードを使い始めたとき、他のCocoaコードと同じように見えると感じれば、より親しみやすいでしょう。

何をすべきか、何をすべきでないかの例:

  • オブジェクトのインターフェイスでid m_something;を宣言せずに、メンバー変数またはフィールド;名前にsomethingまたは_somethingを使用し、インスタンス変数と呼びます。
  • ゲッターに-getSomethingという名前を付けないでください。適切なCocoa名は-somethingです。
  • セッターに-something:という名前を付けないでください。 -setSomething:である必要があります
  • メソッド名には引数が散在しており、コロンが含まれています。 -[NSObject performSelector:withObject:]ではなく、NSObject::performSelectorです。
  • メソッド名、パラメーター、変数、クラス名などにアンダーバー(アンダースコア)ではなく、インターキャップ(キャメルケース)を使用します。
  • クラス名は大文字で始まり、変数名とメソッド名は小文字で始まります。

他に何をするにしても、しない Win16/Win32スタイルのハンガリー語表記を使用します。 Microsoftでさえ、.NETプラットフォームへの移行をあきらめました。

108
Chris Hanson

IBOutlets

歴史的に、コンセントのメモリ管理は貧弱でした。現在のベストプラクティスは、アウトレットをプロパティとして宣言することです。

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

プロパティを使用すると、メモリ管理のセマンティクスが明確になります。また、インスタンス変数合成を使用する場合、一貫したパターンを提供します。

107
mmalc

LLVM/Clang Static Analyzerを使用する

注:Xcode 4では、これは現在IDEに組み込まれています。

Clang Static Analyzer to-当然のことながら-Mac OS X 10.5でCおよびObjective-Cコードを分析します(C++はまだありません)。インストールして使用するのは簡単です:

  1. このページ から最新バージョンをダウンロードします。
  2. コマンドラインからcdをプロジェクトディレクトリに移動します。
  3. scan-build -k -V xcodebuildを実行します。

(いくつかの追加の制約などがあります。特に、「デバッグ」構成でプロジェクトを分析する必要があります。詳細については、 http://clang.llvm.org/StaticAnalysisUsage.html を参照してください。しかし、それは多かれ少なかれそれが要約するものです。)

アナライザーは、コンパイラーが検出できないメモリ管理やその他の基本的な問題を示す一連のWebページを生成します。

98
mmalc

これは微妙ですが、便利です。自分を別のオブジェクトのデリゲートとして渡す場合は、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;
95
schwa

@kendell

の代わりに:

@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を宣言できます」

したがって、それらは実際のクラスの一部であり、クラスに加えて(プライベート)カテゴリではありません。微妙だが重要な違い。

87
schwa

自動解放を避ける

通常(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)独自のローカル自動解放プールを使用して制御できます。詳細については、 Autorelease Pools を参照してください。

75
mmalc

これらのいくつかはすでに言及されていますが、ここに私の頭の中で思い浮かぶものがあります:

  • KVOの命名規則に従ってください。現在KVOを使用していない場合でも、私の経験では、将来的にはまだ有益であることがよくあります。また、KVOまたはバインディングを使用している場合は、想定どおりに機能していることを知る必要があります。これには、アクセサメソッドとインスタンス変数だけでなく、多対多の関係、検証、依存キーの自動通知などが含まれます。
  • プライベートメソッドをカテゴリに入れます。インターフェイスだけでなく、実装も同様です。プライベートメソッドと非プライベートメソッドの間に概念的にある程度の距離を置くのは良いことです。 .mファイルにすべてを含めます。
  • カテゴリにバックグラウンドスレッドメソッドを配置します。上記と同じです。メインスレッドにあるものとそうでないものについて考えているとき、明確な概念上の障壁を維持するのが良いことがわかりました。
  • #pragma mark [section]を使用通常、独自のメソッド、各サブクラスのオーバーライド、情報または正式なプロトコルでグループ化します。これにより、探しているものに簡単にジャンプできます。同じトピックで、同様のメソッド(Table Viewのデリゲートメソッドなど)をグループ化し、それらをどこにも貼り付けないでください。
  • 接頭辞のプライベートメソッドとivarsに_を付けます。外観が好きで、偶然プロパティを意味するときにivarを使用する可能性は低くなります。
  • initおよびdeallocでミューテーターメソッド/プロパティを使用しないでください。何か悪いことが起こったことはありませんが、メソッドに依存する何かを行うようにメソッドを変更すると、ロジックを見ることができます。オブジェクトの状態。
  • プロパティにIBOutletsを配置します。私は実際にここでこれを読んでいますが、それを始めます。メモリの利点に関係なく、スタイル的には(少なくとも私には)より良いようです。
  • 絶対に必要ではないコードの記述は避けてください。これは、#defineが行うときにivarを作成する、データが必要になるたびにソートするのではなく配列をキャッシュするなど、多くのことをカバーします。私はこれについて多くのことを言うことができますが、一番下の行はあなたがそれを必要とするかプロファイラーがあなたに言うまでコードを書かないことです。長期的には物事を維持するのがずっと簡単になります。
  • あなたが始めたものを仕上げてください。多くの半分に終わったバグのあるコードは、プロジェクトの死者を殺すための最速の方法です。問題のないスタブメソッドが必要な場合は、NSLog( @"stub" )を内部に配置することでそれを示すか、または物事を追跡する必要があります。
70

単体テストを作成します。他のフレームワークでは難しいかもしれないCocoaのlotをテストできます。たとえば、UIコードを使用すると、通常は物事が正常に接続されていることを確認し、使用時に機能することを信頼できます。また、状態を設定し、デリゲートメソッドを簡単に呼び出してテストすることができます。

また、内部メソッドのテストを作成する際に、パブリックメソッドと保護メソッドとプライベートメソッドの可視性がありません。

56
Chris Hanson

黄金律:allocの場合、release

更新:ARCを使用していない場合

55
JamesSugrue

Objective-CをJava/C#/ C++/etcのように書かないでください。

私はかつて、Java EE Webアプリケーションの作成に慣れているチームがCocoaデスクトップアプリケーションを作成しようとするのを見ました。 Java EE Webアプリケーションであるかのように。本当に必要なのはFooクラスと、おそらくFooableプロトコルだけでしたが、AbstractFooFactoryとFooFactory、IFooとFooが飛び回っていました。

これを行わないようにすることの一部は、言語の違いを真に理解することです。たとえば、Objective-Cクラスのメソッドはインスタンスメソッドと同様に動的にディスパッチされ、サブクラスでオーバーライドできるため、上記の抽象ファクトリーおよびファクトリークラスは必要ありません。

55
Chris Hanson

Debugging Magic ページをブックマークしてください。これは、Cocoaバグの原因を見つけようとして頭を壁にぶつけたときの最初の手段です。

たとえば、最初にメモリを割り当てたメソッドを見つける方法を教えてくれます(後でアプリの終了時など)。

50
mj1531

ユーザーが望むように文字列を並べ替える

ユーザーに表示する文字列を並べ替えるときは、単純なcompare:メソッドを使用しないでください。代わりに、常にlocalizedCompare:localizedCaseInsensitiveCompare:などのローカライズされた比較メソッドを使用する必要があります。

詳細については、「 文字列の検索、比較、および並べ替え 」を参照してください。

38
mmalc

私が今、Newbiecategoryaholismと呼ぶことに決めたものを避けるようにしてください。 Objective-Cの初心者がカテゴリを発見すると、多くの場合、既存のすべてのクラスに便利な小さなカテゴリを追加します(「何?NSNumberに数字をローマ数字に変換するメソッドを追加できます!」)。

これをしないでください。

コードはより移植性が高く、理解しやすくなります。これには、2ダースの基礎クラスの上に何十もの小さなカテゴリメソッドが散在しています。

ほとんどの場合、コードを合理化するためにカテゴリメソッドが必要だと本当に思う場合、メソッドを再利用することはありません。

他の危険もあります。カテゴリメソッドに名前空間を付けていない限り(そして、まったくとてつもないddribin以外は誰ですか?)、Apple、プラグイン、またはアドレススペースで実行されている何かが同じカテゴリを定義する可能性がありますわずかに異なる副作用を持つ同じ名前のメソッド....

OK。警告が表示されたので、「この部分を実行しないでください」は無視してください。しかし、極度の抑制を行使してください。

38
schwa

世界のサブクラス化に抵抗します。 Cocoaでは、他のフレームワークではサブクラス化により行われる、基になるランタイムの委任と使用により多くのことが行われます。

たとえば、Javaでは匿名の*Listenerサブクラスのインスタンスを多く使用し、.NETではEventArgsサブクラスを多く使用します。 Cocoaでは、どちらも行いません。代わりにtarget-actionが使用されます。

37
Chris Hanson

宣言されたプロパティ

通常、すべてのプロパティに対してObjective-C 2.0宣言プロパティ機能を使用する必要があります。パブリックでない場合は、クラス拡張に追加します。宣言されたプロパティを使用すると、メモリ管理のセマンティクスがすぐに明確になり、deallocメソッドを確認しやすくなります。プロパティ宣言をグループ化すると、それらをすばやくスキャンしてdeallocメソッドの実装と比較できます。

プロパティを「非原子」としてマークしない前に、よく考える必要があります。 The Objective C Programming Language Guide notesのように、プロパティはデフォルトでアトミックであり、かなりのオーバーヘッドが発生します。さらに、すべてのプロパティをアトミックにするだけでは、アプリケーションがスレッドセーフになりません。もちろん、「nonatomic」を指定せず、独自のアクセサメソッドを(それらを合成するのではなく)実装しない場合は、アトミックな方法で実装する必要があります。

31
mmalc

ゼロ値について考える

この質問 注意事項として、nilへのメッセージはObjective-Cで有効です。これは多くの場合、利点であり、よりクリーンで自然なコードにつながりますが、nil値を予期していないときに取得すると、この機能により、特異で追跡が困難なバグが発生することがあります。

26
mmalc

NSAssertとフレンドを使用します。私は常にnilを有効なオブジェクトとして使用しています...特にnilへのメッセージ送信はObj-Cでは完全に有効です。ただし、変数の状態を本当に確認したい場合は、NSAssertとNSParameterAssertを使用します。これにより、問題を簡単に追跡できます。

26
NikWest

シンプルだが忘れられがちなもの。仕様によると:

一般に、同じセレクター(同じ名前)を持つ異なるクラスのメソッドも同じ戻り値と引数の型を共有する必要があります。この制約は、動的バインディングを可能にするためにコンパイラによって課せられます。

この場合、すべて同じ名前のセレクター異なるクラスであってもは、同一の戻り値/引数タイプを持つと見なされます。以下に簡単な例を示します。

@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;
}   
23
Özgür

Leopard(Mac OS X 10.5)以降を使用している場合は、Instrumentsアプリケーションを使用してメモリリークを検出および追跡できます。 Xcodeでプログラムをビルドした後、[実行]> [パフォーマンスツールで開始]> [リーク]を選択します。

アプリにリークが表示されない場合でも、オブジェクトを長くしすぎている可能性があります。機器では、このためにObjectAlloc機器を使用できます。 InstrumentsドキュメントでObjectAllocインストゥルメントを選択し、[表示]> [詳細]を選択して、インストゥルメントの詳細を表示します(まだ表示されていない場合)。 ObjectAllocの詳細の[割り当ての有効期間]で、[作成済みの静物]の横のラジオボタンを選択していることを確認します。

これで、アプリケーションの記録を停止するたびに、ObjectAllocツールを選択すると、「#Net」列に、アプリケーション内のまだ存在する各オブジェクトへの参照の数が表示されます。独自のクラスだけでなく、NIBファイルのトップレベルオブジェクトのクラスも確認してください。たとえば、画面にウィンドウがなく、まだ生きているNSWindowへの参照が表示されている場合、コード内でそれを解放していない可能性があります。

22
mj1531

Deallocでクリーンアップします。

これは忘れやすい最も簡単なものの1つです。 150mphでコーディングする場合。常に、常に、deallocの属性/メンバー変数を常にクリーンアップします。

私はObjc 2属性を使用したいです-with新しいドット表記法-これにより、クリーンアップが簡単になります。多くの場合、次のように簡単です:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

これにより、リリースが処理され、属性がNULLに設定されます(防御プログラミングを検討します-deallocでさらに下の別のメソッドが再びメンバー変数にアクセスする場合-まれですがcouldが発生します)。

10.5でGCをオンにすると、これはそれほど必要ではなくなりますが、作成した他のリソースをクリーンアップする必要がある場合は、代わりにfinalizeメソッドで行うことができます。

21
schwa

これらのコメントはすべて素晴らしいですが、誰も言及していないことに本当に驚いています GoogleのObjective-Cスタイルガイド しばらく前に公開されました。彼らは非常に徹底した仕事をしたと思います。

17
slf

また、半関連のトピック(より多くの応答の余地がある!):

2年前に知っておいてほしい小さなXcodeのヒントとコツは何ですか?

15
schwa

NSWindowControllerとNSViewControllerは、それらが管理するNIBファイルのトップレベルのオブジェクトを解放することを忘れないでください。

NIBファイルを手動でロードする場合は、NIBの作業が完了したら、NIBの最上位オブジェクトを解放する責任があります。

13
mj1531

初心者が使用するかなり明白なもの:コードにXcodeの自動インデント機能を利用します。別のソースからコピー/貼り付けしている場合でも、コードを貼り付けたら、コードブロック全体を選択して右クリックし、そのブロック内のすべてを再度インデントするオプションを選択できます。

Xcodeは実際にそのセクションを解析し、括弧、ループなどに基づいてインデントします。すべての行でスペースバーまたはタブキーを押すよりもはるかに効率的です。

12
iwasrobbed

変数とプロパティ

1 /ヘッダーをクリーンに保ち、実装を隠します
ヘッダーにインスタンス変数を含めないでください。プライベート変数は、プロパティとしてクラス継続に配置されます。パブリック変数は、ヘッダーのパブリックプロパティとして宣言します。読み取り専用にする必要がある場合は、読み取り専用として宣言し、クラス継続で読み取り書き込みとして上書きします。基本的に、私は変数をまったく使用せず、プロパティのみを使用します。

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ステートメントの後に発生します。自動リリースではなくリリースは、例外的な状況でのみ使用する必要があります。ランループを待っているときに、オブジェクトを早めに自動リリースしたくない場合。

2/Authomatic Reference Countingを使用している場合でも、retain-releaseメソッドの仕組みを完全に理解する必要があります。リテインリリースを手動で使用することはARCより複雑ではありません。どちらの場合も、リークとリテインサイクルについて気にしなければなりません。大きなプロジェクトまたは複雑なオブジェクト階層では、保持リリースを手動で使用することを検討してください。

コメント

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の基本的なコード構造(enum、構造体、配列、ポインターなど)の仕組みを理解する必要があります。例:


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++標準、および独自の追加が混在しています。コードを文書化し、標準の標準インデント、適切な場所の空白、空白行などを使用します。

10
Sulthan

すべてのGCC警告をオンにしてから、ノイズを減らすためにAppleのヘッダーによって定期的に引き起こされる警告をオフにします。

また、Clang静的解析を頻繁に実行します。 「静的アナライザーの実行」ビルド設定を使用して、すべてのビルドに対して有効にすることができます。

ユニットテストを作成し、ビルドごとに実行します。

10
oefe

Cocoaプログラミングを初めて使用するときに、これを見落としていたことを知っています。

NIBファイルに関するメモリ管理の責任を必ず理解してください。ロードするNIBファイルのトップレベルオブジェクトをリリースする責任があります。この件について Appleのドキュメント を読んでください。

10
mj1531

もっと機能的

Objective-Cはオブジェクト指向言語ですが、Cocoaフレームワークの機能スタイルに対応しており、多くの場合、機能スタイルが設計されています。

  1. 可変性の分離があります。 immutableクラスをプライマリとして使用し、可変オブジェクトをセカンダリとして使用します。たとえば、主にNSArrayを使用し、必要な場合にのみNSMutableArrayを使用します。

  2. 純粋な機能があります。フレームワークAPIの多くを購入することは、純粋な機能のように設計されています。 CGRectMake()CGAffineTransformMake()などの関数を見てください。明らかに、ポインタ形式はより効率的に見えます。ただし、ポインターを使用した間接引数は、副作用なしで提供できません。構造をできるだけ純粋に設計します。偶数の状態オブジェクトを分離します。他のオブジェクトに値を渡すときは、-copyではなく-retainを使用します。共有状態は、他のオブジェクトの値への変換にサイレントに影響を与える可能性があるためです。したがって、副作用がないことはできません。オブジェクトの外部からの値がある場合は、コピーします。そのため、共有状態をできるだけ最小限に設計することも重要です。

ただし、不純な関数も使用することを恐れないでください。

  1. 遅延評価があります。 -[UIViewController view]プロパティのようなものを参照してください。オブジェクトが作成されるとき、ビューは作成されません。呼び出し側がviewプロパティを初めて読み込んだときに作成されます。 UIImageは、実際に描画されるまでロードされません。この設計のような多くの実装があります。この種の設計はリソース管理に非常に役立ちますが、遅延評価の概念がわからない場合、それらの動作を理解することは容易ではありません。

  2. 閉鎖があります。可能な限りCブロックを使用します。これにより、人生が大幅に簡素化されます。ただし、使用する前にブロックメモリ管理についてもう一度お読みください。

  3. セミオートGCがあります。 NSAutoreleasePool。 -autorelease primaryを使用します。本当に必要な場合は、手動の-retain/-release secondaryを使用してください。 (例:メモリの最適化、明示的なリソースの削除)

9
Eonil

Appleが提供したサンプルでは、​​Appデリゲートをグローバルデータストア、つまり一種のデータマネージャーとして扱いました。それは間違っている。シングルトンを作成し、アプリデリゲートでインスタンス化することもできますが、アプリケーションレベルのイベント処理以外のものとしてアプリデリゲートを使用することは避けてください。 このブログエントリ の推奨事項を心から2番目にしています。 このスレッド 私をひっくり返した。

8
bbrown

プロパティ in deallocメソッドのみをリリースします。 propertyが保持しているメモリを解放する場合は、nilに設定します。

self.<property> = nil;
4
Tuan Nguyen
#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass
0
Nirmit Pathak