Start Developing iOS Apps Today(sup.8)〜アプリ設計の注意

2012. 12. 30
iOSアプリの開発に不慣れな場合、アプリ開発の行程の開始は不思議に思うかもしれません。
アプリに向けて最初のアイディアを考案したら、アプリに実装するためのアクション計画にアイディアを反映させる必要があります。
設計の観点から、アイディアを実現するために最善となる行動の行程について、いくつかの高レベルな決定を行う必要があります。
それからアプリ開発を勧めることができます。

iOSアプリケーションプログラミングガイド』には、この記事で言及している多くの概念、アーキテクチャ、そして技術の詳細が説明されています。



●初期設計を行う

アプリの設計には多くの方法がありますが、最良のアプローチの多くはコードの記述と関係ありません。
優秀なアプリは優秀なアイディアから始まり、それからより完全な機能を備えた製品の説明に展開します。
設計の早い段階では、貴方がアプリで何を行いたいのかを正しく理解するのに役立ちます。
貴方のアイディアを実装するために必要となる、高レベルな機能の設定を書き留めます。
ユーザが必要と思われるものに基づいて、それらの機能に優先順位を付けます。
その機能を理解し、貴方の目標を達成するために使用することができる可能性を探るため、iOS自身を少し研究します。
貴方のアプリがどのように見えるかを視覚化するために、大まかなインターフェイスの設計を紙の上にいくつかスケッチします。

初期設計の目標は、貴方のアプリについていくつかの非常に重要な質問に答えることです。
機能の設定とインターフェイスの大まかなデザインは、コードを書き始めた後に必要となるものについて考えるのに役立ちます。
いくつかの時点では、データオブジェクトのセットに貴方のアプリによって表示される情報を翻訳する必要があります。
同様に貴方のアプリの外観は、ユーザインターフェイスのコードを実装する際にしなければならない選択に圧倒的な影響力を持っています。
(コンピュータ上よりもむしろ)紙の上で初期設計を行うと、制限されず容易に答えを導くための自由度が得られます。

もちろん最も重要なことは、設計を始める前に『iOSヒューマンインターフェイスガイドライン』を読むことです。
このドキュメントは、初期設計を行うためのいくつかの戦略を説明しています。
またiOSで正しくアプリを生成する方法についてのヒントやガイダンスを提供しています。

iOS技術の概要』は、iOSの機能と、それらの機能をどのように使用して設計目標を達成するかについて説明しています。



●アクション計画に初期設計を翻訳

iOSは全てのアプリがモデル-ビュー-コントローラデザインパターンを使用して構築されていることを前提にしています。
したがって、この目的の達成に向けて取ることができる最初の行程は、アプリの一部であるデータとビューのためのアプローチを選択することです。

  • データモデルのための基本的なアプローチの選択

    • 既存のデータモデルのコード
      既にCベースの言語で記述されたデータモデルのコードを持っている場合、iOSアプリに直接コードを統合することができます。
      iOSアプリはObjective-Cで記述されているので、他のCベースの言語で記述されたコードが問題無く動作します。
      もちろんObjective-Cではない任意のコードのために、Objective-Cのラッパーで記述する利点もあります。

    • カスタムオブジェクトのデータモデル
      通常カスタムオブジェクトは、データの管理と一貫性を確保するために必要なビジネスロジックを伴う(文字列や数値、日付、URL等の)いくつかの単純なデータの組み合わせです。
      カスタムオブジェクトは、スカラー値と他のオブジェクトへのポインタの組み合わせを格納することができます。
      例えばFoundationフレームワークは、多くの単純なデータ型と他のオブジェクトのコレクションを格納するためのクラスを定義しています。
      これらのクラスは独自のカスタムオブジェクトを定義するよりも遥かに簡単です。

    • 構造化されたデータモデル
      貴方のデータが高度に構造化されている(つまりデータベース内のストレージを利用できる)場合、データの格納にCore Data(またはSQLite)を使用します。
      Core Dataは、構造化されたデータの管理に単純なオブジェクト指向のモデルを提供します。
      またアンドゥやiCloudのようないくつかの高度な機能のサポートを組み込みで提供しています。
      (SQLiteファイルはiCloudと連携して使用することはできません。)

  • ドキュメントのサポートを必要とするかどうかの決定

    ドキュメントの仕事はアプリのメモリ内のデータモデルオブジェクトを管理し、ディスク上の対応するファイル(またはファイルのセット)のデータのストレージを調整することです。
    ドキュメントは通常ユーザが生成したファイルを意味しますが、アプリがユーザ向けではないファイルの管理にドキュメントを使用することもできます。
    ドキュメントを使用する大きな利点の1つは、UIDocumentクラスがiCloudとローカルファイルシステムとの相互通信をとても簡単に作成するということです。
    コンテンツの格納にCore Dataを使用するアプリでは、UIManagedDocumentクラスが同様のサポートを提供します。

  • ユーザインターフェイスのためのアプローチの選択

    • 構成要素アプローチ
      ユーザインターフェイスを生成する最も簡単な方法は、既存のビューオブジェクトを使用して組み立てることです。
      ビューはテーブルやボタン、テキストフィールドなどの視覚的要素を表します。
      多くのビューはそのまま使用しますが、貴方のニーズを満たすために必要に応じて標準のビューの外観や動作をカスタマイズすることもできます。
      またカスタムビューを使用して新しい視覚的要素を実装し、貴方のインターフェイスにそれらのビューと標準のビューを自由に混在させることもできます。
      ビューの利点は一貫したユーザ体験を提供し、迅速かつ比較的少ないコードで複雑なインターフェイスを定義できることです。

    • OpenGL ESベースのアプローチ
      貴方のアプリが頻繁な画面の更新または精巧なレンダリングを必要とする場合は、おそらくOpenGL ESを使用して直接コンテンツを描画する必要があります。
      OpenGL ESの主な用途は、可能な限り最高のパフォーマンスを必要とするゲームや、精巧なグラフィックスに大きく依存するアプリです。


●アプリ制作行程の開始

アクション計画を考案した後は、コーディングを開始する時間です。
iOSアプリの記述に不慣れな場合、開発用に提供されている最初のXcodeのテンプレートを調べるために、時間をかけるのは良いことです。
これらのテンプレートは貴方の作業を大幅に簡素化し、数分でアプリの起動と実行を可能にします。
また、これらのテンプレートは貴方の特有のニーズをより正確にサポートするために、貴方の初期プロジェクトをカスタマイズすることができます。
そのためXcodeプロジェクトを生成する場合には、以下の質問に対する答えを既に持っている必要があります。

  • 貴方のアプリの基本的なインターフェイスのスタイルは何ですか?
    アプリの種類が異なれば、必要となる初期のビューやビューコントローラの設定も異なります。
    どのようなユーザインターフェイスの構成を計画しているかを認識することで、貴方のニーズに最も適した初期のプロジェクトテンプレートを選択することができます。
    ユーザインターフェイスは後からいつでも変更することができますが、最初に最も適切なテンプレートを選択することで、プロジェクトを遥かに容易に開始することができます。

  • ユニバーサルアプリ、あるいはiPadまたはiPhoneのいずれかを特定のターゲットとして作成しますか?
    ユニバーサルアプリを作成では、iPadとiPhone用にビューとビューコントローラで異なる設定し、実行時に適切な設定を動的に選択する指定を行う必要があります。
    ユニバーサルアプリはより多くのiOSデバイスをサポートするため好ましいですが、各プラットフォーム用により良いコード考慮する必要があります。

  • 貴方のアプリはストーリーボードを使用しますか?
    ストーリーボードはユーザインターフェイスのビューとビューコントローラの両方、およびそれらの間の遷移を表示することによって、設計行程を簡素化します。
    ストーリーボードはiOS 5以降でサポートされ、新規プロジェクトではデフォルトで有効になっています。
    それより前のiOSバージョンでアプリを実行する必要がある場合は、ストーリーボードを使用することができず、nibファイルを継続して使用する必要があります。

  • データモデルにCore Dataを使用しますか?
    アプリの種類によっては構造化されたデータモデルをそのまま使用する方が向いていますが、Core Dataを使用するための理想的な候補になる場合もあります。

Xcodeをインストールした後、貴方のiOS開発チームを構成し、Xcodeでアプリのプロジェクトを生成して、アプリの開発を始めることができます。
以下のアプリ開発の段階は共通しています。

  1. アプリの主要なコードの記述を開始

    新規アプリでは、おそらく最初にアプリのデータモデルに関連付けされたクラスの生成から始まります。
    通常これらのクラスは、アプリの他の部分に依存すること無く、最初に取り組むことができるはずです。
    またメインのストーリーボードあるいはnibファイルにビューを追加することによって、ユーザインターフェイスの設計に思案を巡らせ始める場合もあります。
    またこれらのビューから、インターフェイスに関連付けされた変化に応答する必要があるコードの場所を識別を始めることもできます。
    貴方のアプリがiCloudをサポートする場合、早い段階で貴方のクラスにiCloudのサポートを組み込む必要があります。

  2. アプリの状態変化のサポートを追加

    iOSでは、アプリの状態はその時に何が実行できるかによって決定されます。
    アプリの状態は貴方のアプリの高レベルのオブジェクトによって管理されますが、同様に多くの他のオブジェクトに影響を及ぼす可能性もあり、したがって現在のアプリの状態が貴方のデータモデルとビューコードにどのような影響を及ぼすかを検討し、適切にコードを更新する必要があります。

  3. アプリをサポートするために必要なリソースの生成

    App Storeに提出するアプリは、全体的なユーザ体験をより良いものにするために、アイコンや起動画像などの特定のリソースを持つことを期待されています。
    また適切に組み込まれたアプリはコードを維持するために、操作しているコードのデータから、多用しているリソースファイルを分離しています。
    この組み込み方法はアプリのローカライズをはるかに簡単に行うことができ、外観の微調整や、任意のコードを書き換えること無く他のタスクを実行します。

  4. 必要に応じて、適切なアプリ固有の動作をアプリに実装

    アプリの起動やシステムとの相互通信の方法を変更するには、多くの方法があります。
    例えば特定の機能のためにローカル通知を実装することができます。

  5. 唯一のアプリを作成する高度な機能の追加

    iOSにはマルチメディアの管理や高度なレンダリング、ゲームコンテンツ、地図、連絡先、位置追跡など、他にも多くの高度な機能を含むフレームワークが大量にあります。
    iOS技術の概要』では、貴方のアプリに組み込むことができるフレームワークや機能の概要を説明しています。

  6. アプリのためのいくつかの基本的なパフォーマンスチューニング

    全てのiOSアプリは可能な限り最高のパフォーマンスを得るためにチューニングする必要があります
    チューニングされたアプリは高速で実行できるだけではなく、メモリやバッテリ寿命などのシステムリソースをより効率的に使用します。

  7. 反復適用

    アプリ開発は反復的な行程です。
    新しい機能を追加する場合、既存のコードの調整に、前述の行程のいくつか、あるいは全てを再検討する必要があります。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Design Your App with Care

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.7)〜ユーザを意識したデザイン

2012. 12. 27
iOSアプリの成功は主にユーザインターフェイスの品質に依存します。
ユーザが魅力的で使い易いアプリを見つけられない場合でも、最も速く、強力で、完全な機能を持つアプリはApp Storeで生き長らえることができます。

最初のインスピレーションから人気のあるアプリにする方法はたくさんありますが、成功を保証する道は一つではありません。
しかし全ての成功したアプリの開発が依存している1つの指示があります。
それはユーザを意識したデザインです。
以下の計画とベストプラクティスの概要は全てこの指示に基づいており、これらは貴方がアプリを設計する際に従う必要がある多くの原則とガイドラインのいくつかを表しています。
作業を始める準備ができたら、構想を完全なものにするために『iOSヒューマンインターフェイスガイドライン』を必ず読んでください。



●人々のデバイス使用法の理解

貴方がiOSに不慣れな場合、最初の行程は自身がiOSユーザになることです。
その後、開発者としてではなくユーザとして、可能な限りiOSプラットフォームの特性を調べます。
貴方が最初からiOSベースのデバイスを使用していたか、または以前から所持していなかったかどうかによって、貴方の期待とデバイス使用時の行動の分析を明確にするために時間がかかります。

IntroUserInterface_2x.jpg

例えば、以下に述べるデバイスとソフトウェアの機能がユーザ体験にどのような影響を及ぼすかを検討します。

  • iPhone、iPad、そしてiPod touchは、人々が外出先で使用することを可能および推奨するハンドヘルドデバイスです。
    人々はアプリの起動が速く、様々な環境で容易に使用できることを期待しています。

  • 全てのiOSベースのデバイスは、サイズに関係無くディスプレイが最も重要になります。
    比較的小さなデバイスでは、人々がアプリを使用して作業している間、ディスプレイ周辺の余白はほとんど見えなくなります。

  • マルチタッチインターフェイスは、マウスなどの他のデバイスが介在すること無しに人々がコンテンツを操作することができます。
    人々は画面上にある要素の操作にタッチを使用することができるので、アプリ体験の制御をより感じる傾向があります。

  • 最前面には同時に1つだけアプリがあります。
    ユーザはマルチタスクバーを使用することでアプリ間の切り替えを迅速かつ容易にすることができますが、コンピュータのディスプレイ上で複数のアプリを同時に開いて見るような体験とは異なります。

  • 通常は、ウィンドウを分割してアプリを同時に開くことはできません。
    代わりに、ユーザがコンテンツの画面間を移行して、複数のビューをそれぞれ含めることができます。

  • 組み込みの『設定』アプリは、デバイスおよびその上で実行するいくつかのアプリの両方のユーザ設定を含みます。
    『設定』を開くには、ユーザは現在使用しているアプリからは慣れて切り替える必要があるので、これらは『設定は一度、かつ変更は稀』な種類のユーザ設定にします。
    ほとんどのアプリは『設定』にユーザ設定を追加するのを避けていて、代わりに人々がアプリのメインユーザインターフェイス内で選択できるようにしています。

優秀なiOSアプリは実行しているプラットフォームを利用し、デバイスとプラットフォームの機能がシームレスに統合された体験を提供していることを覚えておいてください。



●基本的なヒューマンインターフェイスの原則を学ぶ

ユーザとして、貴方の入力を受信したかどうか、またはポップオーバーが明確な理由無しに画面上の異なる領域から現れるなど、アプリの伝え方が難解なことがあることに貴方は気付くでしょう。
このような場合、アプリがヒューマンインターフェイス設計の基本的な原則に従っていないと理解してください。

この文脈でのヒューマンインターフェイスという用語は、人々とデバイス間(それらの上で実行されるソフトウェアも含めて)の相互作用を表します。
アプリ(またはデバイス)は、人々が実際に想定した振る舞いの方法でヒューマンインターフェイスを構築すると、人々にとって使い易く楽しめるものになります。

Appleのヒューマンインターフェイスの設計原則は、ユーザ体験の視覚効果を持つ、いくつかの高レベルのヒューマン-デバイスの相互作用の側面を成文化しています。
貴方がアプリを設計する際、以下のヒューマンインターフェイス設計の原則に留意してください。

  • 審美的整合性
    審美的整合性は、アプリがどのように美しいかの尺度ではなく、アプリの外観と機能がどのように統合されているかの尺度です。

  • 一貫性
    インターフェイスの一貫性は、人々があるアプリから別のアプリへ知識や技能を移行できることです。
    アプリがiOSの標準とアプリ自身、そして自身の以前のバージョンと調和しているのが理想的です。

  • 直接操作
    人々が操作に独立したコントロールを使用する代わりに画面上のオブジェクトを直接操作する場合、行為の結果がよりタスクとかみ合い、容易に理解することができます。

  • フィードバック
    フィードバックは人々の行為を認識し、処理が行われていることを保証するものです。
    例えば、人々はコントロールを操作した時に、時間のかかる操作をしている間は状態の更新が理解できるように、即時フィードバックされることを期待しています。

  • メタファー
    アプリ内の仮想オブジェクトとアクションが現実世界のオブジェクトとアクションのメタファーである場合、ユーザはアプリをどのように使用するかをすぐに理解することができます。
    最も適切なメタファーは、現実世界に基づいてオブジェクトやアクションの制約を強制すること無く、慣例や体験を提示することです。

  • ユーザコントロール
    アプリは危険な結果について手段や警告を提示することができますが、通常はアプリがユーザの手から離れて解決を決定するのは誤りです。
    最善なアプリは、危険な結果を回避するために人々が必要とする機能と手助けとの間に、訂正する決定を確認することです。


●ガイドラインに従う

iOSヒューマンインターフェイスガイドライン』は、iOS技術の処理と画面上の要素を管理する、推奨されるユーザ体験から具体的な規約に及ぶ指針です。
この項は『iOSヒューマンインターフェイスガイドライン』の要約としては機能しませんが、成功したアプリを設計するのに役立つガイドラインの典型を体感できます。

優秀なiOSアプリは、人々にコンテンツへの合理的なアクセスを与えるように気を配っています。
これを行うには、下記に示すユーザ体験のガイドラインをアプリに組み込みます。

  • 主要なタスクに焦点を合わせる
  • 使用法は簡単で明快にする
  • ユーザ中心の用語を使用する
  • ターゲットは指先のサイズにする
  • 設定は強調しない
  • 一貫したユーザインターフェイス要素を使用する
  • 通信には繊細なアニメーションを使用する
  • 必要な場合のみ人々に保存するか尋ねる

ユーザはアプリに対してマルチタスクやiCloud、VoiceOver、そして印刷などのプラットフォームの機能を組み込むことを期待しています。
たとえこれらの機能が自動的に利用できるとユーザが考えているとしても、彼らはそれらを統合する作業が必要であることをアプリ開発者は知っています。
アプリがこれらの機能への対応を期待されるユーザ体験を提供することを確認するには、開発者は以下のようなiOSのテクノロジーガイドラインに従ってください。

  • 簡単で明快なiCloudストレージのサポート
  • マルチタスクに関連した中断と復帰準備への備え
  • ローカルとプッシュ通知の処理における、ユーザの通知センターの設定の準拠
  • VoiceOverユーザが利用し易いアプリにするための説明的な情報の提供
  • 印刷が可能であるとユーザが理解できるように、システムが提供する印刷UIに依存する
  • サウンドが全ての状況でユーザの期待に応えて聴こえることを保証する

アプリがボタンやタブバーなどのUI要素を正確に使用している場合、ユーザはアプリが期待通りに動作するだけだとおそらく分かるでしょう。
しかしアプリが間違ったUI要素を使用している場合、ユーザは大抵即座に不満を口にするでしょう。
優秀なiOSアプリは次のようなUI要素の使用法のガイドラインに気をつけています。
例えば、

  • ナビゲーションバーのバックボタンには、前の画面のタイトルを表示することを保証してください。
  • その機能が利用できない場合に、タブバーからタブを削除しないでください。
  • 『Popoverを却下する』ボタンの提供は避けてください。
  • テーブルビューに表示されている項目をユーザが選択した場合、常にフィードバックを提供してください。
  • iPadにおいて、Popover内でのみピッカーを提示してください。
  • システムが提供するボタンやアイコンは、文書化されている意味に従って使用してください。
  • カスタムのアイコンや画像を設計する場合、全てのユーザが理解でき、AppleのUI要素や製品の模写を避けた、一般的なイメージを使用します。

繰り返しになりますが、この項で記載しているガイドラインのリストは、『iOSヒューマンインターフェイスガイドライン』に含まれている指針の一部を表しています。
このドキュメント全体読むことは、アプリ開発の工程で重要なステップです。



●いくつかの実証された設計戦略を利用する

最も成功したiOSアプリは、多くの場合設計の思索を反復した結果です。
開発者が主要なタスクに集中し、機能リストの洗練を継続した時、上質なユーザ体験を生成することができます。
この項の戦略の要約は、貴方のアイデアの洗練や、オプションの設計を再考、そして人々が歓迎するようなアプリに収束させるのに役立てることができます。

機能リストの純化
設計行程のできるだけ早い時期に、アプリが何を行うのかと、ターゲットとする顧客は誰かを明確に定義します。
不必要な機能を取り除き、アプリの様式を導くには(アプリケーション定義ステートメントと呼ばれる)この定義を使用します。
機能が多い方がより良いアプリになると考えがちですが、多くの場合は逆と言えます。
最高のアプリは主要なタスクに能力を集中し、ユーザが必要とするタスクを遂行する機能のみを提供する傾向があります。

デバイスのための設計
更にiOSのユーザインターフェイスとユーザ体験の様式を統合して、貴方のアプリがそのデバイスに対応していることを確認してください。
(つまりiPhoneとiPadの両方で実行できるアプリ)を開発する予定の場合、各デバイス用に異なるUIを設計する必要があることを意味しますが、基本となるコードはほとんど同じにすることができます。
同様に、ウェブベースのコンテンツで開始する予定の場合、ネイティブアプリのような外観と操作法のコンテンツに設計し直すことが重要です。

適切なカスタマイズ
全てのアプリにはApp Storeのアイコンだけでも、いくつかのUIのカスタマイズが含まれます。
iOS SDKは全てのUIの様相をカスタマイズ機能を提供していますが、〜まで(果たすように、〜できる 決定 どの程度のカスタマイズが適切かを決定するのは貴方の責任です。
最高のアプリは目的の明瞭さと使い易さの調和のとれたカスタマイズです。
理想的には、貴方のアプリの独自性をユーザに認識してもらいつつ、同時に一貫性を保った直感的に認識できて使い易いアプリを作成します。

プロトタイプと反復適用
どのような機能を含めるかを決定した直後、テスト可能なプロトタイプの生成を開始します。
初期のプロトタイプは、実際のUIまたは絵の表示や、実際のコンテンツでの処理は必要ありませんが、アプリがどのように動作するかの精密なアイディアはテスターに提供する必要があります。
テスト中、テスターが試みて実行しなかったものは、アプリが期待に沿わない動作をする恐れがあるので、そのような試みの箇所を明らかにすることができるように特に注意を払う必要があります。
アプリがどのように動作し、全ての機能をどう操作するのかをユーザが容易に把握できるように、貴方が納得できるまでテストを継続します。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Design with the User in Mind

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.6)〜デザインパターンを使ったアプリの合理化

2012. 12. 24
Objective-Cプログラミングにおいて、アプリに固有の動作を追加する1つの方法は継承を介して行われます。
スーパークラスの属性や動作を増補するか、いくつかの方法でそれらを修正して、既存のクラスのサブクラスを生成します。
しかし他にもサブクラス化を伴わずに、アプリ固有の動作を追加するより動的な方法があります。
これらの動的な技術とアプローチはデザインパターンに基づいています。
この記事が説明するように、貴方のコードにデザインパターンを採用することで、貴方のクラスとフレームワークのクラスの両方に再利用性と拡張性を提供します。



●デザインパターン:プログラミングの問題を解決するためのデザインのテンプレート

デザインパターンはオブジェクト指向のソフトウェア開発だけでなく、他の分野でも使用される抽象化のツールです。
テンプレートは一般的に、特定の状況で繰り返し発生する問題を解決するための設計です。
デザインパターンは特定するためのガイドのようなもので、実際の設計はある意味でパターンの『インスタンス化』と言えます。
適用することができるデザインパターンは柔軟性があり、多くの場合プログラミング言語や既存のアーキテクチャなどによって適用されるパターンが決定されます。

いくつかの設計のテーマまたは原理はデザインパターンに影響を与えます。
これらの設計原理は、『変化するシステム構成のカプセル化』や『実装ではなく、インターフェイスへのプログラム』など、オブジェクト指向システムを構築するための経験則です。
これらは重要な洞察を表現しています。
例えばカプセル化の原則は変化するシステムの一部を分離したい場合、それらをカプセル化し、システムの他の部品から独立して変更することができるようにすることで、特に実装の仕様に縛られないインターフェイスを定義する場合に用いられます。
そうすることでシステムの他の部品に影響を及ぼすこと無く、それらの可変部品を後から変更または拡張することができます。
このように部品間の依存状態を排除し結合を減らすことによって、システムはより柔軟かつ変更を容易にすることができます。

このような利点は、ソフトウェアを記述する際にデザインパターンの重要な考慮事項です。
アプリの設計でパターンに気付く、あるいは適応させたり使用する場合、
将来に要件が要求された際、プログラム(および構成するオブジェクトやクラス)の再利用や拡張がより容易になります。
更に、デザインパターンに基づいたアプリは一般的にそうではないアプリよりも洗練され且つ効率的になり、同じ目的を果たすためのコード行数が少なくなります。

貴方はCocoa TouchとCocoaフレームワーク、およびObjective-Cのランタイムと言語の全般で、デザインパターンの適応を見つけることができるでしょう。
これらのパターンベースのメカニズムのいくつかはほとんど『無償で』取得できますが、他の貴方の部品は作業をする必要があります。
状態が保証されている場合、貴方の独自のアプリのコードにデザインパターンを適用することができます。
貴方がCocoa TouchやCocoaフレームワークが使用しているものと同じパターンを使用する場合、貴方のコードはフレームワークのコードとより良く適合し、より洗練された動作をする傾向があります。



●最も重要なデザインパターン:モデル-ビュー-コントローラ

(一般的にMVCとして知られる)モデル-ビュー-コントローラデザインパターンは、アプリのオブジェクトを(モデル、ビュー、コントローラの)3つの役割のいずれかに割り当てることです。
パターンはアプリ内でのオブジェクトが果たす役割を定義するだけでなく、オブジェクトが相互に通信する方法を定義します。
3つのタイプのオブジェクトそれぞれが抽象的な境界によって他から分離し、それらの境界を越えて他のタイプのオブジェクトと通信します。
アプリ内のMVCタイプのオブジェクトのコレクションは、時々(モデル層など)層と呼ばれます。

model_view_controller_2x.png

MVCは全てのiOSアプリやMacアプリのための優れた設計の中心となるものです。
このパターンを採用することの利益はたくさんあります。
これらのアプリでは多くのオブジェクトが再利用し易くなる傾向があり、そしてインターフェイスがより良く定義される傾向があります。
MVCデザインを持つアプリは、他のアプリよりも容易に拡張することができます。
更に、貴方のアプリが使用することができる多くの技術やアーキテクチャはMVCに基づいており、カスタムオブジェクトはMVCの役割のいずれかを果たす必要があります。

貴方は気付いていないかもしれませんが、『初めてのiOSアプリケーション』のHelloWorldで貴方は既にMVCに基づいたアプリを生成しています。
モデルオブジェクトはuserNameプロパティ(NSStringオブジェクト)が宣言され、HelloWorldViewControllerクラスによって管理されます。
HelloWorldViewControllerとHelloWorldAppDelegateクラスのインスタンスはアプリのコントローラオブジェクトで、アプリのビューオブジェクトはテキストフィールド、ラベル、ボタン、そして背景のビューになります。

モデル-ビュー-コントローラについての詳細は、『Objective-Cプログラミングの概念』の『Model-View-Controllerパターン』を参照してください。


モデルオブジェクト

モデルオブジェクトはアプリのデータをカプセル化し、データの操作や処理の計算とロジックを定義します。
例えばモデルオブジェクトは、ゲーム内の文字やアドレス帳の連絡先を表すことがあります。
時々、アプリのモデル層は事実上の関連するオブジェクトの1つまたは複数のグラフになります。
データの多くは(永続的な状態がファイルまたはデータベースに格納されているかどうかに関わらず)アプリの永続的な状態の一部であり、データがアプリに読み込まれた後にモデルオブジェクトに存在している必要があります。
モデルオブジェクトは特定の問題領域に関連した知識や専門的技術を表しているため、類似した問題領域で再利用することができます。
『純粋な』モデルオブジェクトは、データを表示するビューオブジェクトへの明示的な接続を持っておらず、(ユーザインターフェイスや結果の提示に関連していない)データの編集をユーザに許可しています。

データを生成または変更するビュー層でのユーザのアクションは、モデルオブジェクトの作成または更新した結果を、コントローラオブジェクトを介して伝達します。
モデルオブジェクトが(ネットワーク接続経由で受信した新規データなどで)変更された場合、適切なビューオブジェクトを更新するコントローラオブジェクトに通知します。


ビューオブジェクト

ビューオブジェクトはユーザが見ることができるアプリのオブジェクトです。
ビューオブジェクトは自身がどのように描画され、ユーザのアクションに応答するかを知っています。
ビューオブジェクトの主な目的は、アプリのモデルオブジェクトからのデータを表示し、データの編集を可能にすることです。
にも関わらず、MVCアプリでのビューオブジェクトは通常モデルオブジェクトから分離されています。

通常ビューオブジェクトは再利用や再構成するため、ビューオブジェクトはアプリ間での一貫性を提供します。
iOSの場合はUIKitフレームワークがビュークラスのコレクションを提供し、OS XではAppKitフレームワークが同様のコレクションを提供します。
UIKitではビューオブジェクトは最終的にUIViewクラスから継承され、AppKitでは最終的にNSViewクラスから継承されます。

ビューオブジェクトはアプリのコントローラオブジェクトを介してモデルデータの変更について知るとともに、コントローラオブジェクトを介してアプリのモデルオブジェクトへ(テキストフィールドへのテキストの入力など)ユーザによって開始された変更について通信を行います。


コントローラオブジェクト

コントローラオブジェクトは、1つ以上のアプリのビューオブジェクトと1つ以上のモデルオブジェクト間を仲介します。
コントローラオブジェクトはビューオブジェクトがモデルオブジェクトの変更について、またはその逆について知らせるために介在する導管です。
またコントローラオブジェクトはアプリのタスクの設定や調整、そして他のオブジェクトのライフサイクルを管理も行います。

コントローラオブジェクトはビューオブジェクトで行われたユーザのアクションを解釈し、モデル層へ新規のまたは変更されたデータを通信を行います。
モデルオブジェクトが変更された場合に表示できるようにするため、コントローラオブジェクトは新しいモデルデータをビューオブジェクトへ通信します。



●デザインパターンと問題の解決

アプリのようなオブジェクト指向システムは動的です。
実行時にオブジェクトが行うことができる処理は、コンパイル時に設定された動作に制限されるものではありません。
オブジェクトは他のオブジェクトにメッセージを送信することができ、同じメッセージのターゲットを実行時の状況によって変更することもできます。
またオブジェクトはアプリの処理を効率的に遂行するため、様々な技術を使用し、実行時に他のオブジェクトの変数グループと協力することができます。
オブジェクトまたはオブジェクトのネットワークがこれを行うためには、デザインパターンに適応した多くの技術とフレームワークのアーキテクチャを活用する必要があります。

以下の項ではこれらの技術とアーキテクチャの多くを説明します。
貴方のObjective-Cプログラミングのツールキットの一部として考えてください。


デリゲーション:他のオブジェクトに代わって動作する

デリゲーションは、あるオブジェクトが他のオブジェクトから依頼された時に、デリゲートを呼び出して代わりに実行することです。
通常、委任するオブジェクトはフレームワークのオブジェクトです。
実行中のある時点でデリゲートへメッセージを送信し、メッセージはいくつかのイベントが発生していくつかの応答を要求することをデリゲートに伝えます。
デリゲート(通常はカスタムクラスのインスタンス)はメッセージによって呼び出されるメソッドを実装し、適切な値を返します。
多くの場合、その値はアクションを続行するかどうかを委任するオブジェクトに伝えるブール値です。

delegation_2x.png

デリゲーションは、(そのクラスのサブクラスを有すること無く)フレームワークのクラスの処理にアプリケーション固有の動作を導入する手段です。
これはフレームワークの動作を拡張して影響を与えるための、一般的かつ強力な設計です。

初めてのiOSアプリケーション』で作業をした時にHelloWorldアプリでHelloWorldAppDelegateオブジェクトを生成したことを思い出してください。
Xcodeはフレームワークのオブジェクトであるアプリのオブジェクトのデリゲートとして、自動的に割り当てます。
アプリのデリゲートはapplication:didFinishLaunchingWithOptions:を処理することができ、他のデリゲーションメッセージはアプリのオブジェクトによって送信されます。

デリゲーションには2つのプログラムの構成要素があります。
委任クラスはデリゲートへの参照を保持する(慣例によってdelegateと名付けられる)プロパティを定義する必要があります。
またデリゲートのクラスが採用しなければならないプロトコルを宣言する必要があります(次の項の『プロトコル』を参照してください)。
Cocoa TouchとCocoaフレームワークのクラスの多くは、アプリ固有のものでフレームワークの動作を強化するために、アプリが利用することができるアプローチとしてデリゲーションを提供します。

ただし、デリゲーションはフレームワークのクラスに限定されていません。
アプリ内の2つのカスタムオブジェクト間でデリゲーションを実装することができます。
Cocoa Touchアプリの一般的な設計では、子ビューコントローラが親ビューコントローラに何らかの値(通常はユーザが入力した値)を通信できるようにするための手段としてデリゲーションを使用します。


プロトコル:継承によって関連していないオブジェクト間の通信を有効にする

プロトコルは任意のクラスのメソッドを実装することができるようにする、プログラムインターフェイスの宣言です。
プロトコルに関連付けられたクラスのインスタンスは、プロトコルのメソッドを呼び出し、プロトコルを正式に採用し実装しているクラスによって返された値を取得します。
このオブジェクト間の通信は、XMLコードの解析やオブジェクトのコピーなどの特定の目的を助成します。
どちらのプロトコルインターフェイスのオブジェクトも、継承によって相互に離れて関連付けすることができます。
したがってプロトコルはデリゲーションとしてはサブクラス化の代替であり、多くの場合デリゲーションのフレームワークの実装の一部です。

protocol_2x.png

Appleが提供するフレームワークは多数のプロトコルを宣言します。
更に、貴方のアプリは貴方のクラスが採用することができるカスタムプロトコルを宣言することができます。
プロトコルは貴方のプログラミングツールキットの一部です。
Programming with Objective-C』ではプロトコルの包括的な説明がされています。


通知センター:関連するイベントのオブザーバへの通知

通知センターは、イベントのオブザーバに登録されているアプリ内の全てのオブジェクトにメッセージ(通知)を提供する、Foundationフレームワークのサブシステムです。
(プログラムはNSNotificationCenterクラスのインスタンスです。)
イベントは、例えばアプリがバックグラウンド状態になったり、またはユーザがテキストフィールドへ入力を開始するなど、アプリに発生する何かです。
通知はイベントが発生した、または発生しようとしていることをオブザーバに告げ、オブザーバに適切な方法で応答する機会を与えます。
通知センターによって提供される通知は、アプリ内のオブジェクト間の協調と結束を強めるための方法です。

notificationcenter_2x.png

例えばiOSアプリのビューコントローラは、仮想キーボードを収容するためにビューのジオメトリを調整する通知UIKeyboardWillShowNotificationを観測することができます。
この例が示すように、通知は特定のイベントを示す名前と、イベントが発生した、または発生しようとしているかどうかを持っています。
また通知センターに通知を投稿(または送信)するオブジェクトへの参照を保持し、補足情報の辞書を含むことができます。

全てのオブジェクトは通知を観測することができますが、受信するには登録する必要があります。
登録するには、通知を送付することによって呼び出されるメソッドを識別するセレクタを指定し、メソッドのシグネチャは単一のパラメータ(通知オブジェクト)を持っている必要があります。
登録する際は、オブザーバも投稿オブジェクトを指定することができます。

通知センターの通知はデリゲーションのメッセージに似ており、双方共に特定のイベントが発生した場合に任意のオブジェクトに送信されます。
ただし通知を処理するメソッドはデリゲーションのメソッドとは異なり、値を返すことはできません。
通知センターを経た通知は、デリゲーションと同様に同期します。

貴方のアプリのカスタムオブジェクトは独自の通知を定義および投稿することができ、貴方のアプリの他のカスタムオブジェクトは通知を観測することができます。


ターゲット-アクション:イベント発生時送信されるメッセージをカプセル化

ターゲット-アクションの設計は概念的には単純です。
オブジェクトはメッセージ式を構成する要素を格納し、特定のイベントが発生した時にこれらの要素と一緒にメッセージを送信します。
要素はメッセージ(アクション)を識別するセレクタとメッセージを受信するオブジェクト(ターゲット)です。
ターゲットのクラスはアクションとターゲットに対応するメソッドを実装しており、実行時にメッセージを受信した場合は、メソッドを実行することによってイベントに応答します。

ターゲット-アクションは、主にCocoa TouchとCocoaフレームワークの双方におけるコントロール機能です。
コントロールはユーザがアプリに意志を伝えるために(タップやドラッグなどの)操作をする、ボタンやスライダ、スイッチなどのユーザインターフェイスオブジェクトです。
Cocoa Touchコントロールはアクションとターゲットの両方を格納し、ほとんどのCocoaコントロールはターゲットとアクションを格納する1つ以上のセルオブジェクトと対になっています。

target_action_2x.png

いくつかのフレームワークはコントロール以外のオブジェクトでターゲット-アクションを使用します。
例えばUIKitフレームワークはジェスチャリコグナイザの設計にターゲット-アクションを使用しています。
ジェスチャリコグナイザオブジェクトがジェスチャを認識すると、ターゲットオブジェクトにアクションメッセージが送信されます。


キー値監視:値変更時にオブザーバへ通知

キー値監視(Key-value observingまたはKVO)は、オブジェクトが他のオブジェクトのプロパティを監視することを可能にするものです。
監視オブジェクトはプロパティの値が変更された時に通知します。
古い値が新しい値になったことを知るだけでなく、監視されているプロパティが(配列などの)対多関係の場合、変更に関与しているものを含むオブジェクトも知ることができます。
KVOは変更に同期したモデル、コントローラ、ビュー層のオブジェクトを保持することによって、よりまとまりのあるアプリにするのに役立ちます。

kvo_2x.png

NSNotificationCenterの通知と同様に、複数のKVOのオブザーバは単一のプロパティを監視することができます。
更に、KVOは通知名などの新しいAPIを必要とせずに、オブジェクトが任意のプロパティを監視することができるので、より動的です。
KVOは、全てのインスタンスの特定のプロパティを監視することを許可しない、軽量のPoint-to-Point通信メカニズムです。


デザインパターンに基づいた他のフレームワークの設計

Cocoa TouchとCocoaフレームワークには、次のようなデザインパターンに基づいた他の設計も含まれています。

  • ビュー階層
    アプリが提示するビューは視覚的に基づく階層構造に配置されたコンテナです。
    この形式はアプリが個々のビューとビューの構成物を一様に扱うことができます。
    階層のルートはウィンドウオブジェクトで、ルート下にある各ビューは1つの親ビューと0個以上の子ビューを持ちます。
    親ビューは子ビューを収納します。
    ビュー階層は描画とイベント処理の両方の構成要素です。

  • レスポンダチェーン
    レスポンダチェーンはチェーン内のあるオブジェクトがイベントを処理するまで、順次イベントまたはアクションメッセージを渡すことができる一連のオブジェクト(通常はビューやウィンドウ、ビューコントローラ、そしてアプリケーションオブジェクト自身)です。
    つまり協調的なイベント処理のメカニズムです。
    レスポンダチェーンはビュー階層に密接に関係しています。

  • ビューコントローラ
    UIKitとAppKitフレームワークは双方共にビューコントローラクラスを持っていますが、iOSでは特に重要です。
    ビューコントローラは、ビューのセットを提示および管理するためのコントローラオブジェクトの特殊な種類です。
    ビューコントローラオブジェクトは、コンテンツ関連のビューの管理と表示/非表示を調整するための基盤を提供します。
    ビューコントローラはアプリケーションのビューのサブ階層を管理します。

  • Receptionist
    Receptionistパターンは、アプリがある実行コンテキストから別の実行コンテキストにリダイレクト(または『跳ね返す』)する処理です。
    (実行コンテキストは主スレッドまたは副スレッドに関連付けられたディスパッチキューや操作キューです。)
    Receptionistパターンを適用する状況は、主にユーザインターフェイスを更新する操作など、主キュー上で実行する必要があるタスクが、副キューで実行されている処理に起因している場合です。

  • カテゴリ
    カテゴリはメソッドを追加することによってクラスを拡張する方法を提供します。
    デリゲーションと同様に、サブクラス化せずに動作のカスタマイズをすることができます。
    カテゴリは『Objective-Cコードの記述』で説明しているObjective-Cの特徴です。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Streamline Your App with Design Patterns

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.5)〜コードとフレームワークの統合

2012. 12. 18
iOSまたはOS Xのアプリを開発する場合、独力で行うことはできません。
Appleなどによって開発され、Objective-Cフレームワークに集積されたクラスを利用することになります。
フレームワークは実行時に複数の工程で共有することができるクラスライブラリで、ライブラリを使用してソフトウェア開発をサポートするリソースが含まれています。
CocoaとCocoa Touchフレームワークは、貴方のアプリの一部(多くの場合、重要な部分)を構築するために一緒に作用する相互依存のクラスのセットを提供します。

含まれているC関数のライブラリは、貴方が記述しようとするプログラムで関数を使用して呼び出す際に、必要に応じて精選して使用することができます。
一方フレームワークは、貴方のプログラムに設計を課したり、少なくとも特定の問題空間上で貴方のプログラムが対処することになります。
オブジェクト指向フレームワークを使用する場合、手続き型プログラムにおけるように、多くのプログラムの処理を行うため、フレームワークのクラスのメソッドを呼び出すことができます。
ただし汎用的なフレームワークの動作をカスタマイズしたり、フレームワークが適切な時に呼び出せるようにメソッドを実装することによって対応できるようにする必要があります。
これらの方法はフレームワークによって化せられる構造にコードを導入するフックとなり、貴方のプログラムを特徴付ける動作を増大させます。

以下の項で、フレームワークのコードとアプリケーションのコード間の関係を説明します。



●アプリはイベントによって駆動する

アプリケーションの起動時に何が行われているかを考慮することによって、貴方のコードとフレームワークのコード間の関係について、いくつかの洞察を得ることができます。
基本的にアプリはオブジェクトのコアグループを設定し、それらのオブジェクトに制御を渡します。
プログラムが実行されると次々とオブジェクトが生成されますが、まず必要となるのは最初のタスクを処理するために必要な(つまりコアオブジェクトのネットワークに十分な)構成です。
2つの重要なタスクがあります。
  • アプリの初期ユーザインターフェイスを描画
  • ユーザがユーザインターフェイスを操作した時に受信したイベントの処理
初期ユーザインターフェイスが画面に表示された後、アプリは外部イベントによって駆動されますが、最も重要なのはそれらが(例えば、ボタンをタップするなど)ユーザによって生じることです。
オペレーティングシステムはそのようなイベントを、それらについての情報と一緒にアプリに報告します。
アプリは貴方のコードとフレームワークの両方で構成され、イベントを処理し、それに応じてユーザインターフェイスを更新します。

アプリはイベントを取得して(多くの場合、ユーザインターフェイスの一部を描画することによって)それに応答し、次のイベントのために待機します。
ユーザまたは(タイマーなどの)他のリソースが開始されるまで、取得したイベントを保持します。
アプリが起動した時から終了する時まで、ほとんど全てイベントという形式のユーザのアクションによって駆動します。

イベントを取得して応答するためのメカニズムはメインイベントループです。

アプリオブジェクトとコアオブジェクトの一括りで、一つのオブジェクトとしてメインイベントループを管理する(イベントを取得し、そのオブジェクトまたはそれを処理することができる最適なオブジェクトへイベントをディスパッチし、それから次のイベントを取得する)責任があります。
iOSでのCocoa Touchアプリのメインイベントループを下図に示します。

main_event_loop_2x.png



●オブジェクト指向フレームワークの使用

CocoaとCocoa Touchフレームワークは、個々のサービスを提供するクラスの福袋以上のものです。
これらのオブジェクト指向フレームワークは、構造問題空間と統合されたソリューションを提示するクラスのコレクションです。
(関数ライブラリのように)必要に応じて使用できる個別のサービスを提供する代わりに、フレームワークはアプリケーション全体の構造を計画し実装するため、貴方の独自のコードはそれに適応させる必要があります。
アプリケーション構造は汎用的なものであるため、貴方のアプリ特有の要件を満たすように特化させることができます。
むしろアプリにライブラリ関数を挿入する設計はなく、フレームワークによって提供される設計に貴方のアプリのコードを挿入する形となります。

フレームワークを使用するには、定義されているアプリケーション構造を受け入れて採用する必要があり、必要に応じてアプリ特有の構造に整形するために、多くのクラスをカスタマイズします。
フレームワークのクラスはグループとして相互に依存しており、個々に独立してはいません。
一見すると、アプリ用のフレームワークの構造に貴方のコードを適応させる必要性は限定的に見えるかもしれません。
しかし実際には全く逆です。
フレームワークは汎用的な動作を変更および拡張することができる多くの方法を提供します。
それらは全て同じ構造に基づいているため、同じ基本的な方法で全てのアプリが動作するように適応させることを要求します。

広義に例えるならObjective-Cフレームワークは家の骨組みのようなもので、貴方のアプリのコードは独自の家を造るための戸や窓、羽目板などの要素のようなものです。

house_framework_2x.jpg

フレームワークを使用して貴方のコードと統合するという視点で見た場合、2つの一般的なクラスの種類があります。
  • 既製品
    いくつかのクラスが定義する既製品オブジェクト、つまり使用する準備ができているオブジェクトです。
    貴方は単にクラスのインスタンスを生成し、必要に応じてインスタンスを使用します。

  • 汎用品
    汎用的なフレームワークのクラスで、(いくつかの状況では必然的に)それらのサブクラスを生成し、特定のメソッドの実装をオーバーライドすることができます。
    サブクラス化することによって、アプリケーション構造に貴方のコードを導入します。
    フレームワークは適切な機会にサブクラスのメソッドを呼び出します。
汎用的なフレームワークのクラスのサブクラス化は、フレームワークによって提供された構造に貴方のプログラム固有のコードを統合する主要な手法です。
これは唯一の技術ではありませんが、それ以外は多くの場合は好ましい技術ではありません。
以降の記事で学びますが、Cocoa TouchとCocoaフレームワークはアーキテクチャとメカニズムを含み、全ての設計パターンの基礎であり、双方のフレームワークオブジェクトと貴方のカスタムオブジェクト間で、重要な協調と調整を可能にします。

サブクラスを作成する場合、どのクラス(スーパークラス)から継承するかと、そのクラスのどのメソッドをオーバーライドするかという、2つの基本的な決定する事項があります。
以下の項では、これらの決定を行うための状況を説明します。



●CocoaまたはCocoa Touchクラスからの継承

UIKitなどのフレームワークは構造を定義していますが、一般的なものであるため多くのアプリの種類は共有することができます。
構造は一般的なものであるため、いくつかのフレームワーククラスは抽象的または意図的に不完全ですが、驚くべきことではありません。
このようなクラスは多くの場合、共通するコードのかなりの量を実装しますが、安全なデフォルトの方法で元に戻すか完了し、処理の重要な部分は残します。

フレームワークにアプリケーション固有の動作を追加する主な方法は、これらのフレームワークのいずれかのクラスのカスタムサブクラスを生成することです。
サブクラスはフレームワークのクラスで欠けている部分を供給し、これらのスーパークラスの不足を補充します。
貴方のカスタムサブクラスのインスタンスは、フレームワークが定義するオブジェクトのネットワーク上での役割を引き継ぎ、フレームワークから他のオブジェクトと処理を行う能力を継承します。
アプリで有用な何かを行うためには、少なくとも1つ、できれば多くのサブクラスを生成する必要があります。

以降の解説ではサブクラス化するための計画と解決についての説明と、いくつかの一般的な要件を述べています。
どのようにサブクラスを作成するかについての詳細は含まれていません。
その技術は『Objective-Cプログラミング言語』の『クラスの定義』で説明されています。


サブクラスを作成する際

サブクラス化は既存のクラスを再利用する工程で、貴方の必要とするものに特殊化します。
時には全てのサブクラスが単一継承されたメソッドをオーバーライドする必要があり、メソッドは元の動作とは若干異なる何かを持っています。
他のサブクラスはスーパークラスに(インスタンス変数などの)属性を1つまたは2つ追加するなどして、その後これらの属性へアクセスしたり操作するメソッドを定義し、スーパークラスの動作に統合します。

サブクラス化は、サブクラスにフレームワークのクラスを識別させることから始まります。
ここで貴方を導くためのいくつかの考慮事項があります。

  • フレームワークを知る

    貴方はフレームワークの各クラスの目的と機能を理解する必要があります。
    始めるには、デベロッパライブラリのフレームワークの導入を読み、フレームワークのクラスのリストを調べます。
    多分、貴方が必要とするクラスは既にあると思います。
    貴方が必要とするクラスがほとんど見つけられたら、あなたは幸運です。
    そのクラスは貴方のカスタムクラスのための有望なスーパークラスです。

    例えば『初めてのiOSアプリケーション』での処理の場合、UIViewControllerとUIKitフレームワークのその他のクラスに遭遇しました。
    これらのクラスについて詳細を調べるには、以下の事を行います。

    1. XcodeでWindowメニューのOrganizerを選択します。
    2. ツールバーのDocumentaionボタンをクリックします。
    3. インストール済みのデベロッパライブラリの閲覧を始めるには、ナビゲーション領域の上部にあるBrowse(Explore Documentation)をクリックします。
    4. 最新のiOSライブラリをクリックします(最初にApple Developerにログインする必要があるかもしれません)。
      コンテンツ領域にiOS Developer Libraryが開きます。
    5. ドキュメント領域のドキュメントのリスト上部にあるドキュメントフィルタフィールドに、『UIKit Framework Reference』と入力します。
      フィルタリングされたリストには、入力したドキュメントの名前だけが表示されます。
    6. UIKitの全てのクラスとプロトコルを表示するページを開くため、ドキュメント名をクリックします。

    導入を読み、それらについてもっと学ぶため、リストされたクラスまたはプロトコルをクリックします。

  • アプリが何を行うのかが非常に明確である

    この助言は全体としてのアプリとアプリの特定の部分に適用されます。
    いくつかのフレームワークのアーキテクチャは、独自のサブクラス化の要件を課します。
    例えば貴方のアプリがドキュメントベースの場合、抽象ドキュメントクラスのサブクラスである必要があります。

  • サブクラスのインスタンスが果たす役割を定義する

    iOSまたはOS X用のアプリ開発では、モデル-ビュー-コントローラのデザインパターンがオブジェクトに役割を割り当てるために使用されています。
    ビューオブジェクトはユーザインターフェイスを表示し、モデルオブジェクトはアプリケーションのデータを保持し(そしてデータを決定するアルゴリズムを実装して)、コントローラオブジェクトはビューとモデルオブジェクト間の仲介を行います。
    オブジェクトが果たす役割を知ることで、どのスーパークラスを使用するかの決定を絞り込むことができます。
    例えばiOSアプリでカスタム描画を行いたい場合、UIKitフレームワークのビュークラスを元にして、UIViewのサブクラスを使うことになるかもしれません。

iOSとOS Xのプログラミングにおいて重要ではありますが、時にはサブクラス化は問題を解決する最善の方法ではありません。
便利なメソッドを少し追加するだけの場合、サブクラスの代わりにカテゴリを生成する場合もあります。
またはアプリケーション固有の動作を挿入するには、デリゲートなどのデザインパターンを元にした、フレームワークの多くの他のリソースのいずれかを使うこともできます。
(これらのパターンはデザインパターンの記事『Streamline Your App with Design Patterns』に記述されています。)
そして、いくつかのフレームワークのクラスはサブクラス化を意図していないことを心に留めておいてください。
リファレンスドキュメントでは、フレームワークのクラスがサブクラス化されることを意図しているかが説明されています。


メソッドのオーバーライド

任意のスーパークラスのメソッドを再実装せずにサブクラスを生成することも可能です。
例えばサブクラスに特別な状態を追加したり、状態にアクセスする新しいメソッドを定義したり、スーパークラスのメソッドを呼び出すこともできます。
ただし、いくつかのサブクラスの主なタスクは、スーパークラス(またはスーパークラスによって採用されたプロトコル)によって宣言されたメソッドの独自の設定を実装することです。
継承されたメソッドの再実装はメソッドのオーバーライドとして知られています。

フレームワークのクラスで定義されているほとんどのメソッドは実装済みであり、クラスが提供するサービスを得るために呼び出すことができます。
そのようなメソッドはオーバーライドする必要は稀なので、オーバーライドしようとしないでください。
その他のフレームワークのメソッドはオーバーライドすることができますが、そうする理由は滅多にありません。

いくつかのフレームワークのメソッドはオーバーライドされることを意図していますが、フレームワークにプログラム固有の動作を追加できるように存在しています。
多くの場合、フレームワークによって実装されているメソッドは貴方のアプリにとって価値はほとんど、あるいは全くありません。
これらのメソッドの種類のコンテンツを提供するため、アプリは独自のバージョンを実装する必要があります。
フレームワークはアプリの実行中の適切な時期にこれらのメソッドを呼び出します。


呼び出しまたはオーバーライド?

サブクラスでオーバーライドするフレームワークのメソッドは、一般的に貴方が自身を呼び出すメソッドではなく、少なくとも直接ではありません。
貴方は単にメソッドを再実装し、後はフレームワークに任せます。
実際には、アプリケーション固有のバージョンのメソッドを記述することになり、貴方の独自のコードで呼び出すことはあまりないでしょう。
一般的に、フレームワークのクラスはパブリックメソッドを宣言し、開発者は以下の2つの内1つを実行します。
  • クラスが提供するサービスを使用するために呼び出す。
  • フレームワークによって定義されているプログラムモデルに、独自のコードを取り入れてオーバーライドする。
時にはメソッドがこれら両方の種類であり、呼び出し時に有益なサービスを行い、効果的にオーバーライドすることができます。
しかしほとんどの場合、呼び出すことができるメソッドはフレームワークによって完全に定義されており、コード内で再定義する必要はありません。
メソッドをサブクラスで再実装する必要がある場合、フレームワークはそれを行うための特定の処理を持っているので、適切な時にメソッド自体を呼び出します。
フレームワークのメソッドの一般的な2つのタイプを下図に示します。

message_web_2x.png

この図では貴方のカスタムクラスの架空のメソッド(myMethod)が、フレームワークによって実装されているsetNeedsDisplayメソッドを呼び出します。

フレームワークは描画環境を設定するためにいくつかの処理を行い、その後フレームワークで宣言されていて、実際に描画を行うためにカスタムクラスによってオーバーライドされているメソッドdrawRect:を呼び出します。

メソッドのオーバーライドは困難な作業ではありません。
多くの場合、複数のコードの行を必要とせず、メソッドの再実装を慎重に行うことによって、スーパークラスの動作に重要な変更を行うことができます。


スーパークラスの実装を呼び出す

フレームワークメソッドをオーバーライドする場合、継承されたメソッドの動作を置換するのか、あるいは動作を拡張または追加するのかを決定する必要があります。
既存の動作を置換する場合は単にメソッドを独自に実装して提供し、動作を拡張する場合はスーパークラスの実装を呼び出して独自のコードを提供します。

superのメソッドを呼び出す場合と同じくメッセージを送信することによって、スーパークラスの実装を呼び出します。
superにメッセージを送信することによって、呼び出し時に再実装しているメソッドへスーパークラスのコードが『プラグイン』されます。
例えば架空のCelebrateクラスがperformFireworksという名前のメソッドを定義しているとします。
フレームワークがビューに花火のアニメーションを描画した後、ビューにバナーを表示するとします。
この場合、superがどのように処理を呼び出すかを下図に示します。

calling_super_2x.png

このようにsuperを呼び出すための決定は、どのようにメソッドを再実装しようとしているかに基づいています。
  • スーパークラスの実装の動作を補足するつもりならば、superを呼び出します。
  • スーパークラスの実装の動作を置換するつもりならば、superを呼び出しません。
スーパークラスの動作を補足する場合、他の重要な考慮事項は何時スーパークラスのメソッドの実装を呼び出すかです。
貴方のコードが実行される前にスーパークラスのコードを呼び出したい場合もあれば、逆の場合もあります。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Integrate Your Code with the Frameworks

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.4)〜主要フレームワークの概要

2012. 12. 14
フレームワークは、共有ライブラリやライブラリに格納されているコードへアクセスするためのヘッダファイル、そして画像や音声ファイルなどの他のリソースが含まれているディレクトリです。
共有ライブラリは、アプリが呼び出すことができる関数やメソッドを定義しています。

iOSは、アプリ開発に使用することができる多くのフレームワークを提供します。
フレームワークを使用するには、アプリがリンクできるようにするためプロジェクトに追加します。
ほとんどのアプリは、Foundation、UIKit、Core Graphicsフレームワークにリンクしています。
アプリ用に選択したテンプレートに依っては、その他のフレームワークが含まれる可能性があります。
フレームワークのコアセットが貴方のアプリが要件を満たしていない場合、プロジェクトにいつでも補足するフレームワークを追加することができます。

HelloWorld.xcodeprojに含まれているフレームワークを調べる
  1. (まだ開いていなければ)XcodeでHelloWorld.xcodeprojを開きます。
    以前にチュートリアル『初めてのiOSアプリケーション』でこのプロジェクトは生成しています。

  2. プロジェクトナビゲータにあるFrameworksフォルダの隣にある三角マークをクリックすることによって、フォルダを開きます。
    UIKit.frameworkとFoundation.framework、そしてCoreGraphics.frameworkが表示されるはずです。

  3. 各フレームワークのヘッダファイルは、そのフレームワークの隣にある三角マークをクリックし、それからHeadersフォルダの隣にある三角マークをクリックします。

各フレームワークは、iOSシステムのレイヤに属しています。
各レイヤは、その下のレイヤの上に構築されています。
できるだけ下位レベルのフレームワークの代わりに上位レベルのフレームワークを使用してください。
上位レベルのフレームワークは、下位レベルの構成物をオブジェクト指向で抽象化して提供しています。

framework_layer_2x.png



●iOSアプリはFoundationとUIKitフレームワークに基づいている

プログラミングを始める場合、アプリ開発で必要となる物のほとんどを扱うFoundationとUIKitフレームワークを主に使用します。


Foundationフレームワークは全てのアプリにおける基本的なシステムサービスを提供する

UIKitや他のフレームワークと同様に、アプリはFoundationフレームワークを基盤として構築されています。
Foundationフレームワークは、アプリ開発の基礎を作成する多くのプリミティブオブジェクトクラスとデータ型を提供します。
また、より再利用可能で一貫したコードを作成するための(割り当て解除などの)規則を確立します。

Foundationは以下の処理で使用します。
  • 配列や辞書などのコレクションの生成と管理
  • アプリに格納されている画像や他のリソースへのアクセス
  • 文字列の生成と管理
  • 通知の投稿と観測
  • 日付と時刻オブジェクトの生成
  • IPネットワーク上のデバイスの自動検出
  • URLストリームの操作
  • 非同期のコード実行
初めてのiOSアプリケーション』において、貴方は既にFoundationフレームワークを使用していました。
例えば、userNameにユーザの入力を格納するために、NSStringクラスのインスタンスを使用しました。
また挨拶の文字列の生成に、FoundationのインスタンスメソッドinitWithFormat:を使用しました。


UIKitフレームワークはタッチベースのユーザインターフェイスを生成するためのクラスを提供する

全てのiOSアプリはUIKitに基づいています。
このフレームワーク無しにアプリを出荷することはできません。
UIKitは画面の描画、イベント処理、そして一般的なユーザインターフェイス要素を生成するための基盤を提供します。
またUIKitは、画面上に表示されるコンテンツを管理することによって、複雑なアプリを整理します。

UIKitは以下の処理で使用します。
  • ユーザインターフェイスの構築と管理
  • タッチやモーションベースのイベント処理
  • テキストやウェブコンテンツの表示
  • マルチタスクのためのアプリの最適化
  • カスタムユーザインターフェイス要素の生成
初めてのiOSアプリケーション』ではUIKitを使用していました。
アプリがどのように起動するかを調査した時、ユーザイベントが発生した際に処理を行う、UIApplicationクラスのインスタンスを生成するUIApplicationMain関数を見たことでしょう。
ユーザがDoneキーをタップした時に、キーボードを閉じるためにUITextFieldDelegateプロトコルを実装しました。
実際にはUITextFieldUILabel、そしてUIButtonクラスといった、インターフェイス全体を生成するためにUIKitを使用していました。



●知っておくべきその他の重要なフレームワーク

Core Data、Core Graphics、Core Animation、そしてOpenGL ESフレームワークは、アプリ開発において重要で、習得や精通に時間を要する高度な技術です。


Core Dataフレームワークはアプリのデータモデルを管理する

Core Dataはオブジェクトグラフを管理します。
Core Dataを使用するには、管理オブジェクトとして知られるモデルオブジェクトを生成します。
貴方はそれらのオブジェクト間の関係を管理し、フレームワークを介してデータに変更を加えます。
Core Dataは、データを効率的に格納および管理するため、組み込みのSQLite技術を利用しています。

Core Dataは以下の処理で使用します。
  • ストレージからのオブジェクトの取得と保存
  • 基本的なアンドゥ/リドゥのサポート
  • 自動的なプロパティ値の検証
  • メモリ内のデータをフィルタ、グループ、整理
  • NSFetchedResultsControllerによるテーブルビュー内の結果の管理
  • ドキュメントベースアプリケーションのサポート

Core Graphicsフレームワークはグラフィックスの生成を支援する

高品質なグラフィックスは、全てのiOSアプリの重要な部分です。

iOSでグラフィックを生成するために最も簡単で最も効率的な方法は、UIKitフレームワークの標準のビューとコントローラでレンダリング画像を使用し、iOSで描画することです。
またUIKitは、パス、色、パターン、グラデーション、画像、テキスト、そして変換を含むカスタム描画を行うためのクラスも提供しています。
下位レベルのフレームワークであるCore Graphicsの代わりに、上位レベルのフレームワークであるUIKitをできるだけ使用してください。

iOSとOS Xとの間で直接共有する描画コードを記述したい場合は、Core Graphicsを使用します。
Core GraphicsフレームワークはQuartzとしても知られており、両プラットフォームにおいてほぼ同じものです。

Core Graphicsは以下の処理で使用します。
  • パスベースの線描の作成
  • アンチエイリアシングレンダリングの使用
  • グラデーション、画像、および色の追加
  • 座標空間の変換の使用
  • PDF文書の生成、表示、および解析

Core Animationは高度なアニメーションや視覚効果を追加することができます

UIKitはCore Animation技術の上に構築されているアニメーションを提供します。
UIKitの能力を超えた高度なアニメーションが必要な場合、直接Core Animationを使用することができます。
Core AnimationインターフェイスはQuartz Coreフレームワークに含まれています。
Core Animationを使用すると、操作しているレイヤオブジェクトに回転、拡大縮小、そして変換などの階層を生成することができます。
Core Animationのよく知られているビューに似た抽象化を使用することより、OpenGL ESなどの下位レベルのグラフィックスAPIを使用することなく、動的なユーザインターフェイスを生成することができます。

Core Animationは以下の処理で使用します。
  • カスタムアニメーションの生成
  • グラフィックスにタイミング機能を追加
  • キーフレームアニメーションをサポート
  • グラフィカルなレイアウトの制約を指定
  • 複数のレイヤの変更をアトミックな更新にまとめる

●OpenGL ESフレームワークは2Dおよび3D描画のためのツールを提供

OpenGL ESは基本的な2Dおよび3D描画をサポートします。
Appleの標準OpenGL ESの実装は、フルスクリーンのゲームスタイルのアプリケーション用に高フレームレートを提供するため、デバイスのハードウェアと密接に連携します。

OpenGL ESは以下の処理で使用します。
  • 2Dおよび3Dグラフィックスを生成
  • データの可視化やフライトシミュレーション、またはビデオゲームのような複雑なグラフィックスの作成
  • 基礎となるグラフィックスハードウェアへのアクセス


●iOSとOS XのAPI間の相違点と類似点を理解する

貴方がMacの開発者の場合、CocoaとCocoa Touchアプリは類似した技術に基づいていることに気付くでしょう。
これらの共有しているAPIはCocoaからの移行を容易にしています。
実際にはFoundationとCore Dataのように、いくつかのフレームワークは同一(またはほぼ同じ)です。
しかし他のフレームワークは、OS Xのものとは異なります。
特にAppKitとUIKitがそれに該当します。
したがってMacアプリをiOSに移行する場合、かなりの数のインターフェイス関連のクラスとそれらのクラスに関連するコードを置換する必要があります。

プラットフォーム間の相違点と類似点に関する詳細は、『iOSテクノロジーの概要』の『Cocoaからの移行』を参照してください。



●必要に応じてプロジェクトに他のフレームワークを追加する

アプリで使用することができる、より多くのフレームワークがあります。
既に含まれているフレームワーク以外を使用する必要があると判断した場合、アプリがリンクすることができるようにプロジェクトにフレームワークを追加します。

project_editor_2x.png

HelloWorld.xcodeprojに他のフレームワークをリンクするには
  1. (まだ開いていなければ)XcodeでHelloWorld.xcodeprojプロジェクトを開きます。

  2. HelloWorldプロジェクトのプロジェクトナビゲータをクリックし、プロジェクトエディタを表示します。

  3. ターゲットリストでHelloWorldをクリックし、追加したいフレームワークのターゲットとしてHelloWorldを指定します。

  4. プロジェクトエディタの上部にある『Build Phases』をクリックします。

  5. 『Link Binary With Libraries』の隣にある三角マークをクリックして開きます。

  6. フレームワークを追加するため追加(+)ボタンをクリックします。

  7. リストからフレームワークを選択し、Addボタンをクリックします。

フレームワークの完全なリストや、それらについて多く学ぶためには、『iOSテクノロジーの概要』を参照してください。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Survey the Major Frameworks

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.3)〜基礎プログラミングスキルの習得

2012. 12. 11
Foundationフレームワークは、その名前が示唆するように、iOSとOS X双方における全てのプログラミングの基礎となるツールキットです。
これらのプラットフォームで成功した開発者になるためには、このツールキットに精通する必要があります。

Foundationは様々な目的のために多数のクラスやプロトコルを定義していますが、クラスやプロトコルには特に基礎として傑出している3つのカテゴリがあります。

  • ルートクラスと関連プロトコル
    ルートクラスNSObjectは同名のプロトコルと共に、全てのObjective-Cオブジェクトの基本的なインターフェイスと動作を指定します。
    また、クラスのインスタンスをコピーし、その状態をエンコードできるクライアントにするために、クラスが採用することができるプロトコルもあります。

  • 値クラス
    値クラスは文字列、数値、日付、またはバイナリデータなどのプリミティブなデータ型のためのオブジェクト指向のラッパーで、(値オブジェクトと呼ばれる)インスタンスを生成します。
    同じ値クラスのインスタンスと同じカプセル化された値は等しいとみなされます。

  • コレクションクラス
    (コレクションと呼ばれる)コレクションクラスのインスタンスは、オブジェクトのグループを管理します。
    コレクションの特定の型を識別することは、格納されているオブジェクトにどのようにアクセスするかということです。
    多くの場合、コレクション内の項目は値オブジェクトです。

コレクションと値オブジェクトは、メソッドの引数や戻り値として頻繁に取得するため、Objective-Cプログラミングでは非常に重要です。



●ルートクラスとObjective-Cオブジェクト

クラス階層では、ルートクラスは他のクラスから継承されておらず、階層内の他の全てのクラスは最終的にルートクラスから継承されています。
NSObjectはObjective-Cクラス階層のルートクラスです。
他のクラスはNSObjectからObjective-Cのランタイムシステムへの基本的なインターフェイスを継承します。
これらのクラスのインスタンスは、Objective-Cオブジェクトとしての基本的な性質をNSObjectから導出しています。

ただしNSObject自体のインスタンスは単純なオブジェクトであり、それ以外の何か有用なことができるわけではありません。
貴方のプログラムに固有のロジックやプロパティを追加するには、NSObject、またはNSObjectから直接あるいは間接的に継承された1つ以上のクラスを作成する必要があります。

NSObjectNSObjectプロトコルを採用しており、全てのオブジェクトのインターフェイスに共通する追加メソッドを宣言しています。
更に(NSObjectのクラス定義を含むヘッダファイル)NSObject.hには、NSCopyingNSMutableCopying、そしてNSCodingプロトコルの宣言が含まれています。
クラスがこれらのプロトコルを採用した場合、オブジェクト・コピーやオブジェクト・エンコーディングの機能を備える、オブジェクトの基本的な動作を強化します。
モデルクラス(そのインスタンスがアプリケーションデータをカプセル化し、データを管理するクラス)では、しばしばオブジェクト・コピーやオブジェクト・エンコーディングプロトコルを採用します。

NSObjectクラスと関連するプロトコルは、オブジェクトの生成や、継承チェーンのナビゲート、特性や機能についての問い合わせ、オブジェクトの比較、そしてオブジェクトのコピーやエンコーディングをするためのメソッドを定義しています。
この記事の残りのほとんどは、これらのタスクの基本的な要件について説明しています。



●オブジェクトの観点で考える

実行時、アプリはオブジェクトが連携したネットワークであり、これらのオブジェクトがアプリの処理を行うため相互に通信します。
各オブジェクトは少なくとも1つは他のオブジェクトと接続し、少なくとも1つは応答する役割を担っています。
(孤立しているオブジェクトは、ほとんど価値がありません。)
下図に示すように、ネットワーク内のオブジェクトにはフレームワークオブジェクトとアプリケーションオブジェクトの両方が含まれます。
アプリケーションオブジェクトは、通常はフレームワークをスーパークラスとする、カスタムサブクラスのインスタンスです。
オブジェクトのネットワークは、一般的にオブジェクトグラフとして知られています。

app_as_object_network_2x.png

貴方は参照を介して、これらのオブジェクト間のリレーションシップや接続を確立します。
参照の多くの言語形式には、インスタンス変数、グローバル変数、そして(限られたスコープ内の)ローカル変数があります。
リレーションシップは、一対一または多対一にすることができ、所有権やや親子対応の概念を表現することができます。
これは、あるオブジェクトへのアクセス、通信、または他のオブジェクトの制御を意味します。
参照されるオブジェクトは、自然にメッセージのレシーバとなります。

アプリ内でのオブジェクト間のメッセージは、アプリの機能の一貫性にとって重要です。
オーケストラの音楽家と同様に、アプリ内の各オブジェクトには役割があり、アプリに寄与する動作の限定的な設定を持っています。
オブジェクトはタップに応答する楕円面の表示や、データを持つオブジェクトのコレクションの管理、あるいはアプリの活動の中での主要なイベントを調整することがあります。
しかし実際にそれらに寄与するためには、他のオブジェクトに対して通信できることが必要になります。
つまりアプリ内の他のオブジェクトにメッセージを送信したり、他のオブジェクトからのメッセージを受信できる必要があります。

強く結合したオブジェクト(直接参照を介して接続されたオブジェクト)のメッセージ送信は簡単なことです。
しかしアプリの弱い結合のオブジェクト(オブジェクトグラフ内で遠くに離れたオブジェクト)では、いくつかの他の通信手段が必要になります。
Cocoa TouchとCocoaフレームワークには、(下図に示すような)弱い結合のオブジェクト間の通信を可能にする技術とメカニズムが多く備わっています。
これらのメカニズムと技術は(後で詳しく学ぶ)全てのデザインパターンに基づいており、堅牢で拡張可能なアプリの効率的な構築を可能にします。

communication_loosely_coupled_2x.png



●オブジェクトの生成

オブジェクトは通常、割り当ててから初期化して生成します。
これらは2つの別個な行程ですが、密接にリンクしています。
また多くのクラスは、クラスのファクトリメソッドを呼び出すことによってオブジェクトを生成します。


割り当てと初期化によるオブジェクトの生成

オブジェクトを割り当てるには、オブジェクトのクラスにallocメッセージを送信し、そのクラスの『生の』(初期化されていない)インスタンスを取得します。
オブジェクトを割り当てる時、Objective-Cランタイムはアプリケーションの仮想メモリからオブジェクトに対して十分なメモリを割り当てます。
メモリの割り当てに加えて、ランタイムは全てのインスタンス変数をゼロに設定するなど、いくつかの他の事も行います。

生のインスタンスを割り当てた後、すぐに初期化する必要があります。
初期化は、オブジェクトの初期状態(インスタンス変数やプロパティ)を適切に設定し、オブジェクトを返します。
初期化の目的は、使用可能なオブジェクトを返す事です。

フレームワークでは、オブジェクトを初期化するイニシャライザと呼ばれるメソッドを多く見かけるでしょうが、それらは全て類似性を持っています。
イニシャライザはinitで始まるインスタンスメソッドで、id型のオブジェクトを返します。
ルートクラスNSObjectでは、他の全てのクラスが継承しているinitメソッドを宣言しています。
他のクラスは、それぞれ独自のキーワードや引数型を持つ独自のイニシャライザを宣言しています。
例えばNSURLクラスでは次のようなイニシャライザを宣言しています。

- (id)initFileURLWithPath:(NSString *)path isDirectory:(BOOL)isDir

オブジェクトの割り当てと初期化を行うには、初期化呼び出しの内側に割り当てをネストします。
例として上記のイニシャライザを使用した場合、下記のようになります。

NSURL *aURL = [[NSURL alloc] initFileURLWithPath:NSTemporaryDirectory() isDirectory:YES];

安全なプログラミングの慣習として、生成されたオブジェクトを照合するため、返されたオブジェクトをテストすることができます。
オブジェクトの生成を妨げるような何かが、どちらかの段階で発生した場合、イニシャライザはnilを返します。
ただし、Objective-Cは否定的な結果を除いて(例えば、例外を投じること無く)nilにメッセージを送信することがあり、メソッドが呼び出されなかったために貴方のコードが想定している処理を行わない場合があります。
allocメソッドによって返されたものの代わりに、イニシャライザによって返されたインスタンスを使用する必要があります。


クラスファクトリメソッドの呼び出しによるオブジェクトの生成

クラスファクトリメソッド(割り当て、初期化、自身のインスタンス返すことを目的とするクラスメソッド)を呼び出すことによって、オブジェクトを生成することもできます。
クラスファクトリメソッドは、2つではなく1つの行程でオブジェクトを生成することを許可しているため便利です。
それらの形式は次の通りです。

    + (type)className... (where className excludes any prefix)

Objective-Cフレームワークのいくつかのクラスは、クラスのイニシャライザに対応したクラスファクトリメソッドを定義しています。
例えば、NSStringでは以下の2つのメソッドを宣言しています。

- (id)initWithFormat:(NSString *)format, ...;
+ (id)stringWithFormat:(NSString *)format, ...;

このNSStringのクラスファクトリの使用法の例を示します。

NSString *myString = [NSString stringWithFormat:@"Customer: %@", self.record.customerName];



●メモリリークを回避するためのオブジェクトグラフの管理

Objective-Cプログラム内のオブジェクトは、オブジェクトグラフ(各オブジェクトと他のオブジェクトとのリレーションシップ(または参照)によって形成された、オブジェクトのネットワーク)を構成します。
オブジェクトの参照には一対一、または(コレクションオブジェクトを介しての)多対一があります。
オブジェクトの寿命の要因であるため、オブジェクトグラフは重要です。
コンパイラはオブジェクトグラフ内の参照の強さを検査し、必要に応じて保持や解放のメッセージを追加します。

:Objective-Cランタイムの最新バージョンでは、自動参照カウント(Automatic Reference Counting:ARC)を実装しています。
ARCでは明示的なメモリの管理(つまりオブジェクトの保持や解放)が不要です。
デフォルトの場合、新規アプリケーションプロジェクトのARCは常に使用する必要があります。

貴方はグローバル変数やインスタンス変数、ローカル変数などの基本的なCやObjective-Cの構造体を介して、オブジェクト間の参照を形成します。
これらの構造体はそれぞれ暗黙のスコープを保持しており、例えばローカル変数によって参照されるオブジェクトのスコープは、宣言された機能ブロックです。
重要なのはオブジェクト間の参照には、強い参照と弱い参照があるということです。
強い参照は所有権を示し、参照しているオブジェクトは参照されているオブジェクトの所有権を所有しています。
弱い参照は参照しているオブジェクトは参照されているオブジェクトを所有していないことを意味します。
オブジェクトの寿命は、どのくらい多くの強い参照があるかによって決定されます。
オブジェクトは強い参照が存在する限り解放されません。

Objective-Cでの参照は、デフォルトでは強い参照になります。
通常は、オブジェクトを使用している間は解放されないようにするために、コンパイラが実行時のオブジェクトの寿命を管理できるため、良いことです。
ただし注意しないと下図の左側に示すように、オブジェクト間の強い参照で途切れないチェーンが形成される場合があります。
このような途切れないチェーンが形成されると、それぞれに強い参照が存在するため、実行時にオブジェクトの解放が行われない可能性があります。
その結果、強い参照のサイクルでプログラムがメモリリークを発生させる可能性があります。

strong-ref-cycle-weak-ref_2x.png

図のオブジェクトにおいて、AとB間の参照を切断した場合、B、C、D、Eで形成されている部分は強い参照のサイクルによって互いに結合されているため、『永遠に』存在することになります。
EからBへ弱い参照を導入すると、この強い参照のサイクルを切断することができます。

強い参照のサイクルを弱い参照を使用して修正することは、賢明です。
ランタイムは、オブジェクトの弱い参照と強い参照の両方を追跡します。
オブジェクトへの強い参照が存在しなくなった後、オブジェクトは解放され、全てのオブジェクトへの弱い参照はnilに設定されます。
(グローバル、インスタンス、そしてローカル)変数では、弱い参照を表すために変数名の前に__weak修飾語を使用します。
プロパティの場合は、weakオプションを使用します。
以下の種類の参照では、弱い参照を使用する必要があります。

  • デリゲート
    @property(weak) id delegate;
    貴方はデザインパターンの記事『Streamline Your App with Design Patterns』でデリゲートとターゲットについて学びます。

  • アウトレットはトップレベルのオブジェクトへの参照ではない
    @property(weak) IBOutlet NSString *theName;
    アウトレットは、アプリがストーリーボードまたはnibファイルを読み込む時に復元された、ストーリーボードまたはnibファイル内のアーカイブされたオブジェクト間の接続(または参照)です。
    ストーリーボードまたはnibファイル内のトップレベルのオブジェクト(通常はウィンドウ、ビュー、ビューコントローラ、あるいは他のコントローラ)のためのアウトレットは、(デフォルトでは指定されませんが)強い参照である必要があります。

  • ターゲット
    (void)setTarget:(id __weak)target

  • ブロック内のselfへの参照
    __block typeof(self) tmpSelf = self;
    [self methodThatTakesABlock:^ {
        [tmpSelf doSomething];
    }];
    ブロックは獲得する変数への強い参照を形成しています。
    ブロック内でselfを使用する場合、ブロックはselfに強い参照を形成しますが、(通常は)selfもブロックに強い参照を持ち、結果として強い参照のサイクルとなります。
    サイクルを回避するためには上記の例のように、ブロックの外側でselfに弱い参照(または__block)を生成する必要があります。



●可変性オブジェクトの管理

可変オブジェクトは、オブジェクトを生成した後にその状態を変更することができます。
通常はプロパティやアクセサメソッドによって変更を行います。
不変オブジェクトは、オブジェクトを生成した後にカプセル化された状態を変更することができません。
Objective-Cフレームワークのほとんどのクラスで生成するインスタンスは可変であり、不変は少数です。
不変オブジェクトは以下のような利点を提供します。
  • 不変オブジェクトは使用中に突然値が変更されることはありません。

  • オブジェクトの多くの型は、オブジェクトが不変の場合、アプリケーションのパフォーマンスを向上させます。
Objective-Cフレームワークでは、不変クラスのインスタンスは通常、配列や文字列などの離散またはバッファされた値のコレクションをカプセル化したものです。
これらのクラスには通常、名前に『Mutable』の付いた可変のクラスがあります。
例えば、(不変の)NSStringクラスとNSMutableStringクラスがあります。
カプセル化した離散値の不変オブジェクトであるNSNumberNSDateなどのいくつかのクラスは、可変クラスを持たないことに注意してください。

オブジェクトの内容を頻繁に増加する変更が予想される場合は、不変クラスの代わりに可変クラスを使用してください。
不変オブジェクトとして型付けされたフレームワークのオブジェクトを受信した場合、戻り値の型は尊重し、オブジェクトに変更を加えようとはしないでください。



●値オブジェクトの生成と使用

値オブジェクトは、(Cのデータ型の)プリミティブ値をカプセル化したオブジェクトで、値に関連したサービスを提供します。
値オブジェクトはオブジェクトの形式の内、スカラー型を表します。
Foundationフレームワークは、文字列、バイナリデータ、日付と時刻、数値などの値オブジェクトを生成する以下のクラスを提供します。

    NSStringNSMutableString
    NSDataNSMutableData
    NSDate
    NSNumber
    NSValue

値オブジェクトはObjective-Cプログラミングにおいて重要です。
貴方はアプリケーションが呼び出すメソッドや関数の引数や戻り値として、これらのオブジェクトに頻繁に遭遇するでしょう。
値オブジェクトを渡すことによって、フレームワークの異なる部分や異なるフレームワークでも、データを交換することができます。
値オブジェクトはスカラー値を表しているので、オブジェクトを必要とするコレクション内でもどこでも使用することができます。
しかしプリミティブ値の持つ共通性やそれに伴う必要性以上に、カプセル化するプリミティブ型よりも優れた利点を持ちます。
値オブジェクトは、単純かつ効率的な方法でカプセル化された値を一定の操作で実行することができます。
例えばNSStringクラスには、部分文字列の検索と置換や、ファイルや(より望ましい)URLへの文字列の書き込み、あるいはファイルシステムパスを構築するメソッドがあります。

時には、より効率的で分かり易い(intやfloatなどで型付けされた値の)プリミティブ型を使用しているのを見かけるでしょう。
そのような状況の主な例は、値の計算です。
したがってNSNumberNSValueオブジェクトは、フレームワークメソッドの引数や戻り値として、あまり一般的には使用されません。
しかしNSIntegerCGFloatなど、多くのフレームワークは独自の数値データ型を宣言し、引数や戻り値としてこれらの型を使用しています。
基盤となるプラットフォームから離れた抽象的なコードから貴方を助けるため、これらのフレームワークで定義されている適切な型を使用する必要があります。


値オブジェクトの基本的な使用法

値オブジェクトを生成する基本的なパターンは、プリミティブ型のデータから貴方のコードまたはフレームワークのコードに対して(おそらくメソッドの引数として渡すために)生成する場合です。
貴方のコードでは、後にオブジェクトからカプセル化したデータへアクセスします。
NSNumberクラスは、このアプローチの最も明確な例を提供します。

int n = 5;    // Value assigned to primitive type
NSNumber *numberObject = [NSNumber numberWithInt:n];    // Value object created from primitive type
int y = [numberObject intValue];    // Encapsulated value obtained from value object (y == n)

ほとんどの『値』クラスは、そのインスタンスを生成するためのイニシャライザとクラスファクトリメソッドの両方を宣言しています。
また一部のクラス(特にNSStringNSData)はメモリ内のデータからだけではなく、ローカルまたはリモートファイルに格納されたプリミティブデータから、そのインスタンスを生成するためのイニシャライザとクラスファクトリメソッドを提供します。
また、これらのクラスはファイルまたはURLで指定された場所に、文字列やバイナリデータを書き込む補完的なメソッドも提供します。
以下の例のコードでは、URLオブジェクトによって指定された場所にあるファイルの内容から、NSDataオブジェクトを生成するinitWithContentsOfURL:メソッドを呼び出し、データを使用した後、ファイルシステムにデータオブジェクトを書き戻します。

NSURL *theURL = // Code that creates a file URL from a string path...
NSData *theData = [[NSData alloc] initWithContentsOfURL:theURL];
// use theData...
[theData writeToURL:theURL atomically:YES];

ほとんどの値クラスは値オブジェクトの生成だけでなく、カプセル化された値へのアクセスや、オブジェクトの比較などの単純な操作のためのメソッドを提供します。

プロパティとして値クラスのインスタンスを宣言する際には、copyオプションを使用する必要があります。


文字列とNSStringリテラル

CのスーパーセットであるObjective-Cは、Cと同様に文字列を指定するための同じ規則をサポートしています。
(単一文字は単一引用符で、文字の文字列は二重引用符で囲みます。)
ただし、通常のObjective-CフレームワークではC文字列を使用しないでください。
代わりにNSStringオブジェクトを使用します。

初めてのiOSアプリケーション』でHelloWorldアプリを生成した際に、貴方はフォーマットされた文字列を生成しました。

NSString *greeting = [[NSString alloc] initWithFormat:@"Hello, %@!", nameString];

NSStringクラスは文字列のためのオブジェクトラッパーを提供し、それによって異なる文字エンコーディング(特にUnicode)や、printfスタイルのフォーマットユーティリティのサポート、任意長の文字列を格納するための組み込みのメモリ管理などの便宜を提供します。
文字列は一般的に使用されるため、Objective-Cは定数値からNSStringオブジェクトを生成するための簡単な表記法を提供しています。
このNSStringリテラルを使用するには、以下の例に示すように、通常は二重引用符で囲んだ文字列の前にアットマーク(@)を付けます。

// Create the string "My String" plus carriage return.
NSString *myString = @"My String\n";
// Create the formatted string "1 String".
NSString *anotherString = [NSString stringWithFormat:@"%d %@", 1, @"String"];
// Create an Objective-C string from a C string.
NSString *fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding];


NSNumberリテラル

Objective-Cはまた、NSNumberオブジェクトを生成するための簡単な表記法も提供しており、そのようなオブジェクトを生成するためにイニシャライザやクラスファクトリメソッドを呼び出す必要がありません。
単純に数値の前にアットマーク(@)を置くだけで、必要に応じて値の型を示すインジケータを付加します。
例えば、整数値と倍精度値をカプセル化したNSNumberオブジェクトの生成は、以下のように記述します。

NSNumber *myIntValue = @32;
NSNumber *myDoubleValue = @3.22346432;

同様に、NSNumberリテラルを使用してブール値や文字値をカプセル化して生成することもできます。

NSNumber *myBoolValue = @YES;
NSNumber *myCharValue = @'V';

値の表記に文字『U』『L』『LL』『F』を付加することによって、それぞれ符号無し整数、long整数、long long整数、浮動小数点値を表すNSNumberオブジェクトを生成することができます。
例えば、浮動小数点値をカプセル化したNSNumberオブジェクトの生成は、以下のように記述します。

NSNumber *myFloatValue = @3.2F


日付と時刻

NSDateオブジェクトはプリミティブ値として時間特有の性質を持つため、他の種類の値オブジェクトとは異なります。
日付オブジェクトは、基準日からの感覚を秒単位でカプセル化します。
その基準日は、GMTの2001年1月1日の最初の瞬間です。

NSDateのインスタンス自体で行えることは僅かです。
それは時間の内で現在の瞬間を表しますが、暦やタイムゾーン、ロケールの時間規則によって提供されるコンテキスト無しで表されています。
幸いにも、これらの概念の物を表すFoundationクラスがあります。

  • NSCalendarNSDateComponents
    暦で日付を関連付けた後、暦から日付の年、月、時、日、週などの時間の単位を導出することができます。
    また暦の計算を実行することもできます。

  • NSTimeZone
    日付や時刻に地域のタイムゾーンを反映する必要がある場合は、暦にタイムゾーンオブジェクトを関連付けることができます。

  • NSLocale
    ロケールオブジェクトは、時間に関連する文化的・言語的規則をカプセル化します。

以下のコードでは、必要とする情報(この場合、現在の時間の時、分、秒を出力)を取得するために、NSDateオブジェクトと他のオブジェクトをどのように使用することができるかを例示しています。

NSDate *now = [NSDate date];    // 1
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];    // 2
[calendar setTimeZone:[NSTimeZone systemTimeZone]];    // 3
NSDateComponents *dc = [calendar components:(NSHourCalendarUnit|NSMinuteCalendarUnit|
     NSSecondCalendarUnit) fromDate:now];    // 4
NSLog(@"The time is %d:%d:%d", [dc hour], [dc minute], [dc second]);    // 5

コードの各番号の行を解説します。
  1. 現在の瞬間を表す日付オブジェクトを生成します。
  2. グレゴリオ暦を表すオブジェクトを生成します。
  3. システム環境設定で指定されたタイムゾーンを表すオブジェクトで、暦オブジェクトを設定します。
  4. 手順1で生成された日付オブジェクトを渡し、暦オブジェクトのcomponents:fromDate:メソッドを呼び出します。
    この呼び出しは日付オブジェクトの時、分、秒要素を含むオブジェクトを返します。
  5. コンソールへ現在の時、分、秒を出力します。
この例では結果をログに出力していますが、アプリのユーザインターフェイスで日付情報を表示するためには、日付フォーマッタ(NSDateFormatterクラスのインスタンス)を使用したアプローチが推奨されます。
暦計算では常に適切なクラスとメソッドを使用する必要があり、分、時、日などの要素を数値でハードコードしてはいけません。



●コレクションの生成と使用

コレクションは特定の方法で他のオブジェクトを格納し、クライアントがそれらのオブジェクトへアクセスできるようにするオブジェクトです。
貴方はしばしばメソッドや関数の引数としてコレクションを渡したり、メソッドや関数の戻り値としてコレクションを取得したりします。
多くの場合コレクションは値オブジェクトを格納しますが、全てのオブジェクトの型を格納できるわけではありません。
ほとんどのコレクションは、含まれているオブジェクトへの強い参照を持っています。

Foundationフレームワークにはいくつかのコレクションの型がありますが、Cocoa TouchとCocoaプログラミングにおいては、配列、辞書、そしてセットの3つが特に重要です。
これらのコレクションのクラスには不変と可変の2種類があります。
可変コレクションではオブジェクトの追加と削除が可能ですが、不変コレクションは生成時のオブジェクトしか含めることはできません。
全てのコレクションはコンテンツを列挙することができ、言い換えれば格納されているオブジェクトは順番に検査されるということになります。

コレクションには様々な型があり、特有の方法でオブジェクトを格納します。

  • NSArrayNSMutableArray
    配列は順序付けされたオブジェクトのコレクションです。
    オブジェクトには配列内の位置(つまりインデックス)を指定することによってアクセスします。
    配列の最初の要素のインデックスは0(ゼロ)です。

  • NSDictionaryNSMutableDictionary
    辞書はキーと値をペアとしてエントリを格納します。
    キーは一意の識別子で通常は文字列であり、値は格納したいオブジェクトです。
    キーを指定することによってオブジェクトにアクセスします。

  • NSSetNSMutableSet
    セットは各オブジェクトが一度だけ出現する、順不同のオブジェクトのコレクションです。
    一般的にはテストまたはフィルタを適用することによって、セット内のオブジェクトにアクセスします。

collections_2x.png

このように格納、アクセス、実行の特性により、あるコレクションのタイプは他のタイプよりも特定のタスクに適したものにすることができます。

配列や辞書の生成と含まれている値へのアクセスは、NSArrayNSDictionaryのメソッドを呼び出すことによって、または特別なObjective-Cのコンテナリテラルやサブスクリプティング技術を使用することによってすることができます。
以下の項目では両方のアプローチに付いて説明します。


配列内に特定の順序でオブジェクトを格納

配列は順序付けられたシーケンス内にオブジェクトを格納します。
したがって、コレクション内のオブジェクトの順序が重要な場合に配列を使用します。
例えば多くのアプリケーションでは、テーブルビューの行やメニューの項目へコンテンツを提供するために、配列が使用されます。
インデックス0のオブジェクトが最初の行に対応し、インデックス1のオブジェクトが2行目に対応するという形になります。
配列内のオブジェクトへのアクセス時間は、セット内のオブジェクトよりも遅くなります。


配列の生成

NSArrayクラスには配列を生成・初期化するための多くのイニシャライザやクラスファクトリメソッドがありますが、いくつかのメソッドは特に一般的で実用的です。
arrayWithObjects:count:arrayWithObjects:メソッド(と対応するイニシャライザ)で、一連のオブジェクトから配列を生成することができます。
前者のメソッドでは第二引数に第一引数のオブジェクトの数を指定しますが、後者のメソッドではnilで終端されたコンマ区切りの一連のオブジェクトを指定します。

// Compose a static array of string objects
NSString *objs[3] = {@"One", @"Two", @"Three"};
// Create an array object with the static array
NSArray *arrayOne = [NSArray arrayWithObjects:&(*objs) count:3];
// Create an array with a nil-terminated list of objects
NSArray *arrayTwo = [[NSArray alloc] initWithObjects:@"One", @"Two", @"Three", nil];

可変配列を生成する場合は、配列の生成にarrayWithCapacity:(またはinitWithCapacity:)メソッドを使用することができます。
capacity引数は予想される配列のサイズについてクラスにヒントを与えるもので、実行時により効率的に配列を作成することができます。
配列は指定した容量を超えることができます。

またコンテナリテラル@[...]を使用し、角括弧内にコンマ区切りでオブジェクトを指定して、配列を生成することもできます。
例えば、文字列、数値、そして日付を格納した配列の生成は、下記のように記述することができます。

NSArray *myArray = @[ @"Hello World", @67, [NSDate date] ];


配列内のオブジェクトへのアクセス

一般的に、配列内における(ゼロベースの)インデックス位置を指定することによって、配列内オブジェクトにアクセスするにはobjectAtIndex:メソッドを呼び出します。

NSString *theString = [arrayTwo objectAtIndex:1];    // returns second object in array

NSArrayは、配列内のオブジェクトまたは配列のインデックスにアクセスする他のメソッドも提供します。
例えば、lastObjectfirstObjectCommonWithArray、そしてindexOfObjectPassingTest:などがあります。

配列内のオブジェクトへのアクセスにNSArrayのメソッドを使用する代わりに、添字表記を使用することもできます。
例えば、(上記で生成した)myArray内の2番目のオブジェクトへアクセスするには、以下のような記述をすることもできます。

id theObject = myArray[1];

配列におけるもう一つの一般的なタスクは、配列内の各オブジェクトで何かを行う、列挙として知られている処理です。
多くの場合、1つまたは複数のオブジェクトが特定の値または条件に一致するかどうかを判別するために配列を列挙し、合致した場合にアクションを完了します。
配列を列挙するには、高速列挙、ブロックベースの列挙、またはNSEnumeratorオブジェクトを使用するという3つのアプローチを採ることができます。
高速列挙はその名の通り、通常は配列内のオブジェクトへアクセスする他の技術を使用するよりも高速です。
高速列挙は特定の構文を必要とする言語の機能です。

for (type variable in array){ /* inspect variable, do something with it */ }

例えば、

NSArray *myArray =    // get array
for (NSString *cityName in myArray) {
    if ([cityName isEqualToString:@"Cupertino"]) {
        NSLog(@"We're near the mothership!");
        break;
    }
}

いくつかのNSArrayメソッドはブロックで配列を列挙でき、enumerateObjectsUsingBlock:は最も単純なメソッドです。
ブロックには現在のオブジェクト、そのインデックス、そして(YESに設定された場合に列挙を終了するための)参照されるブール値の3つの引数があります。
ブロック内のコードは、高速列挙文の中括弧間のコードとして、同じ処理を正確に実行します。

NSArray *myArray =    // get array
[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if ([obj isEqual:@"Cupertino"]) {
        NSLog(@"We're near the mothership!");
        *stop = YES;
    }
}];


可変配列の管理

NSArrayは配列のソート、配列の検索、そして配列内の各オブジェクトのメソッドを呼び出す、他のメソッドを持っています。

addObject:メソッドを呼び出すことによって、可変配列にオブジェクトを追加することができます。
オブジェクトは配列の最後に置かれます。
また可変配列内の特定の場所にオブジェクトを配置するには、insertObject:atIndex:を使用することができます。
removeObject:メソッドまたはremoveObjectAtIndex:メソッドを呼び出すことによって、可変配列からオブジェクトを削除することができます。

また可変配列内の特定の場所にオブジェクトを挿入するために、添字記法を使用することもできます。

NSMutableArray *myMutableArray = [NSMutableArray arrayWithCapacity:1];
NSDate *today = [NSDate date];
myMutableArray[0] = today;


辞書内にキーと値のペアを格納

キーと値をペアとして(つまり識別子(キー)とオブジェクト(値)を組み合わせて)オブジェクトを格納するために辞書を使用することができます。
キーと値のペアは任意の順序で指定できるため、辞書は順不同のコレクションです。
キーには実質的になんでも指定できますが、一般的には(文字列定数である)NSFileModificationDateUIApplicationStatusBarFrameUserInfoKeyなど、値を説明する文字列が使用されます。
公開キーが存在する場合、辞書はオブジェクト間のあらゆる種類の情報を渡すための素晴らしい方法です。


辞書の生成

NSDictionaryクラスはイニシャライザやクラスファクトリメソッドを介して辞書を生成する多くの方法を提供していますが、特に一般的なのはdictionaryWithObjects:forKeys:dictionaryWithObjectsAndKeys:(またはそれに対応するイニシャライザ)の2つのクラスメソッドです。
前者のメソッドは、オブジェクトの配列とキーの配列を渡します。
(キーと値の位置関係は一致する必要があります。)
後者のメソッドは、最初のオブジェクトの値とそのキー、次に二番目のオブジェクトの値とそのキー・・・と指定します。
このオブジェクトの一連の終端はnilで通知します。

// First create an array of keys and a complementary array of values
NSArray *keyArray = [NSArray arrayWithObjects:@"IssueDate", @"IssueName", @"IssueIcon", nil];
NSArray *valueArray = [NSArray arrayWithObjects:[NSDate date], @"Numerology Today",
    self.currentIssueIcon, nil];
// Create a dictionary, passing in the key array and value array
NSDictionary *dictionaryOne = [NSDictionary dictionaryWithObjects:valueArray forKeys:keyArray];
// Create a dictionary by alternating value and key and terminating with nil
NSDictionary *dictionaryTwo = [[NSDictionary alloc] initWithObjectsAndKeys:[NSDate date],
    @"IssueDate", @"Numerology Today", @"IssueName", self.currentIssueIcon, @"IssueIcon", nil];

配列の場合と同様に、コンテナリテラル@{key : value, ...}(『...』は任意の数のキーと値の組)を使用することによって、NSDictionaryオブジェクトを生成することができます。
例として、3つのキーと値の組で可変辞書オブジェクトを生成するコードを下記に示します。

NSDictionary *myDictionary = @{
    @"name" : NSUserName(),
    @"date" : [NSDate date],
    @"processInfo" : [NSProcessInfo processInfo]
};


辞書内のオブジェクトへのアクセス

objectForKey:メソッドで引数としてキーを指定することによって、辞書内のオブジェクトの値にアクセスすることができます。

NSDate *date = [dictionaryTwo objectForKey:@"IssueDate"];

また添字を使用して辞書内のオブジェクトにアクセスすることもできます。
キーは辞書変数の右後ろの角括弧間に記述します。

NSString *theName = myDictionary[@"name"];


可変辞書の管理

setObject:forKey:removeObjectForKey:メソッドを呼び出すことによって、可変辞書に項目の挿入や削除を行うことができます。
setObject:forKey:メソッドは、指定されたキーの既存の値を置換します。
これらのメソッドは高速です。

また添字を使用して、可変辞書にキーと値の組を追加することもできます。
キーは代入の左辺に添字で、値は右辺に指定します。

NSMutableDictionary *mutableDict = [[NSMutableDictionary alloc] init];
mutableDict[@"name"] = @"John Doe";


セット内へ順不同でオブジェクトを格納

セットは、格納されている項目が順序付けられている代わりに順不同になっていることを除けば、配列に類似したコレクションのオブジェクトです。
セット内のオブジェクトへのアクセスは、インデックスで場所を指定したりキーを介して行うのではなく、コレクションを列挙したり、またはセットにフィルタやテストを適用することによって、(anyObjectメソッドを使用して)ランダムにアクセスします。

セットオブジェクトは、辞書や配列などと比べてObjective-Cプログラミングでは一般的ではありませんが、特定の技術において重要なコレクション型です。
(データ管理技術である)Core Dataでは、対多関係のプロパティを宣言する場合、NSSetまたはNSOrderedSetのプロパティ型である必要があります。
またセットは、UIKitフレームワークのネイティブのタッチイベント処理でも重要です。
例えば、

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    UITouch *theTouch = [touches anyObject];
    // handle the touch...
}

順序付きセットは、セットの基本的な定義の例外です。
順序付きセットでは、セット内の項目の順序が重要になります。
順序付きセットのメンバーシップのテストは、配列よりも高速です。



●実行時のオブジェクト機能の照合

Objective-CとNSObjectクラスの強力かつ便利な機能は、実行時にオブジェクトに関する特定の事柄について学ぶことができます。
これにより、認識していないオブジェクトへのメッセージの送信や、継承していない特定のクラスを継承しようとした場合など、貴方のコードの間違いを回避することができます。

実行時にオブジェクト自身について開示できる情報には、3つの重要なタイプがあります。
  • 特定のクラスまたはサブクラスのインスタンスかどうか
  • メッセージに応答するかどうか
  • プロトコルに準拠しているかどうか

オブジェクトが特定のクラスまたはそのサブクラスのインスタンスかどうかを知る

オブジェクトがクラスまたはそのサブクラスのインスタンスかどうかを知るには、そのオブジェクトでisKindOfClass:メソッドを呼び出します。
アプリが(実装または継承していて)応答できるメッセージを知りたい場合に、アプリは時々このチェックを行います。

static int sum = 0;
for (id item in myArray) {
    if ([item isKindOfClass:[NSNumber class]]) {
        int i = (int)[item intValue];
        sum += i;
    }
}

isKindOfClass:メソッドは、引数としてClass型のオブジェクトを取ります。
このオブジェクトを取得するには、クラスのシンボルにclassメソッドを呼び出します。
このメソッドによって返されるブール値を評価し、それに応じて進みます。

NSObjectはオブジェクトの継承に関する情報を発見するために、他のメソッドも宣言しています。
例えば、isKindOfClass:がオブジェクトのクラスまたはその派生クラスのいずれかであるかを伝えるのに対し、isMemberOfClass:メソッドはオブジェクトが指定したクラスのインスタンスであるかを伝えます。


オブジェクトがメッセージに応答するかどうかを知る

オブジェクトがメッセージに応答するかどうかを知るには、そのオブジェクトでrespondsToSelector:メソッドを呼び出します。
アプリのコードは、しばしばオブジェクトにメッセージを送信する前に、オブジェクトがメッセージに応答するかどうかを照合します。

if ([item respondsToSelector:@selector(setState:)]) {
    [item setState:[self.arcView.font isBold] ? NSOnState : NSOffState];
}

respondsToSelector:メソッドは、引数としてセレクタを取ります。
セレクタは、メソッド実行時の識別子のためのObjective-Cのデータ型で、@selectorコンパイラディレクティブを使用してセレクタを指定します。
コードでは、このメソッドによって返されるブール値を評価し、それに応じて進みます。

オブジェクトがメッセージに応答するかを識別する際、一般的にクラス型を評価するよりもrespondsToSelector:を呼び出した方が便利です。
例えばクラスの最新バージョンでは、以前のバージョンでは発見されなかったメソッドが実装されている場合があります。


オブジェクトがプロトコルに準拠しているかどうかを知る

オブジェクトがプロトコルに応答するかどうかを知るには、そのオブジェクトでconformToProtocol:メソッドを呼び出します。

- (void) setDelegate:(id __weak) obj {
    NSParameterAssert([obj conformsToProtocol:
        @protocol(SubviewTableViewControllerDataSourceProtocol)]);
    delegate = obj;
}

conformToProtocol:メソッドは、引数として実行時のプロトコルの識別子を取ります。
この識別子には、@protocolコンパイラディレクティブを使用して指定します。
このメソッドによって返されるブール値を評価し、それに応じて進みます。
オブジェクトは、オプションのメソッドを実装していなくてもプロトコルに準拠することができることに注意してください。



●オブジェクトの比較

isEqual:メソッドを使用することによって、2つのオブジェクトを比較することができます。
メッセージを受信するオブジェクトは渡されたオブジェクトと比較され、それらが同じ場合、メソッドはYESを返します。
例えば、

BOOL objectsAreEqual = [obj1 isEqual:obj2];
if (objectsAreEqual) {
    // do something...
}

オブジェクトの等価性は、オブジェクトの同一性と異なることに注意してください。
後者の場合、2つの変数が同じインスタンスを示すかどうかを、等価演算子 == を使用してテストします。

同じクラスの2つのオブジェクト比較する場合、どうなるでしょうか?
それはクラスに依存します。
ルートクラスであるNSObjectの場合、比較の基準としてポインタの等価性を使用しています。
どのレベルのサブクラスでも、オブジェクトの状態としてクラス固有の基準に基く比較を元に、そのスーパークラスの実装をオーバーライドすることができます。
例えば架空のPersonオブジェクトは、両方のオブジェクトの名、姓、誕生日の属性が一致している場合、別のPersonオブジェクトと等しい可能性があります。

Foundationフレームワークの値とコレクションクラスは、isEqualToString:isEqualToDictionary:など、isEqualToType:形式(Typeはクラス型からNS接頭辞の除いたもの)の比較メソッドを宣言しています。
比較メソッドは渡されたオブジェクトが指定した型であり、そうでない場合は例外が発生すると仮定しています。



●オブジェクトのコピー

copyメッセージを送信することによって、オブジェクトのコピーを作成することができます。

NSArray *myArray = [yourArray copy];

コピーするには、受信側のオブジェクトのクラスがNSCopyingプロトコルに準拠している必要があります。
オブジェクトをコピーできるようにしたい場合は、このプロトコルを採用し、copyメソッドを実装する必要があります。

時々、プログラム内の他の場所から取得したオブジェクトについて、使用している間はオブジェクトの状態が変更されないようにしたい場合は、オブジェクトをコピーします。

コピー動作はクラス固有のものであり、インスタンスの特定の性質に依存します。
ほとんどのクラスは深いコピーを実装しており、全てのインスタンス変数とプロパティの複製を作成しますが、(コレクションクラスなど)いくつかのクラスは浅いコピーを実装しており、インスタンス変数とプロパティの参照のみ複製します。

不変と可変の種類があるクラスでは、オブジェクトの可変コピーを生成するためのmutableCopyメソッドを宣言しています。
例えばNSStringオブジェクト上でmutableCopyを呼び出した場合、NSMutableStringのインスタンスを取得します。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Acquire Foundational Programming Skills

0 CommentsPosted in 資料

Start Developing iOS Apps Today(sup.2)〜Objective-Cコードの記述

2012. 12. 01
貴方がiOSまたはMac OS Xのどちらかでプログラムをしていなかった場合、主要なプログラミング言語であるObjective-Cに精通する必要があります。
Objective-Cは難しい言語ではなく、一度しばらく使用してみると、その優雅さを理解できるでしょう。
Objective-C言語は、洗練されたオブジェクト指向プログラミングを可能にします。
Objective-C言語は、標準ANSI Cプログラミング言語に、クラスやメソッドを定義する構文を規定したものです。
またクラスや任意のクラスが採用できるインターフェイスの動的拡張を推奨しています。

ANSI Cに精通している場合、以下の情報はObjective-Cの基本的な構文を学ぶのに役立ちます。
また他のオブジェクト指向言語でプログラミングしていた場合、カプセル化や継承、多態性といった因習的なオブジェクト指向の概念の全てが、Objective-Cで表現されているのを多く見つけることができるでしょう。
ANSI Cに精通していない場合、この記事を読もうとする前に、少なくともC言語の概要を読んでおくことをお勧めします。

Objective-Cプログラミング言語』では、Objective-C言語の完全な説明がされています。



●Objective-CはC言語のスーパーセット

Objective-C言語は、オブジェクトのメソッドの呼び出しや、クラスの動的拡張、特定の問題に対処するように適応されたプログラミングインターフェイスの生成をするための、クラスやメソッドを定義する構文を指定します。
Objective-CはCプログラミング言語のスーパーセットで、Cと同じ基本的な構文をサポートします。
(int、floatなどの)原始的な型、構造体、関数、ポインタ、if...elseやfor文などの制御フロー構成といった、一般的な要素の全てを持っています。
また、stdlib.hやstdio.hなどで宣言されている標準Cライブラリのルーチンへのアクセスも持っています。

Objective-CはANSI Cの機能に以下の構文が追加されます。
  • 新しいクラスの定義
  • クラスメソッドとインスタンスメソッド
  • メソッドの呼び出し(メッセージングと呼ばれます)
  • プロパティ(とそれらからのアクセサメソッドの自動合成)の宣言
  • 静的および動的型付け
  • ブロック(常時実行可能な、コードのカプセル化セグメント)
  • プロトコルやカテゴリなどの、基本的な言語の拡張
現在、このようなObjective-Cの側面を知らなくても心配しないでください。
この記事の残りの部分を読み進めることによって、これらについて学びます。
貴方がオブジェクト指向の概念に不慣れな手続き型プログラマの場合、最初は基本的にオブジェクトに関連付けられた機能を持つ構造として考えるとよいでしょう。
ただし、この見解は特にランタイム実装において実際とは乖離しています。

さらに他のオブジェクト指向言語に見られるほとんどの抽象概念やメカニズムを提供するObjective-Cは、非常に動的な言語で、そのダイナミズムが最大の利点です。
アプリの動作はアプリのビルド時に固定されるのではなく、実行時に(つまりランタイムで)動的に決定することができます。
したがってObjective-Cのダイナミズムはコンパイルやリンク時に課せられる制約からプログラムを解放し、代わりにユーザの制御時にランタイムでシンボルの解決をする責任を負います。



●クラスとオブジェクト

ほとんどのオブジェクト指向言語と同様に、Objective-Cのクラスはデータのカプセル化をサポートし、そのデータを操作するアクションを定義します。
オブジェクトはクラスの実行時のインスタンスです。
それにはクラスによって宣言されたインスタンス変数のコピーと、クラスのメソッドへのポインタが自身のメモリ内に含まれています。
オブジェクトは割り当て(allocation)と初期化(initialization)という2つの工程を呼び出して生成します。

Objective-Cでのクラスの指定には、インターフェイスと実装といった2つの部分を必要とします。
インターフェイス部分は、クラス宣言とクラスの公開インターフェイスの定義が含まれています。
Cコードと同様に、貴方のコードではソースファイルでの実装の詳細から公開宣言を分離するために、ヘッダファイルで定義します。
(プログラムインターフェイスの一部の場合、実装ファイル内で他の宣言を記述することができますが、プライベートであることを意味します。)
これらのファイルは下表に示すファイル名の拡張子を持っています。

拡張子ソースタイプ
.hヘッダファイル。
ヘッダファイルには、クラス、型、関数、および定数の宣言が含まれています。
.m実装ファイル。
この拡張子のファイルは、Objective-CとCコードの両方を含めることができます。
時々ソースファイルと呼ばれます。
.mm実装ファイル。
この拡張子のファイルは、Objective-CとCコードに加え、C++コードを含めることができます。
実際にはObjective-CコードからC++のクラスまたは機能を明示する場合のみ、この拡張子を
使用します。

ソースコードにヘッダファイルをインクルードしたい場合は、ヘッダファイルまたはソースファイルの最初の行の1つとして、インポートのディレクティブ(#import)を指定します。
#importディレクティブは同じファイルを複数回インクルードしないことを確認すること以外は、Cの#includeディレクティブと同様です。
フレームワークのヘッダファイルのほとんど、または全てをインポートしたい場合は、フレームワークと同じ名前を持つフレームワークのアンブレラヘッダファイルをインポートします。
(仮想の)Gizmoフレームワークのヘッダファイルをインポートする構文は以下の通りです。

#import <Gizmo/Gizmo.h>

基本(またはルート)クラスであるNSObjectから継承されるMyClassと呼ばれるクラスの宣言をする場合の構文を下図に示します。
(ルートクラスは、全てのクラスが直接または間接的に継承しているクラスです。)
クラスの宣言は@interfaceコンパイラディレクティブで始まり、@endディレクティブで終わります。
クラス名(と区切りのコロン)の後が、親クラスの名前です。
Objective-Cでは、クラスの親は1つだけ持つことができます。

class_decl_2x.png

プロパティとメソッドの宣言は、@interfaceと@endディレクティブの間に記述します。
これらの宣言は、クラスのパブリックインターフェイスを形成します。
(宣言済みプロパティは『宣言済みプロパティとアクセサメソッド』で説明しています。)
セミコロンは、各プロパティやメソッドの宣言の終端を示しています。
クラスがカスタム関数、定数、またはパブリックインターフェイスに関連付けられたデータ型を持っている場合は、@interface...@endブロックの外側で宣言します。

クラス実装の構文も類似しています。
@implementation(の後にクラス名が続く)コンパイラディレクティブで始まり、@endディレクティブで終わります。
その間にメソッドを実装します。
(関数の実装は、@implementation...@endブロックの外側で行う必要があります。)
実装では、常にコードの最初の行の1つとしてインターフェイスファイルをインポートする必要があります。

#import "MyClass.h"

@implementation MyClass

- (id)initWithString:(NSString *)aName
{
    // code goes here
}

+ (MyClass *)myClassWithString:(NSString *)aName
{
    // code goes here
}

@end

Objective-Cはオブジェクトを格納している変数の動的型付けをサポートしていますが、静的型付けもサポートしています。
静的に型付けられた変数には、変数の型宣言でのクラス名が含まれています。
動的に型付けられた変数は、代わりにオブジェクトの型idが使用されます。
特定の状況で使用される変数は、動的型付けされていることに気付くでしょう。
例えば(格納されたオブジェクトの正確な型が不明な)配列のようなコレクションオブジェクトは、動的型付けされた変数を使用する場合があります。
このような変数は途方もない柔軟性と、Objective-Cプログラムのより大きなダイナミズムを可能にします。

静的および動的な型の変数宣言の例を以下に示します。

MyClass *myObject1;    // Static typing
id             myObject2;    // Dynamic typing
NSString *userName;    // From Your First iOS App (static typing)

最初の宣言にあるアスタリスク『*』に注目してください。
Objective-Cでは、オブジェクトの参照は常にポインタである必要があります。
この要件は、貴方が完全な意味を把握していない場合は気にする必要はありません。
Objective-Cのプログラミングを開始するために、ポインタの専門家になる必要は無いからです。
静的に型付けされたオブジェクト宣言の変数名の前にはアスタリスクを付けることは忘れないでください。
id型はポインタを意味します。



●メソッドとメッセージング

貴方がオブジェクト指向プログラミングに不慣れな場合、メソッドは特定のオブジェクトにスコープが設定された関数と考えると良いでしょう。
オブジェクトへのメッセージの送信(またはメッセージング)は、オブジェクトのメソッドの呼び出しです。
Objective-Cにはインスタンスメソッドとクラスメソッドの2種類があります。
  • インスタンスメソッドは、クラスの特定のインスタンスにスコープが設定されて実行するメソッドです。
    すなわち、インスタンスメソッドを呼び出す前にクラスのインスタンスを最初に生成する必要があります。
    インスタンスメソッドはメソッドの最も一般的なタイプです。

  • クラスメソッドは、メソッドのクラスにスコープが設定されて実行するメソッドです。
    オブジェクトのインスタンスがメッセージのレシーバである必要はありません。
メソッドの宣言は、メソッドの型識別子、戻り値の型、1つ以上のシグネチャキーワード、および引数の型と名前という情報で構成されています。
insertObject:atIndex:インスタンスメソッドの宣言は下図のようになります。

method_decl_2x.png

インスタンスメソッドは宣言の前にマイナス記号『-』を付け、クラスメソッドの場合はプラス記号『+』になります。
クラスメソッドに関しては、後述する『クラスメソッド』でより詳細に説明します。

メソッドの実際の名前(insertObject:atIndex:)は、全てのシグネチャキーワードをコロン文字で連結したものです。
コロン文字は引数が存在することを宣言します。
上記の例では、メソッドは2つの引数を持ちます。
メソッドが引数を持たない場合、最初(にして唯一)のシグネチャキーワードの後のコロンを省略します。

メソッドを呼び出したい場合、メソッドを実装するオブジェクトにメッセージを送信することで行います。
(『メソッドの呼び出し』の別称として一般的に『メッセージを送信』という語句を使用していますが、Objective-Cランタイムでは実際に送信しています。)
メッセージは、メソッドが必要とする(型に正確に一致する)引数情報を伴うメソッド名です。
オブジェクトに送信される全てのメッセージは動的にディスパッチされるため、Objective-Cクラスの多態性な動作を容易にします。
(ポリモーフィズム(多態性)とは、異なる型のオブジェクトに対して同じメッセージで応答できる能力を意味します。)
呼び出されるメソッドがメッセージを受信したオブジェクトのクラスのスーパークラスによって実装されている場合もあります。

メッセージをディスパッチするには、ランタイムでのメッセージ式が必要です。
メッセージ式は、メッセージ自体を(必要な引数と共に)角括弧([と])で括り、括弧内の左端にはメッセージを受信するオブジェクトを指定します。
例えば、insertObject:atIndex:メッセージをmyArray変数が保持するオブジェクトに送信する場合は、以下の構文を使用します。

[myArray insertObject:anObject atIndex:0];

一時的な結果を格納するために多数のローカル変数を宣言することを避けるために、Objective-Cはメッセージ式のネストを許可しています。
ネストされた各式からの戻り値は他のメッセージの引数、または受信するオブジェクトとして使用されます。
例えば、値を取得するメッセージと、前述の例で使用している変数のいずれかを置き換えることができます。
したがって、myAppObjectと呼ばれる別のオブジェクトがあり、配列オブジェクトにアクセスして配列内にオブジェクトを挿入するためのメソッドを持っている場合、前述の例は下記のように記述することができます。

[[myAppObject theArray] insertObject:[myAppObject objectToInsert] atIndex:0];

Objective-Cはまた、アクセサメソッドを呼び出すためのドット記法の構文を提供します。
アクセサメソッドはオブジェクトの状態を設定または取得し、全てのオブジェクトの重要な特質であるカプセル化の鍵となります。
オブジェクトを隠蔽またはカプセル化し、その状態とその状態にアクセスするための全てのインスタンスに共通するインターフェイスを提示します。
ドット記法の構文を使用すると、前述の例は以下のように書き換えることができます。

[myAppObject.theArray insertObject:myAppObject.objectToInsert atIndex:0];

また、割り当てのためにドット記法の構文を使用することができます。

myAppObject.theArray = aNewArray;

この構文は単純に[myAppObject setTheArray:aNewArray];を別の方法で記述したものです。
ドット記法の式では、動的型付けされたオブジェクト(id型のオブジェクト)への参照に使用することはできません。

貴方は既に『初めてのiOSアプリケーション』において、変数の割り当てにドット構文を使用しています。

self.userName = self.textField.text;


クラスメソッド

前述の例ではクラスのインスタンスにメッセージを送信していましたが、クラス自身にメッセージを送信することもできます。
(クラスはランタイムによって生成されたClass型のオブジェクトです。)
クラスへメッセージングする場合、メソッドはインスタンスメソッドの代わりにクラスメソッドとして定義する必要があります。
クラスメソッドはC++の静的クラスメソッドに似た機能です。

クラスメソッドは多くの場合、クラスの新しいインスタンスを生成するファクトリメソッドとして、またはクラスに関連付けられている共有された情報のいくつかにアクセスするために使用されます。
クラスメソッドを宣言する構文は、メソッドの型識別子のマイナス記号の代わりにプラス記号(+)を使用することを除けば、インスタンスメソッドと同じです。

次の例では、クラスのファクトリメソッドとしてクラスメソッドをどのように使用するかを説明します。
この場合arrayメソッドは、クラスの新しいインスタンスを割り当てて初期化しコードにそれを返す、NSArray(と継承しているNSMutableArray)クラスのクラスメソッドです。

NSMutableArray *myArray = nil;    // nil is essentially the same as NULL

// Create a new array and assign it to the myArray variable.
myArray = [NSMutableArray array];



●宣言済みプロパティとアクセサメソッド

一般的な意味でのプロパティは、オブジェクトによってカプセル化または格納されたいくつかのデータです。
これは名前や色などの属性や、1つ以上の他のオブジェクトへの関係です。
オブジェクトのクラスは、そのオブジェクトのユーザがカプセル化されたプロパティの値を取得または設定するためのインターフェイスを定義します。
これらのアクションを実行するメソッドは、アクセサメソッドと呼ばれます。

アクセサメソッドには2つのタイプがあり、各メソッドは次の命名規則に準拠する必要があります。
『ゲッタ(getter)』アクセサメソッドはプロパティの値を返し、プロパティと同じ名前を持ちます。
『セッタ(setter)』アクセサメソッドはプロパティに新しい値を設定し、プロパティ名の最初の文字が大文字となる、setPropertyName:という形式を持ちます。
適切な名前のアクセサメソッドは、CocoaとCocoa Touchフレームワークのいくつかの技術の重要な要素で、キー値コーディング(KVC)を含め、それらの名前を介して間接的にオブジェクトのプロパティにアクセスするメカニズムです。

Objective-Cはアクセサメソッドの宣言と実装のため、表記上の便宜として宣言済みプロパティを提供します。
初めてのiOSアプリケーション』において貴方はuserNameプロパティを宣言しました。

@property (nonatomic, copy) NSString *userName;

宣言済みプロパティは、クラスで公開される各プロパティのゲッタとセッタメソッドを実装する必要がありません。
代わりに、プロパティ宣言で使用する動作を指定します。
コンパイラは宣言に基づいて、実際のゲッタまたはセッタを生成(または合成)します。
宣言済みプロパティは定型的なコードの記述を減らすことになり、その結果としてエラーの発生し難い、はるかに綺麗なコードを作ることができます。
オブジェクトの状態の項目を取得または設定するには、宣言済みプロパティまたはアクセサメソッドを使用します。

クラスのインターフェイス内には、メソッド宣言を伴うプロパティ宣言を含めます。
クラスのヘッダファイルにはパブリックプロパティを宣言し、ソースファイルのクラス拡張にはプライベートプロパティを宣言します。
(例を含めたクラス拡張の簡単な説明については『プロトコルとカテゴリ』を参照してください。)
デリゲートやビューコントローラなどのコントローラオブジェクトのプロパティは、通常プライベートにする必要があります。

プロパティの基本的な宣言では@propertyコンパイラディレクティブを使用し、型情報やプロパティ名が続きます。
また弱い参照であるか、読み込み専用であるか、アクセサメソッドがどのように動作するかを定義する、カスタムオプションでプロパティを構成することができます。
オプションは、@propertyディレクティブに続く括弧内に記述します。

以下にいくつかのプロパティ宣言のコード行を示します。

@property (copy) MyModelObject *theObject;    // Copy the object during assignment.
@property (readonly) NSView *rootView;           // Declare only a getter method.
@property (weak) id delegate;                            // Declare delegate as a weak reference

宣言済みプロパティはコンパイラが自動的に合成します。
プロパティの合成では、アクセサメソッドだけでなく、プロパティの『裏』でプライベートなインスタンス変数を生成します。
インスタンス変数はプロパティとして同じ名前を持ちますが、アンダースコア接頭辞(_)を持ちます。
貴方のアプリは、オブジェクトの初期化と解放のためのメソッドでのみ、(プロパティの代わりに)インスタンス変数に直接アクセスする必要があります。

インスタンス変数に別の名前を付けたい場合は、プロパティの自動合成を迂回して明示的に合成することができます。
クラスの実装で@synthesizeコンパイラディレクティブを使用し、特別な名前のインスタンス変数と一緒にアクセサメソッドを生成するようにコンパイラに依頼します。
例えば、

@synthesize enabled = _isEnabled;

ちなみにプロパティ宣言の際にアクセサメソッドにカスタム名を指定することができますが、以下のブール型プロパティのゲッタメソッドのように、通常は一般的な形式に準ずるように作成します。

@property (assign, getter=isEnabled) BOOL enabled;    // Assign new value, change name of getter method



●ブロック

ブロックは処理の単位(コードのひとまとまり)をカプセル化したオブジェクトで、いつでも実行することができます。
ブロックは基本的に可搬性を持ち、メソッドや関数の引数として渡すことができる、またはメソッドや関数から返すことができる匿名関数です。
ブロック自体は型付きの引数リストを持ち、推定または宣言された戻り値型を持つ場合もあります。
また、変数にブロックを割り当て、関数と同じように呼び出すこともできます。

カレット(^)はブロックの構文マーカーとして使用されます。
他にも、一般的な引数の構文規則、戻り値、ブロックの本体(つまり実行されるコード)があります。
変数にブロックを割り当てる際の具体的な構文を下図に示します。

blocks_2x.png

関数のようにブロック変数を呼び出すことができます。

int result = myBlock(4)    // result is 28

ブロックはローカルのレキシカルスコープ内のデータを共有します。
このブロックの特性は有用で、メソッドを実装し、そのメソッドがブロックを定義している場合、ブロックはインスタンス変数を含むグローバル変数や関数だけでなく、(スタック変数を含む)メソッドの引数やローカル変数へのアクセスを持ちます。
このアクセスは読み込みのみですが、変数が__block修飾子で宣言されている場合、その値はブロック内で変更することができます。
ブロックを囲むメソッドまたは関数が返されてローカルスコープが破棄された後でも、ローカル変数はブロックへの参照がある間はブロックオブジェクトの一部として保持されます。

メソッドや関数の引数として、ブロックはコールバックとして扱うことができます。
呼び出されると、メソッドまたは関数はいくつかの処理を実行し、適切な瞬間に、追加の情報を要求する、またはプログラム固有の動作を取得するために、(ブロックを介して)呼び出すコードをコールバックします。
ブロックは呼び出し時点でコールバックのコードを提供するために呼び出し元を有効にします。
『コンテキスト』構造で必要とされるデータをパッケージングする代わりに、ブロックはホストメソッドまたは関数が行うように同じレキシカルスコープからデータをキャプチャします。
ブロックコードは別々のメソッドまたは関数で実装する必要が無いので、貴方の実装コードは単純で容易に理解できるようにすることができます。

Objective-Cフレームワークにはブロックパラメータを持つ多くのメソッドがあります。
例えば、FoundationフレームワークのNSNotificationCenterクラスは、ブロック引数を持つ以下のメソッドを宣言します。

- (id)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block

このメソッドは通知センターにオブザーバを追加します(通知は『デザインパターンを使ったアプリの合理化』で説明されています)。
指定された名前の通知がポストされると、ブロックが通知を処理するために呼び出されます。

    opQ = [[NSOperationQueue alloc] init];
    [[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted"
            object:nil queue:opQ
        usingBlock:^(NSNotification *notif) {
        // handle the notification
    }];



●プロトコルとカテゴリ

プロトコルは、それらのクラスがプロトコルを実装している共通のスーパークラスを持っていなくても、任意のクラスで実装することができるメソッドを宣言します。
プロトコルメソッドは、任意の特定のクラスに依存しない動作を定義します。
プロトコルは単に、他のクラスが実装を担当しているインターフェイスを定義します。
貴方のクラスがプロトコルのメソッドを実装した場合、貴方のクラスはプロトコルに準拠していると言われます。

実際の観点からすると、プロトコルは任意の特定のクラスのインスタンスであることを必要とせずに、オブジェクト間の請負を確立するメソッドのリストを定義します。
この請負は、それらのオブジェクト間の通信を有効にします。
一つの目的は、発生しているイベントについて別のオブジェクトに伝える、またはそれらのイベントについての通知を必要とする場合です。

UIApplicationクラスは、アプリケーションに必要な動作を実装します。
貴方がUIApplicationのサブクラスに、アプリケーションの現在の状態についての簡単な通知を受信するよう強制する代わりに、UIApplicationクラスは割り当てられたデリゲートオブジェクトの特定のメソッドを呼び出すことによって、それらの通知を配信します。
UIApplicationDelegateプロトコルのメソッドを実装したオブジェクトは、それらの通知を受信し、適切な応答を提供することができます。

貴方のクラスのインターフェイス・ブロックをプロトコルに準拠させる、またはプロトコルを採用するには、継承しているクラスの名前の後に山括弧(< ... >)内にプロトコルの名前を置くことによって指定することができます。
次のコード行は、『初めてのiOSアプリケーション』でのUITextFieldDelegateプロトコルの採用を示します。

@interface HelloWorldViewController : UIViewController <UITextFieldDelegate> {

貴方が実装するプロトコルメソッドを宣言する必要はありません。

プロトコルの宣言は、プロトコルが親クラスを持たず、インスタンス変数を定義しない(プロパティを宣言することはできます)ということを除けば、クラスのインターフェイスのそれと似ています。
以下の例では、1つのメソッドを持つ簡単なプロトコルの宣言を示します。

@protocol MyProtocol
- (void)myProtocolMethod;
@end

多くのデリゲートプロトコルでは、プロトコルを採用することは単にプロトコルによって定義されたメソッドを実装するためです。
いくつかのプロトコルでは、プロトコルをサポートしていることを明示的に指定する必要があり、必須およびオプションのメソッドの両方を指定することができます。

Objective-Cフレームワークのヘッダファイルを調べ始めると、すぐに以下のような行に遭遇する場合があります。

@interface NSDate (NSDateCreation)

この行は括弧でカテゴリの名前を囲む構文規則によって、カテゴリを宣言しています。
カテゴリは、サブクラス化せずにクラスのインターフェイスを拡張することができる、Objective-C言語の機能です。
カテゴリ内のメソッドは(貴方のプログラムのスコープ内で)クラス型の一部となり、クラスのサブクラスの全てに継承されます。
カテゴリで定義されたメソッドを呼び出すためのクラス(またはそのサブクラス)の任意のインスタンスへ、メッセージを送信することができます。

ヘッダファイル内の関連するメソッド宣言をグループ化するための手段として、カテゴリを使用することができます。
また別のヘッダファイル内に異なるカテゴリの宣言を置くこともできます。
フレームワークでは、明瞭化のためにヘッダファイル全体でこれらの技術を使用しています。

また実装ファイル(.m)で、プライベートプロパティやプライベートメソッドを宣言するためのクラス拡張として知られている、匿名カテゴリを使用することができます。
クラス拡張は、括弧内にテキストが無いことを除けばカテゴリのように見えます。
一般的なクラス拡張は以下のようになります。

@interface MyAppDelegate ()
@property (strong) MyDataObject *data;
@end



●定義済み型とコーディング計画

Objective-Cには、特別な目的のために予約されているため、変数名として使用できないいくつかの用語があります。
これらの用語のいくつかは、@interfaceや@endなどのアットマーク(@)を接頭辞とするコンパイラディレクティブです。
その他の予約語は、定義済み型とそれらの型を伴うリテラルです。
Objective-Cは、ANSI Cでは見ることの無いリテラルと定義済み型の数を使用します。
いくつかのケースでは、これらの型とリテラルがANSI Cの対応物として置換されます。
下表に各型で許容されているリテラルを含む重要な物のいくつかを説明します。

説明とリテラル
id動的オブジェクトの型。動的および静的共に、型付け済みオブジェクトの否定リテラルはnilです。
Class動的クラス型。否定リテラルはNilです。
SELセレクタのデータ型(typedef)で、このデータ型は実行時にメソッドのシグネチャを表します。
否定リテラルはNULLです。
BOOLブール型。リテラル値はYESとNOです。

多くの場合、エラーチェックや制御フローコードで、これらの定義済み型とリテラルを使用しています。
プログラムの制御フロー文で、どのように進行させるかを決定するために、適切なリテラルをテストすることができます。
以下に例を示します。

NSDate *dateOfHire = [employee dateOfHire];
if (dateOfHire != nil) {
    // handle this case
}

このコードは、雇用の日付を表すオブジェクトがnilでない(言い換えると、有効なオブジェクトである)場合に特定の処理を行う論理です。
同じ分岐を行う簡単な方法は以下の通りです。

NSDate *dateOfHire = [employee dateOfHire];
if (dateOfHire) {
    // handle this case
}

(dateOfHireオブジェクトへの参照を必要としないと仮定すると)更にコード行を減らすことができます。

if ([employee dateOfHire]) {
    // handle this case
}

ブール値もほぼ同じ方法で扱えます。
以下の例では、isEqual:メソッドはブール値を返します。

BOOL equal = [objectA isEqual:objectB];
if (equal == YES) {
    // handle this case
}

これはオブジェクトが存在しない、あるいはnilであるかをテストできるコードで、このコードも同じ方法で短縮することができます。

Objective-Cでは、悪影響を与えることなくnilにメッセージを送信することができます。
実際には全く影響が無い
メソッドがオブジェクトを返すことになっている場合に実行時にnilを返すことを除けば、実際に全く効果はありません。
nilに送信されたメッセージからの戻り値は、何かを返すオブジェクトとして型付けされている限り、動作することが保証されています。

Objective-Cでは他にも重要な2つの予約語としてselfとsuperがあります。
最初の予約語selfは、現在のオブジェクトを参照するために、メッセージの実装内で使用することができるローカル変数で、C++のそれと同等です。
メッセージ式のレシーバとしてのみ、予約語superをselfの代わりにすることができます。
selfにメッセージを送信する場合、ランタイムは最初に現在のオブジェクトのクラスに実装しているメソッドを検索し、メソッドが見つけられなかった場合はそのスーパークラス(など)を検索します。
superにメッセージを送信した場合、ランタイムは最初にスーパークラスに実装しているメソッドを検索します。

selfとsuper両方の主な用途はメッセージを送信することです。
呼び出すメソッドがselfのクラスによって実装された場合、以下のようにselfにメッセージを送信します。

[self doSomeWork];

selfも宣言済みプロパティによって合成されたアクセサメソッドを呼び出すために、以下のようにドット表記を使用します。

NSString *theName = self.name;

多くの場合、スーパークラスから継承されたメソッドのオーバーライド(つまり再実装)で、superへメッセージを送信します。
この場合、呼び出されたメソッドはオーバーライドされたメソッドと同じシグネチャを持ちます。



参考文献

Apple/Start Developing iOS Apps Today

Apple/Write Objective-C Code

0 CommentsPosted in 資料






bose_soundlink_revolve
Calendar
11 | 2012/12 | 01
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

bose_soundlink_revolve
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR