「Effective Objective-C」まとめ

第1章 Objective-Cに慣れる

項目1 Objective-Cのルーツを知る

  • Objective-Cはオブジェクト指向機能を追加したCのスーパーセット。Objective-Cは動的束縛によるメッセージング構造を使っているため、オブジェクトの型は実行時に明らかになる。特定のメッセージに対してどのコードを実行すべきかは、コンパイラではなくランタイムが判断する。
  • Cの基本概念を理解すると、優れたObjective-Cコードを描くために役立つ。特に、メモリモデルとポインタを理解する必要がある。

項目2 インポートされるヘッダーに含まれるヘッダーの数は最小限に抑える

  • ヘッダーは可能な限り最も深い一でインポートすること。通常はヘッダーでクラスを先行宣言し、対応するヘッダーを実装にインポートする形になる。こうすると、可能な限りクラス間の密結合を避けられる。
  • 準拠するプロトコルを宣言するときのように、先行宣言ではまずい場合がある。そのような場合には、可能な限り、クラス延長カテゴリにプロトコル準拠の宣言を移すことを検討する。でなければ、プロトコルだけを定義するヘッダーのインポートを検討せよ。

項目3 メソッドよりも同じ意味のリテラル構文を使う

  • 文字列、数値、配列、辞書を作るときには、リテラル構文を使うように心がける。リテラル構文の方が、通常のオブジェクト作成メソッドを使うよりも簡潔でわかりやすい。
  • 配列や辞書の要素には、それぞれ添字、キーを使ったリテラル形式でアクセスする。
  • リテラル構文で配列や辞書にnilを挿入しようとすると例外が投げられる。そのため、要素としてnilが決して混ざらないようにする必要がある。

項目4 プリプロセッサの##defineではなく型付き定数を使う

  • プリプロセッサの##defineは使わないようにしよう。##defineには型情報がなく、単純にコンパイル前にシンボルを見つけて置換するだけである。また、警告なしに再定義できてしまうため、アプリケーションの部分部分によって異なる値が使われる危険がある。
  • 翻訳単位に固有な定数は、実装ファイル内でstatic constとして定義する。これらの定数はグローバルシンボルテーブルには収められないので、名前に名前固有空間的なプレフィックスを付ける必要はない。
  • グローバル定数は、ヘッダーファイルでexternal宣言し、対応する実装ファイルで定義する。これらの定数はグローバルシンボルテーブルに収められるので、名前には対応するクラスの名前をプレフィックスとして付けて名前固有空間的に使うようにする。

項目5 状態、オプション、ステータスコードにはenumを使う

  • 状態マシンの状態、メソッドに渡すオプション、エラーステータスコードなどとして使う値に名前を付けるときにはenumを使おう。
  • enumがメソッドのオプションを定義し、そのオプションが同時に複数指定できるような場合には、その値を2の累乗にすると、複数の値をビット単位ORで結合できる。
  • 土台の型を明示してenumを定義するときには、NS_ENUM、NS_OPTIONSマクロを使う。そうすれば、コンパイラが選んだ型ではなく自分で選んだ型が確実に使われる。
  • enumを処理するswitch文では、defaultを使わないようにしよう。こうすると、enumに値を追加したときに、switch文がすべての値を処理していないということをコンパイラが警告してくれる。

第2章 オブジェクト、メッセージング、ランタイム

項目6 プロパティの理解

  • @property構文を使うと、オブジェクトがカプセル化しているデータが何かを定義できる。
  • 属性を使って格納されるデータのさまざまな側面を正しく設定しよう。
  • プロパティを支えるインスタンス変数に値がセットされるときには、宣言された属性の意味に従った形で値がセットされるようにしなければならない。
  • iOSでは、atomicを使うとパフォーマンスが大きく損なわれるのでnonatomicを使おう。

項目7 インスタンス変数にクラス内でアクセスするときは直接アクセスする

  • クラス内での読み出しではインスタンス変数の直接読み出し、書き込みではプロパティを介した書き込みを使うようにしよう。
  • イニシャライザとdeallocでは、かならずインスタンス変数を介して直接データを読み書きしよう。
  • データが遅延初期化されている場合はプロパティを介してデータを読み出さなければならないことがある。

項目8 オブジェクトが等しいとはどういうことかを理解しよう

  • 同値比較したいオブジェクトでは、isEqual:とhashの2つのメソッドを用意しよう。
  • 等しいオブジェクトはhashの値も同じでなければならないが、hashの値が同じでもそれらのオブジェクトは必ずしも等しいとはかぎらない。
  • 何も考えずにすべてのプロパティをテストするのではなく、等しいことをテストする為に何が必要かをはっきりさせよう。
  • hashメソッドは、高速に計算でき、衝突が起きる確率が低くなるように実装しよう。

項目9 実装の詳細を隠すために、クラスクラスタパターンを使う

  • クラスクラスタパターンを使えば、公開されているFacadeの背後に実装の詳細を隠蔽することができる。
  • クラスクラスタはシステムフレームワークで広く使われている。
  • クラスクラスタの公開抽象クラスをサブクラス化するときには注意が必要であり、ドキュメントがあるときには、それをかならず読まなければならない。

項目10 既存のクラスにカスタムデータを追加するにはAssociated Objectを使う

  • Associated Objectは2つのオブジェクトを結びつける手段を提供する。
  • Associated Objectのメモリ管理属性は、所有するかどうかなどの関係を真似た形で定義できる。
  • Associated Objectは、見つけにくいバグを簡単に持ち込むので、ほかのアプローチでは不可能なときに限り使うようにしよう。

項目11 objc_msgSendの役割を理解する

  • メッセージは、レシーバ、セレクタ、引数から構成される。メッセージを送るということは、オブジェクトのメソッドを呼び出すということと同じ意味だ。
  • 送られたメッセージは、すべて動的メッセージディスパッチシステムを通過する。ここで実装をルックアップして実行する。

項目12 メッセージの転送を理解する

  • メッセージ転送とは、オブジェクトが自分の知らないセレクタを検出したときに通過するプロセスである。
  • 動的メソッド解決を使えば、クラスに実行時にメソッドを追加できる。
  • オブジェクトは、自分が理解できない一定のセレクタをほかのオブジェクトが処理できると宣言できる。
  • 本格的な転送メカニズムは、セレクタの処理方法がどうしても見つからないときに限り実行される。

項目13 不透明なメソッドのデバッグではメソッドのSwizzlingを使うことを検討する

  • クラスの特定のセレクタに対するメソッド実装は、実行時に追加、置換できる。
  • Swizzlingは、メソッド実装を交換する処理で、通常は元の実装に機能を追加するために使われる。
  • ランタイムを使ってメソッドを操作するのは、通常デバッグが目的のときに限り認められるものだ。使えるからと言ってむやみに使ってはならない。

項目14 クラスオブジェクトとは何かを理解する

  • クラス階層は、各クラスが自分の型を定義するためにポインタでさしているClassオブジェクトを使ってモデリングされている。
  • コンパイル時にオブジェクトのはっきりとした型がわからないときには、イントロスペクションを使うようにしよう。
  • オブジェクトはメッセージの転送を使っている可能性があるので、可能な限りクラスオブジェクトを直接比較するのではなく、イントロスペクションメソッドを使おう。

第3章 インターフェイスとAPI設計

項目15 名前空間の衝突を避けるためにプレフィックス名を使う

  • 会社、アプリケーション、または両方に適したクラスプレフィックスを選ぼう。そして、首尾一貫してそのプレフィックスを付けよう。
  • 自分のライブラリの依存ファイルとしてサードパーティーライブラリを使う場合、そのライブラリで使われている名前に自分のプレフィックスをさらに追加するとよい。

項目16 指定イニシャライザを用意せよ

  • クラスには指定イニシャライザを実装し、どれが指定イニシャライザかをドキュメントしよう。ほかの全てのイニシャライザは、指定イニシャライザを呼び出す形で実装する。
  • 指定イニシャライザがスーパークラスと異なる場合には、スーパークラスの指定イニシャライザを必ずオーバーライドしよう。
  • サブクラスで使ってはならないイニシャライザについては、サブクラスでスーパークラスのイニシャライザをオーバーライドし、そのなかで例外を投げよう。

項目17 descriptionメソッドの実装

  • インスタンスについて意味のある文字列情報を提供できるように、descriptionメソッドを実装しよう。
  • デバッグ中には、より詳しいオブジェクト情報を表示できるようにしたい場合は、debugDescriptionメソッドを実装しよう。

項目18 できるだけイミュータブルなオブジェクトを使う

  • 可能な限り、イミュータブルなオブジェクトを作ろう。
  • クラス内でプロパティを書き換えたい場合は、クラス延長カテゴリで読み出し専用プロパティを読み書き両用にしよう。
  • プロパティとしてミュータブルなコレクションを公開するのではなく、オブジェクトが管理するコレクションを書き換えるためのメソッドを提供するようにしよう。

項目19 明快で首尾一貫した名前を使う

  • 周囲に溶け込み、正しいという感じを与えるインターフェースを作るために、Objective-C標準になった命名方法に従おう。
  • メソッド名は簡単にして要を得たものにしよう。左から右に英文のように読めるものにしよう。
  • メソッド名のなかに型の略語を入れるのは避けよう。
  • 最も大切なことだが、メソッド名はあなた自身のコードのなかで、また統合されるほかのコードとの間で統一感のあるものにしよう。

項目20 非公開メソッド名にはプレフィックスを付ける

  • 非公開メソッド名にはプレフィックスを付け、公開メソッドと簡単に区別できるようにしよう。
  • メソッドプレフィックスとしてAppleが予約しているシングルアンダースコアを使うのは避けよう。

項目21 Objective-Cエラーモデルを理解する

  • 例外はアプリケーション全体を終了させるべき致命的エラーのときに限り使うようにしよう。
  • 致命的でないエラーでは、エラーを処理するデリゲートメソッドを提供するか、NSErrorオブジェクトの出力引数を用意しよう。

項目22 NSCopyingプロトコルを理解する

  • オブジェクトをコピー対応にするためには、NSCopyingプロトコルを実装しよう。
  • オブジェクトがミュータブル版とイミュータブル版を持つ場合は、NSCopyingとNSMutableCopyingの両方のプロトコルを実装しよう。
  • シャローコピーをするかディープコピーをするかを決め、可能な限り、通常のコピーとしてはシャローコピーを採用するようにしよう。
  • オブジェクトのディープコピーが役に立つ場合は、ディープコピーメソッドを追加することを検討しよう。

第4章 プロトコルとカテゴリ

項目23 オブジェクト間通信には、DelegateとData Sourceプロトコルを使う

  • ほかのオブジェクトに対して関連イベントを通知しなければならないオブジェクトへのインターフェースを作るためにはDelegateパターンを使おう。
  • デリゲートがサポートすべきインターフェースを定義するために、プロトコルをサポートし、そのメソッド(オプションとなることが多い)を定義しよう。
  • オブジェクトがほかのオブジェクトからデータを取得しなければならないときにも、Delegateパターンを使おう。この場合は、データソースプロトコルと呼ばれることが多い。
  • 必要なら、デリゲートがプロトコルのどのメソッドに応答すべきかをキャッシングするために、ビットフィールド構造体を使おう。

項目24 カテゴリを使ってクラスの実装を管理できるサイズに分割せよ

  • クラスの実装を管理しやすい部分部分に分割したい場合には、カテゴリを使おう。
  • 非公開と見なすべきメソッドの実装の詳細を隠すために、Privateというカテゴリを作ろう。

項目25 サードパーティクラスに追加するカテゴリで使う名前にはかならずプレフィックスを付ける

  • 自分のものではないクラスに追加するカテゴリの名前にはかならずプレフィックスを付けよう。
  • 自分のものではないクラスに追加するカテゴリのメソッド名には必ずプレフィックスを付けよう。

項目26 カテゴリではプロパティを使わないようにする

  • カプセル化されたデータのためのプロパティ宣言は、すべてのメインインターフェース定義に集めよう。
  • クラス延長カテゴリ以外のカテゴリ内では、プロパティ宣言ではなくメソッドを使うようにしよう。

項目27 実装の詳細を隠すためにクラス延長カテゴリを活用せよ

  • クラスにインスタンス変数を追加するときには、クラス延長カテゴリを使おう。
  • クラス内の操作でセッターアクセッサが必要な場合、メインインターフェースで読み出し専用のプロパティをクラス延長カテゴリで読み書き両用に宣言し直そう。
  • 非公開メソッドのプロトタイプは、クラス延長カテゴリで宣言しよう。
  • クラスが非公開にしておきたいプロトコルに準拠していることはクラス延長カテゴリで宣言しよう。

項目28 プロトコルを使って無名オブジェクトを提供せよ

  • プロトコルを使えば、型にあるレベルの匿名性を与えることができる。すると、型はプロトコルのメソッドを実装するid型にまとめられる。
  • 型(クラス名)を隠すべきときは無名オブジェクトを使おう。
  • 型がそれほど重要ではなく、オブジェクトが特定のメソッド(プロトコルで定義されたもの)に応答するかどうかの方がずっと重要なときには、無名オブジェクトを使おう。

第5章 メモリ管理

項目29 参照カウントを理解する

  • 参照カウントを使ったメモリ管理は、インクリメント、デクリメントされるカウンタを基礎としている。作成時のオブジェクト参照カウントは、少なくとも1になっている。参照カウントが正数のオブジェクトは生き残る。参照カウントが0になると、オブジェクトは解体される。
  • オブジェクトは、ライフサイクルを通じて、ほかのオブジェクトから保持されたり解放されたりする。保持、解放はそれぞれ参照カウントをインクリメント、デクリメントする。

項目30 ARCを使って参照カウントを楽にする

  • ARCの導入により、デベロッパーはほとんどメモリ管理を考えなくて済むようになった。ARCを使えば、クラスからボイラープレートコードを取り除くことができる。
  • ARCは適切なところでretain, releaseを追加して、オブジェクトのライフサイクルをほぼ全面的に処理する。メモリ管理属性はさまざまな修飾子で指定できる。以前は、retainとreleaseはマニュアルで追加されていた。
  • メソッド名は一貫して返されるオブジェクトのメモリ管理属性を示すために使われている。ARCはこれを強化し、ルールに従わないという選択肢を取り除いた。
  • ARCはObjective-Cオブジェクトしか処理しない。特に重要なのはCoreFoundationオブジェクトは処理されないということであり、適切なCFRetain/CFRelease呼び出しを追加する必要がある。

項目31 deallocではリファレンスを開放して監視状態をクリーンアップする

  • deallocメソッドは、他のオブジェクトのリファレンスを解放したり、KVOやNSNotificationCenter通知などの登録解除のためにだけ使うようにしよう。
  • オブジェクトがファイルデスクリプタなどのシステムリソースを保持している場合、それらのリソースを解放するためのメソッドを作るようにしよう。リソースを使い終わったらこのcloseメソッドを呼び出すということが、そのようなクラスのコンシューマとの契約であるべきだ。
  • 非同期に仕事をしたり、オブジェクトが通常の状態であることを前提としていたりするメソッドをdeallocメソッドで呼び出すのは避けるようにしよう。その前提は間違っている。

項目32 例外セーフコードによるメモリ管理には注意が必要

  • 例外がキャッチされるときには、tryブロック内で作ったオブジェクトのクリーンアップが必ず行われるように注意を払おう。
  • デフォルトでは、ARCは例外が投げられたときのクリーンアップコードを生成しない。コードの生成は、コンパイラフラグで有効にできるが、コードサイズがかなり大きくなり、実行時にパフォーマンスが下がる。

項目33 循環参照を避けるために弱参照を使う

  • 特定の参照をweakにすれば循環参照は避けられる。
  • 弱参照は自動nil設定機能を持つ場合と持たない場合がある。自動nil設定は、ARCとともに導入された新機能で、ランタイムで実装されている。weak属性のプロパティは、自動nil設定により解体されたオブジェクトの参照を含むことが決してないので安全に読める。

項目34 メモリ最高使用水準を下げるために自動開放プールブロックを使う

  • 自動解放プールはスタックに作られる。オブジェクトはautoreleaseメッセージを送られると、最上位のプールに追加される。
  • 自動解放プールを正しく使えば、アプリケーションのメモリ最高使用水準を下げられる。
  • 新しい@autoreleasepool構文を使う自動解放プールの方がコストがかからない。

項目35 メモリ管理上の問題をデバッグするときにはゾンビが役立つ

  • オブジェクトが完全解放されるとき、オプションで解体する代わりにゾンビに変身させることができる。この機能は環境変数のNSZombieEnabledでオンにする。
  • オブジェクトはisaポインタを操作してオブジェクトのクラスを特別なゾンビクラスに変えれば、ゾンビに変身する。ゾンビクラスは、すべてのセレクタに対して、どのメッセージがどのオブジェクトに送られたかを示すメッセージを表示してから、アプリケーションを強制終了する。

項目36 retainCountは使わないようにする

  • オブジェクトの参照カウントは役に立つように見えるかもしれないが、通常はそうではない。特定のタイミングにおける循環参照のカウントの値を絶対視しても、オブジェクトの寿命の完全なイメージは作れない。
  • ARCが導入されたときに、retainCountメソッドは使うべきではないとされ、実際に使うとコンパイルエラーが生成されるようになった。

第6章 ブロックとGCD

項目37 ブロックを理解する

  • ブロックはC,C++,Objective-Cのためのクロージャである。
  • ブロックはオプションで引数をとり、オプションで値を返すことができる。
  • ブロックはスタック、ヒープに確保することも、グローバルにすることもできる。スタックに確保されたブロックは、ヒープにコピーできる。このとき、ヒープに作られたコピーは、標準のObjective-Cオブジェクトと同じように参照カウント管理を受ける。

項目38 よく使うブロック型にはtypedefを作る

  • ブロック変数を使いやすくするために型定義を利用しよう。
  • 新しい型を定義するときには、ほかの型と衝突しないようにするための命名ルールに従うようにしよう。
  • 同じブロックシグネチャのために複数の型を定義することをためらわないようにしよう。ブロックシグネチャを書き換えてリファクタリングしようとしたとき、型定義が一つになっていると、変更されてよい箇所と変更されて困る箇所が出てくる場合がある。

項目39 コードの分断を避けるためにハンドラブロックを使う

  • ハンドラのビジネスロジックの宣言とオブジェクト作成コードを同じ箇所にまとめると役に立つときは、ハンドラブロックを使おう。
  • デリゲートを使うと、監視対象が複数あるときにはオブジェクトによる処理の切り替えが必要になることが多いが、ハンドラブロックには、デリゲートとは異なり、オブジェクトを直接対応付けられるというメリットがある。
  • ハンドラブロックを使うAPIを設計するときには、ブロックを実行するキューを指定するために、引数としてキューを渡せるようにすることを検討しよう。

項目40 ブロックでオーナーオブジェクトを参照し循環参照を引き起さないようにする

  • ブロックを直接、または間接的に保持するオブジェクトをキャプチャするブロックは、循環参照を発生させることがあるということを意識しよう。
  • 適切なタイミングで循環参照が破られるようにしよう。しかし、APIのコンシューマに循環参照を破ることを求めてはならない。

項目41 同期の確保では、ロックよりもディスパッチキューを使う

  • ディスパッチキューを使えば、@synchronizedブロックやNSLockオブジェクトを使うよりも簡単に同期を実現できる。
  • 同期ディスパッチと非同期ディスパッチを併用すれば、通常のロックと同じ同期動作を実現できるが、非同期ディスパッチでは呼び出し元スレッドをブロックしない。
  • 並行キューとバリアブロックを使えば、同期処理をより効率よく実行できる。

項目42 performSelectorファミリのメソッドではなくGCDを使う

  • performSelectorファミリのメソッドには、メモリ管理に関して危険なところがある。どのセレクタを実行すべきかを判定する方法がなければ、ARCコンパイラは適切なメモリ管理呼び出しを挿入できない。
  • performSelectorメソッドファミリは、戻り型やメソッドに渡せる引数の数に関して非常に大きな制限を抱えている。
  • 別スレッドでセレクタを実行するためのメソッドは、ブロックを使うGCD呼び出しで置き換えた方がよくなる。

項目43 GCDやオペレーションキューをいつ使うか

  • ディスパッチキューは、マルチスレッド対応やタスク管理の唯一のソリューションではない。
  • オペレーションキューは、GCDができるほとんどのことを実行できる高水準のObjective-C APIである。GCDではコードを追加しなければ実現できないような複雑なことでも、オペレーションキューならかなりのことができる。

項目44 プラットフォームのスケーラビリティ活用のためディスパッチグループを使う

  • ディスパッチグループは、一連のタスクをグループにまとめるために使われる。オプションで、グループが実行を終了したときに通知を受け取ることもできる。
  • ディスパッチグループは、並行キューを使って複数のタスクの同時スケジューリングを処理する。自分でこのコードを書こうとすると、かなりの量のコードを書かなければならなくなる。

項目45 スレッドセーフなコードのワンショット実行にはdispatch_onceを使う

  • スレッドセーフなワンショット実行はよく使われる処理だ。GCDは、この処理のために、dispatch_once関数という使いやすいツールを提供している。
  • 一度ずつ実行される各ブロックにまったく同じトークンが渡されるようにするために、トークンはstaticまたはglobalスコープで宣言しなければならない。

項目46 dispatch_get_current_queueは避ける

  • dispatch_get_current_queue関数は、一般に期待通りの仕事をできない。この関数は使わない方がよいとされており、今使ってよいのはデバッグ用としてだけだ。
  • ディスパッチキューは階層構造にまとめられているので、現在のキューは単一のキューオブジェクトで簡単に表現できない。
  • dispatch_get_current_queueを使いたくなる普通の状況(歳入可能でないコードのために起きるデッドロックを避ける)は、キュー固有データを使えば解決できる。

第7章 システムフレームワーク

項目47 システムフレームワークに慣れよ

  • 開発に使えるシステムフレームワークがすでに多数用意されている。もっとも重要なFoundationとCoreFoundationは、多くのアプリケーションの基礎となるコア機能を提供する。
  • オーディオビデオ処理、ネットワーキング、データ管理など、多くの共通機能に対してはフレームワークが作られている。
  • Objective-Cではなく純粋Cで書かれたフレームワークも重要だということを忘れてはならない。優れたObjective-Cデベロッパーになるためには、Cの基本概念を理解していなければならない。

項目48 forループではなく、ブロックの反復処理を使う

  • コレクションの反復処理には4種類の方法がある。forループが最も基本的なもので、NSEnumeratorや高速反復処理を使った方法がそれに次ぐ。もっとも新しく高度な反復処理の方法は、ブロックベースの方法である。
  • ブロックベースの反復処理を使えば、コードを書き足すことなくGCDを利用してイテレーションを並行実行できる。ほかの反復処理テクニックでは並行処理は簡単に実現できない。
  • オブジェクトの性格な型がわかる場合には、その型を使ってブロックシグネチャを書き換えよう。

項目49 カスタムのメモリ管理属性を指定したコレクションを作るためにToll-free bridgeを使う

  • Toll-free bridgeを使えば、FoundationのObjective-CオブジェクトとCoreFoundationのC構造体を相互にキャストできる。
  • CoreFoundationに下りてコレクションを作れば、コレクションが格納するオブジェクトを処理するときに使うコールバックを指定できる。このようにして作ったコレクションをToll-free bridgeでキャストすれば、カスタムメモリ管理属性を指定したObjective-Cコレクションを作れる。

項目50 キャッシュではNSDictionaryではなくNSCacheを使う

  • NSDictionaryオブジェクトをキャッシュとして使うつもりなら、代わりにNSCacheを使うことを検討しよう。NSCacheは、辞書とは異なり、内容の一部に最適な切り捨て、スレッド安全性、キーのコピーなしをサポートする。
  • キャッシュからオブジェクトを捨てるタイミングを定義する指標としては、個数の上限とコストの上限を使う。しかし、これらの指標をあまり杓子定規に捉えてはならない。これらは純粋にガイドラインとして扱われる。
  • キャッシュとNSPurgeableDataを利用すると、自動的にパージされるデータが得られる。データはパージされたときキャッシュからも自動的に削除される。
  • 正しく使えば、キャッシュによってアプリケーションは機敏に反応するようになる。ネットワークからフェッチしたりディスクから読み出したりしなければ成らないデータのように、再計算が高価なデータだけキャッシュするようにしよう。

項目51 initializeとloadの実装は軽くする

  • クラスのロード段階を通り過ぎるときに、そのクラスがloadメソッドを実装していればそれが呼び出される。loadメソッドはカテゴリにも含まれていることがあるが、その場合はカテゴリのloadの前にクラスのloadが実行される。ほかのメソッドとは異なり、loadメソッドにはオーバーライドがない。
  • クラスが初めて使われる前に、そのクラスにはinitializeメッセージが送られる。このメソッドはオーバーライドされるので、どのクラスが初期化されようとしているのかをチェックするとよい。
  • loadとinitializeの実装はともに軽くすべきだ。そうすれば、アプリケーションの反応を機敏なものにする上で役立ち、相互依存の関係が持ち込まれる危険性を防げる。
  • initializeメソッドは、コンパイル時に実行できないグローバルな状態のセットアップに専念させるようにしよう。

項目52 NSTimerがターゲットを保持することを忘れずに

  • NSTimerオブジェクトは、作動するか明示的なinvalidate呼び出しを受けるかして無効化されるまで、ターゲットを保持し続ける
  • 反復タイマを使い、タイマのターゲットがタイマを保持していると、簡単に循環参照が発生する。循環参照は、直接、あるいはオブジェクトグラフのほかのオブジェクトを通じて間接的に発生する。
  • 循環参照を破るためには、NSTimerのブロックを使う拡張を利用する。この機能がNSTimerの公開インターフェースの一部になるまでは、カテゴリを使ってこの機能を追加しなければならない。