0% found this document useful (0 votes)
17K views176 pages

03 iPhoneOSProgrammingGuide

Download as pdf or txt
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 176

iPhoneアプリケーションプログラミング

ガイド
iPhone

2009-01-06
Java and all Java-based trademarks are
Apple Inc. trademarks or registered trademarks of Sun
© 2009 Apple Inc. Microsystems, Inc. in the U.S. and other
All rights reserved. countries.
OpenGL is a registered trademark of Silicon
本書の一部あるいは全部を Apple Inc. から Graphics, Inc.
書面による事前の許諾を得ることなく複写
Apple Inc. は本書の内容を確認しておりますが、
複製(コピー)することを禁じます。ま 本書に関して、明示的であるか黙示的であるかを
た、製品に付属のソフトウェアは同梱のソ 問わず、その品質、正確さ、市場性、または特定
の目的に対する適合性に関して何らかの保証また
フトウェア使用許諾契約書に記載の条件の は表明を行うものではありません。その結果、本
もとでお使いください。書類を個人で使用 書は「現状有姿のまま」提供され、本書の品質ま
する場合に限り 1 台のコンピュータに保管 たは正確さに関連して発生するすべての損害は、
購入者であるお客様が負うものとします。
すること、またその書類にアップルの著作
いかなる場合も、Apple Inc. は、本書の内容に含
権表示が含まれる限り、個人的な利用を目 まれる瑕疵または不正確さによって生じる直接
的に書類を複製することを認めます。 的、間接的、特殊的、偶発的、または結果的損害
に対する賠償請求には一切応じません。そのよう
Apple ロゴは、米国その他の国で登録され な損害の可能性があらかじめ指摘されている場合
においても同様です。
た Apple Inc. の商標です。
上記の損害に対する保証および救済は、口頭や書
キーボードから入力可能な Apple ロゴにつ 面によるか、または明示的や黙示的であるかを問
いても、これを Apple Inc. からの書面によ わず、唯一のものであり、その他一切の保証にか
わるものです。 Apple Inc. の販売店、代理店、ま
る事前の許諾なしに商業的な目的で使用す たは従業員には、この保証に関する規定に何らか
ると、連邦および州の商標法および不正競 の変更、拡張、または追加を加える権限は与えら
れていません。
争防止法違反となる場合があります。
一部の国や地域では、黙示あるいは偶発的または
本書に記載されているテクノロジーに関し 結果的損害に対する賠償の免責または制限が認め
られていないため、上記の制限や免責がお客様に
ては、明示または黙示を問わず、使用を許 適用されない場合があります。 この保証はお客
諾しません。 本書に記載されているテクノ 様に特定の法的権利を与え、地域によってはその
ロジーに関するすべての知的財産権は、 他の権利がお客様に与えられる場合もあります。
Apple Inc. が保有しています。 本書は、
Apple ブランドのコンピュータ用のアプリ
ケーション開発に使用を限定します。
本書には正確な情報を記載するように努め
ました。 ただし、誤植や制作上の誤記がな
いことを保証するものではありません。
Apple Inc.
1 Infinite Loop
Cupertino, CA 95014
U.S.A.

アップルジャパン株式会社
〒163-1450 東京都新宿区西新宿
3 丁目20 番2 号
東京オペラシティタワー
http://www.apple.com/jp/

App Store is a service mark of Apple Inc.


Apple, the Apple logo, Bonjour, Carbon, Cocoa,
iPod, iTunes, Mac, Mac OS, Macintosh,
Objective-C, Pages, Quartz, Safari, and Xcode
are trademarks of Apple Inc., registered in the
United States and other countries.
Finder, Instruments, iPhone, and Multi-Touch
are trademarks of Apple Inc.
NeXT is a trademark of NeXT Software, Inc.,
registered in the United States and other
countries.
目次

序章 はじめに 11

対象読者 12
この書類の構成 12
フィードバックの提供 12
関連項目 13

第1章 コアアプリケーション 15

コアアプリケーションアーキテクチャ 15
アプリケーションのライフサイクル 15
イベント処理サイクル 18
基礎となるデザインパターン 20
アプリケーションのランタイム環境 21
すばやい起動、短時間の使用 22
アプリケーションサンドボックス 22
仮想メモリシステム 23
自動スリープタイマー 23
アプリケーションバンドル 23
情報プロパティリスト 26
アプリケーションアイコンと起動画像 29
nibファイル 29
重要なアプリケーションタスクの処理 30
初期化と終了 30
割り込みへの応答 31
メモリ不足警告を監視する 33
アプリケーションの動作のカスタマイズ 34
横長モードでの起動 34
他のアプリケーションとのやり取り 35
カスタムURLスキームの実装 36
アプリケーション環境設定の表示 39
アプリケーションの国際化 40
パフォーマンスと応答性のチューニング 42
メモリを効率的に使用する 42
浮動小数点演算の留意点 44
電力消費を抑える 44
コードをチューニングする 45

第2章 ウインドウとビュー 47

ウインドウとビューとは? 47
UIWindowの役割 47

3
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
目次

UIViewの役割 48
UIKitのビュークラス 49
View Controllerの役割 52
ビューのアーキテクチャとジオメトリ 52
ビューの対話モデル 52
ビューのレンダリングアーキテクチャ 55
ビューの座標系 57
フレーム(frame)、境界(bounds)、および中心(center)の関係 58
座標系の変換 60
コンテンツモードと拡大縮小 61
自動サイズ変更動作 63
ビュー階層の作成と管理 65
ビューオブジェクトの作成 66
サブビューの追加と削除 66
ビュー階層での座標の変換 68
ビューのタグ付け 70
実行時のビューの変更 70
ビューのアニメーション化 70
レイアウト変更への対応 72
ビューのコンテンツの再描画 73
ビューの非表示 74
カスタムビューの作成 74
カスタムビューの初期化 74
ビューのコンテンツの描画 75
イベントへの応答 76
ビュー使用後のクリーンアップ 77

第3章 イベント処理 79

イベントとタッチ 79
イベントの送付 81
レスポンダオブジェクトとレスポンダチェーン 82
イベント送付の制御 83
マルチタッチイベントの処理 84
イベント処理メソッド 84
単一のタップジェスチャと複数のタップジェスチャの処理 85
スワイプジェスチャの検出 86
複雑なマルチタッチシーケンスの処理 87
イベント処理のテクニック 88

第4章 グラフィックスと描画 91

UIKitのグラフィックスシステム 91
ビューの描画サイクル 91
座標と座標変換 92
グラフィックスコンテキスト 93

4
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
目次

点とピクセル 93
色および色空間 94
サポートされる画像形式 94
描画に関するヒント 95
カスタム描画コードを使用する場面の判断 95
描画パフォーマンスの改善 95
画像品質の維持 96
QuartzとUIKitを使用した描画 96
グラフィックスコンテキストの設定 97
画像の作成と描画 99
パスの作成と描画 100
パターン、グラデーション、陰影の作成 100
OpenGL ESを使用した描画 101
レンダリングサーフェスのセットアップ 101
ベストプラクティス 103
実装の詳細 105
詳細情報 109
Core Animation効果の適用 109
レイヤについて 110
アニメーションについて 110

第5章 テキストとWeb 111

テキストとWebのサポート 111
Text View 111
Web View 113
キーボードと入力方法 114
キーボードの管理 116
キーボード通知を受信する 116
キーボードを表示する 118
キーボードをしまう 118
キーボードの下に隠れているコンテンツを移動する 119
テキストの描画 121

第6章 ファイルとネットワーク 123

ファイルとデータの管理 123
よく使われるディレクトリ 123
バックアップと復元 125
アプリケーションディレクトリへのパスの取得 125
ファイルデータの読み取りおよび書き込み 127
ファイルアクセスガイドライン 131
状態情報を保存する 131
大文字小文字の区別 132
ネットワーク 132
効率的なネットワーク処理のためのヒント 132

5
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
目次

Wi-Fiの使用 133

第7章 マルチメディアサポート 135

iPhone OSでのサウンドの使用 135


基礎:ハードウェアコーデック、オーディオフォーマット、オーディオセッション 136
オーディオの再生 140
オーディオの録音 146
ストリーミングされたオーディオの解析 147
iPhone OSでのオーディオユニットのサポート 148
iPhoneオーディオのベストプラクティス 148
ビデオファイルの再生 150

第8章 デバイスサポート 153

加速度センサーイベントへのアクセス 153
適切な更新間隔の選択 154
加速度データからの重力成分の分離 155
加速度データからの瞬間的な動きの分離 155
現在のデバイスの向きの取得 156
ユーザの現在位置の取得 156
カメラによる写真の撮影 158
フォトライブラリからの写真の選択 160

第9章 アプリケーション環境設定 161

環境設定のためのガイドライン 161
環境設定インターフェイス 162
Settingsバンドル 163
Settings Pageのファイル形式 164
階層型環境設定 165
ローカライズされたリソース 166
Settingsバンドルの追加と変更 167
Settingsバンドルの追加 167
編集用のSettings Pageの準備 167
Settings Pageの設定:チュートリアル 168
追加のSettings Pageファイルの作成 172
環境設定へのアクセス 173
シミュレートしたアプリケーションの環境設定のデバッグ 173

改訂履歴 書類の改訂履歴 175

6
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
図、表、リスト

第1章 コアアプリケーション 15

図 1-1 アプリケーションのライフサイクル 16
図 1-2 イベントと描画サイクル 19
図 1-3 メイン実行ループでのイベント処理 19
図 1-4 ターゲットの情報ウインドウの「プロパティ(Properties)」ペイン 26
図 1-5 情報プロパティリストエディタ 27
図 1-6 割り込みの間のイベントの流れ 32
図 1-7 Info.plistファイルにおけるカスタムURLスキームの定義 37
図 1-8 言語の環境設定ビュー 40
表 1-1 iPhoneアプリケーションで使われるデザインパターン 21
表 1-2 標準的なアプリケーションバンドル 24
表 1-3 Info.plistファイルの重要なキー 27
表 1-4 アプリケーションデリゲートの責務 31
表 1-5 CFBundleURLTypesプロパティのキーと値 36
表 1-6 アプリケーションのメモリ占有量を削減するためのヒント 43
表 1-7 メモリ割り当てのヒント 44
リスト 1-1 iPhoneアプリケーションのmain関数 16
リスト 1-2 カスタムスキームに基づいたURLリクエストの処理 38
リスト 1-3 ローカライズされた言語のサブディレクトリ 41

第2章 ウインドウとビュー 47

図 2-1 ビュークラスの階層 50
図 2-2 UIKitとビューオブジェクトとの対話 53
図 2-3 ビューの座標系 58
図 2-4 ビューのフレームと境界の関係 59
図 2-5 ビューの境界の変更 60
図 2-6 scale-to-fillコンテンツモードを使用して拡大されたビュー 61
図 2-7 コンテンツモードの比較 62
図 2-8 ビューの自動サイズ変更マスク定数 64
図 2-9 「時計(Clock)」アプリケーションのレイヤ化されたビュー 65
図 2-10 「時計(Clock)」アプリケーションのビュー階層 66
図 2-11 回転したビューの値の変換 69
表 2-1 自動サイズ変更マスク定数 63
表 2-2 アニメーション化可能プロパティ 71
リスト 2-1 ビューを含むウインドウの作成 67
リスト 2-2 ビューのサブクラスの初期化 74
リスト 2-3 描画メソッド 75
リスト 2-4 deallocメソッドの実装 77

7
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
図、表、リスト

第3章 イベント処理 79

図 3-1 マルチタッチシーケンスとタッチフェーズ 80
図 3-2 UIEventオブジェクトとそれに対応するUITouchオブジェクトの関係 81
リスト 3-1 ダブルタップジェスチャの検出 85
リスト 3-2 ビュー内のスワイプジェスチャの追跡 86
リスト 3-3 複雑なマルチタッチシーケンスの処理 87

第4章 グラフィックスと描画 91

表 4-1 サポートされる画像形式 94
表 4-2 描画パフォーマンス改善のヒント 95
表 4-3 グラフィックスの状態を変更するCore Graphics関数 97
表 4-4 画像使用のシナリオ 99

第5章 テキストとWeb 111

図 5-1 UICatalogアプリケーションのテキスト関連クラス 112


図 5-2 Web View 114
図 5-3 さまざまなキーボードタイプ 115
図 5-4 さまざまなキーボードと入力方式 116
図 5-5 縦長モードと横長モードのキーボードサイズの比較 117
図 5-6 キーボードに合わせてコンテンツを調整する 119
リスト 5-1 キーボード通知の処理 120

第6章 ファイルとネットワーク 123

表 6-1 iPhoneアプリケーションのディレクトリ 123


表 6-2 よく使われる検索パス定数 126
リスト 6-1 アプリケーションのDocuments/ディレクトリへのファイルシステムパスの
取得 126
リスト 6-2 NSDataオブジェクトへのプロパティリストオブジェクトの変換とストレー
ジへの書き込み 128
リスト 6-3 アプリケーションのDocumentsディレクトリからのプロパティリストオブ
ジェクトの読み取り 128
リスト 6-4 アプリケーションのDocumentsディレクトリへのデータの書き込み 130
リスト 6-5 アプリケーションのDocumentsディレクトリからのデータの読み取り 130

第7章 マルチメディアサポート 135

図 7-1 転送コントロール付きのメディアプレーヤーインターフェイス 150


表 7-1 オーディオセッションインターフェイスによって提供される機能 138
表 7-2 オーディオ割り込みの処理方法 139
表 7-3 サポートされているオーディオユニット 148
表 7-4 オーディオのヒント 149
リスト 7-1 オーディオセッションの初期化 138

8
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
図、表、リスト

リスト 7-2 オーディオセッションカテゴリの設定 139


リスト 7-3 サウンドIDオブジェクトの作成 141
リスト 7-4 システムサウンドの再生 141
リスト 7-5 バイブレーションの起動 141
リスト 7-6 AVAudioPlayerオブジェクトの設定 142
リスト 7-7 AVAudioPlayerのデリゲートメソッドの実装 142
リスト 7-8 AVAudioPlayerオブジェクトの制御 143
リスト 7-9 オーディオキューオブジェクトの作成 144
リスト 7-10 再生レベルの直接設定 145
リスト 7-11 AudioQueueLevelMeterState構造体 146
リスト 7-12 フルスクリーンムービーの再生 151

第8章 デバイスサポート 153

表 8-1 加速度イベントの一般的な更新間隔 154


リスト 8-1 加速度センサーの設定 153
リスト 8-2 加速度センサーイベントの受け取り 154
リスト 8-3 加速度センサーのデータからの重力の影響の分離 155
リスト 8-4 加速度センサーのデータからの瞬間的な動きの取得 155
リスト 8-5 位置更新の初期化と処理 157
リスト 8-6 写真撮影用のインターフェイスの表示 159
リスト 8-7 画像ピッカー用のデリゲートメソッド 159

第9章 アプリケーション環境設定 161

図 9-1 子ペインを使った環境設定の編成 166


図 9-2 書式化されたRoot.plistファイルの内容 168
図 9-3 ルートのSettingsページ 169
表 9-1 環境設定の要素のタイプ 162
表 9-2 Settings.bundleディレクトリの内容 163
表 9-3 環境設定のSettings Pageファイルのルートレベルキー 165
リスト 9-1 アプリケーションの環境設定の値へのアクセス 173

9
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
図、表、リスト

10
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
序章

はじめに

注: この文書は、以前は『iPhone OS Programming Guide』というタイトルでした。

iPhone SDKは、ユーザのホーム(Home)画面にアイコンとして表示される、iPhoneのネイティブアプ
リケーションを作成するために必要なツールおよびリソースを提供します。Safari上で実行される
Webアプリケーションとは違い、ネイティブアプリケーションは、スタンドアロン実行可能ファイ
ルとして、iPhone OSベースのデバイス上で直接実行されます。ネイティブアプリケーションは、加
速度センサー、ロケーションサービス、Multi-Touchインターフェイスなど、iPhoneをおもしろくす
るすべての機能にアクセスできます。また、ローカルのファイルシステムにデータを保存したり、
カスタムURLスキームを利用して、インストール済みのほかのアプリケーションと通信することも
できます。

iPhone OSでは、UIKitフレームワークを使用してネイティブアプリケーションを開発します。このフ
レームワークは、基本的なインフラストラクチャとデフォルトの動作を提供します。このデフォル
トの動作を利用すると、数分程度で機能的なアプリケーションが作成できます。UIKitフレームワー
ク(および、システム上のその他のフレームワーク)は、かなりの量のデフォルトの動作を提供し
ていますが、それをカスタマイズしたり拡張するためのフックも提供しています。

11
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
序章
はじめに

対象読者

この文書は、iPhoneのネイティブアプリケーションを開発しようとしている、初心者および経験者
の両方のiPhone OSデベロッパを対象としています。この文書の目的は、デベロッパの皆さんにiPhone
アプリケーションのアーキテクチャに慣れてもらい、UIKitおよびその他の重要なシステムフレーム
ワークの主要なカスタマイズポイントを示すことです。その過程で、適切な設計判断をするために
役立つガイダンスも示します。また、与えられたテーマについてのアドバイスや、さらに詳しい議
論を提供してくれる追加文書も紹介します。

この文書で説明しているフレームワークの多くはMac OS Xにも存在しますが、必ずしもMac OS Xま
たはそのテクノロジーに精通していることを前提とはしていません。

この書類の構成

この文書は、次の各章で構成されています。

■ 「コアアプリケーション」 (15 ページ)には、すべてのiPhoneアプリケーションに共通する基


本構成についての重要な情報が含まれています。それには、どのアプリケーションも対応して
おく必要がある重要なタスクが含まれています。
■ 「ウインドウとビュー」 (47 ページ)では、iPhoneウインドウモデルについて説明し、ビュー
を使ってユーザインターフェイスを編成する方法を紹介します。
■ 「イベント処理」 (79 ページ)では、iPhoneイベントモデルについて説明し、Multi-Touchイベ
ントの処理方法を紹介します。
■ 「グラフィックスと描画」 (91 ページ)では、iPhone OSのグラフィックスアーキテクチャに
ついて説明し、図形や画像の描画方法やコンテンツにアニメーションを組み込む方法を紹介し
ます。
■ 「テキストとWeb」 (111 ページ)では、iPhone OSでサポートされているテキストについて説
明します。ここには、システムキーボードの管理方法の例も含まれています。
■ 「ファイルとネットワーク」 (123 ページ)では、ファイルとネットワーク接続を扱う際のガ
イドラインを示します。
■ 「マルチメディアサポート」 (135 ページ)では、iPhone OSで利用できるオーディオとビデオ
の各テクノロジーを使用する方法を紹介します。
■ 「デバイスサポート」 (153 ページ)では、位置追跡、加速度センサー、および内蔵カメラな
どの機能をアプリケーションに組み込む方法を紹介します。
■ 「アプリケーション環境設定」 (161 ページ)では、アプリケーション環境設定を構成したり、
それを「設定(Settings)」アプリケーションに表示する方法を紹介します。

フィードバックの提供

ドキュメントに関するフィードバックは、各ページの一番下にある組み込みのフィードバックフォー
ムを使って送ってください。

12 対象読者
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
序章
はじめに

Appleのソフトウェアやドキュメントのバグを発見した場合は、Appleにお知らせください。また、
製品やドキュメントの今後の改訂版に期待する機能についての機能拡張リクエストを提出すること
もできます。バグ報告や機能拡張リクエストを提出するには、次に示すURLにあるADC Webサイト
のBug Reportingページを使用します。

http://developer.apple.com/jp/bugreporter/

バグ報告を行うには、ADCの有効なログイン名とパスワードが必要です。ログイン名は、Bug Reporting
ページに説明されている手順に従って無料で入手できます。

関連項目

次の文書には、iPhone OS向けのアプリケーションを開発する前に、すべてのデベロッパが読んでお
く必要がある重要な情報が書かれています。

■ 『iPhone Development Guide』では、iPhoneの開発プロセスに関する重要な情報をツールの視点か


ら提供しています。この文書は、ソフトウェアをビルド、実行、およびテストするための、デ
バイスの構成とXcode(およびその他のツール)の使用についても言及しています。
■ 『Cocoa Fundamentals Guide』では、iPhoneアプリケーションの開発に使用するデザインパター
ンとデザインプラクティスに関する基本的な情報を提供しています。
■ 『iPhone Human Interface Guidelines』では、iPhoneアプリケーションのユーザインターフェイス
の設計方法についてのガイダンスと重要な情報を提供しています。

次のリファレンスおよび解説書は、iPhoneの重要なトピックスについての補足情報を提供していま
す。

■ 『UIKit Framework Reference』および『Foundation Framework Reference』では、この文書で説明し


ている各クラスに関するリファレンス情報を提供しています。
■ 『View Controller Programming Guide for iPhone OS』では、iPhoneアプリケーションのインターフェ
イス作成のためのView Controllerの使用について情報を提供しています。
■ 『Table View Programming Guide for iPhone OS』では、iPhoneアプリケーションで頻繁に使われる
Table Viewを扱うための情報を提供しています。
■ 『The Objective-C 2.0 Programming Language』では、Objective-Cと、iPhone OSのほとんどの動的な
動作と拡張性の基礎となるObjective-Cランタイムシステムについて解説しています。

関連項目 13
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
序章
はじめに

14 関連項目
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章

コアアプリケーション

すべてのiPhoneアプリケーションは、UIKitフレームワークを使用して作成されます。したがって、
本質的に同じコアアーキテクチャを持っています。UIKitは、アプリケーションを実行したり、ユー
ザ入力の処理や画面へのコンテンツの表示を調整するために必要な主要なオブジェクトを提供しま
す。アプリケーションごとの相違点は、これらのデフォルトのオブジェクトをどのように構成する
かと、アプリケーションのユーザインターフェイスや動作を追加するために、どこにカスタムオブ
ジェクトを組み込むかです。

アプリケーションのユーザインターフェイスや基本動作へのカスタマイズは、アプリケーションの
カスタムコード内で行われますが、アプリケーションの最上位レベルで行わなければならないカス
タマイズもたくさんあります。これらのアプリケーションレベルのカスタマイズは、アプリケー
ションがシステムや、デバイスにインストール済みのその他のアプリケーションとやり取りする方
法に影響を与えるため、カスタマイズが必要な場合とデフォルトの動作で十分な場合を理解するこ
とが重要です。この章では、コアアプリケーションアーキテクチャの概要を説明し、カスタマイズ
が必要な場合とデフォルトの動作を使用する場合の判断をするために役立つ上位レベルのカスタマ
イズポイントを示します。

コアアプリケーションアーキテクチャ

ユーザがアプリケーションを起動したときから終了するまで、UIKitフレームワークは、アプリケー
ションの主要なインフラストラクチャの大部分を管理します。iPhoneアプリケーションは絶えずシ
ステムからイベントを受信し、それらのイベントに応答しなければなりません。イベントの受信は
UIApplicationオブジェクトの仕事ですが、イベントへの応答はカスタムコードで処理する必要が
あります。イベントに応答する必要がある場所について理解するには、iPhoneアプリケーションの
全体的なライフサイクルとイベントサイクルを少し理解しておくと役立ちます。以降のセクション
では、これらのサイクルについて説明し、iPhoneアプリケーションの開発全体を通して使われるい
くつかの主要なデザインパターンの概要を示します。

アプリケーションのライフサイクル
アプリケーションのライフサイクルは、アプリケーションの起動から終了までの間に発生する一連
のイベントで構成されます。iPhone OSでは、ユーザはホーム(Home)画面上のアイコンをタップする
ことによってアプリケーションを起動します。タップが発生するとすぐに、システムはトランジ
ショングラフィックスを表示し、そのアプリケーションのmainを呼び出してアプリケーションの起
動へと進みます。以降、初期化作業のほとんどはUIKitに渡されます。UIKitはアプリケーションのユー
ザインターフェイスをロードし、イベントループを準備します。イベントループの中では、UIKitは
カスタムオブジェクトへのイベントの配信と、アプリケーションから発行されたコマンドへの応答
を調整します。ユーザがアプリケーションを終了させるためのアクションを実行すると、UIKitはア
プリケーションをそれを通知し、終了処理を開始します。

図 1-1は、iPhoneアプリケーションのライフサイクルを単純化して示したものです。この図には、ア
プリケーションの起動時から終了時までに発生する一連のイベントが示されています。初期化時と
終了時に、UIKitはそれを知らせるために特定のメッセージをアプリケーションデリゲートオブジェ

コアアプリケーションアーキテクチャ 15
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

クトに送信します。イベントループの中で、UIKitは、アプリケーションのカスタムイベントハンド
ラにイベントを送信します。初期化イベントと終了イベントの処理については、後述の「初期化と
終了」 (30 ページ)で説明します。また、イベント処理プロセスについては「イベント処理サイ
クル」 (18 ページ)で概要を、それ以降の各章で詳細を説明します。

図 1-1 アプリケーションのライフサイクル

UIKit Your code

User taps application icon

main()

UIApplicationMain() applicationDidFinishLaunching:

Event Handle event


Loop

System asks application to terminate applicationWillTerminate:

Application execution terminates

Main関数

iPhoneアプリケーションでは、main関数の使用は極力抑えられます。代わりに、アプリケーション
の実行に実際に必要な作業のほとんどは、UIApplicationMain関数によって処理されます。その結
果、Xcodeで新規アプリケーションプロジェクトを開始すると、どのプロジェクトテンプレートに
も、リスト 1-1に示すような標準的なmain関数があります。mainルーチンが実行するのは、自動解
放プールを作成して、UIApplicationMainを呼び出し、自動解放プールを解放するという3つの処
理だけです。いくつかの例外はありますが、この関数の実装を変更する必要はありません。

リスト 1-1 iPhoneアプリケーションのmain関数


#import <UIKit/UIKit.h>

int main(int argc, char *argv[])


{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, nil);
[pool release];
return retVal;
}

16 コアアプリケーションアーキテクチャ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

注: 自動解放プールは、メモリ管理に使用されます。このプールは、コードの機能ブロックの間
に作成されるオブジェクトの解放を遅らせるために使用されるCocoaのメカニズムです。自動解放
プールの詳細については、『Memory Management Programming Guide for Cocoa』を参照してくださ
い。iPhoneアプリケーションの自動解放プールに関連する特有のメモリ管理ガイドラインについて
は、「メモリを賢く割り当てる」 (43 ページ)を参照してください。

前述のリストのUIApplicationMain関数は、4つのパラメータを取り、それらを使用してアプリケー
ションの初期化を行います。この関数に渡されるデフォルト値を変更する必要はありませんが、ア
プリケーションの起動という点からその目的を説明しておく価値はあります。mainに渡されるargc
パラメータとargvパラメータのほかに、この関数は、主クラス(アプリケーションオブジェクトの
クラス)とアプリケーションデリゲート(delegate、委任)のクラスを識別する2つの文字列パラ
メータを取ります。主クラスの文字列の値がnilの場合、UIKitはデフォルトでUIApplicationクラ
スを使用します。アプリケーションデリゲートのクラスの値がnilの場合、UIKitは、アプリケーショ
ンデリゲートが、アプリケーションのメインnibファイルからロードされるオブジェクトの1つであ
ることを前提にします(Xcodeのテンプレートを使用して作成されたアプリケーションの場合)。
これらのパラメータのいずれかにnil以外の値が設定されている場合、UIApplicationMain関数は、
アプリケーションの起動中に、それに対応するクラスのインスタンスを作成して、先に示した目的
のためにそれを使用します。したがって、アプリケーションがUIApplicationのカスタムサブクラ
スを使用する場合は(このような方法はお勧めしませんが、可能です)、このカスタムクラスの名
前を3番目のパラメータで指定します。

アプリケーションデリゲート

アプリケーションの上位レベルの動作を監視するのは、デベロッパが提供するカスタムオブジェク
トである、アプリケーションデリゲートオブジェクトの責任です。デリゲーションは、デフォルト
のUIApplicationオブジェクトなどの複雑なUIKitオブジェクトのサブクラス化を避けるために使用
されるメカニズムです。サブクラス化してメソッドをオーバライドする代わりに、複雑なオブジェ
クトは変更せずに使用して、デリゲートオブジェクトの内部にカスタムコードを配置します。関心
のあるイベントが発生すると、複雑なオブジェクトはデリゲートオブジェクトにメッセージを送り
ます。デベロッパはこれらの「フック」を使用して、カスタムコードを実行して必要な動作を実装
できます。

重要: デリゲートデザインパターンは、アプリケーション開発の時間と労力を節約することを目
的としています。したがって、理解しておくべき重要なパターンです。iPhoneアプリケーションで
使用される主要なデザインパターンの概要については、「基礎となるデザインパターン」 (20 ペー
ジ)を参照してください。デリゲーションおよびその他のUIKitデザインパターンの詳細については、
『Cocoa Fundamentals Guide』を参照してください。

アプリケーションデリゲートオブジェクトは、いくつかの重要なシステムメッセージの処理を担当
します。このため、すべてのiPhoneアプリケーションに存在しなければなりません。このオブジェ
クトは、UIApplicationDelegateプロトコルを採用してさえいれば、どのようなクラスのインスタ
ンスでもかまいません。このプロトコルのメソッドは、アプリケーションライフサイクルへのフッ
クを定義しているため、カスタム動作を実装する手段となります。これらのメソッドのすべてを実
装する必要はありませんが、「重要なアプリケーションタスクの処理」 (30 ページ)に記述され
ているメソッドは、すべてのアプリケーションデリゲートが実装しなければなりません。

UIApplicationDelegateプロトコルのメソッドの詳細については、『UIApplicationDelegate Protocol
Reference』を参照してください。

コアアプリケーションアーキテクチャ 17
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

メインnibファイル

初期化時に発生するもう1つのタスクは、アプリケーションのメインnibファイルのロードです。ア
プリケーションの情報プロパティリスト(Info.plist)ファイルにNSMainNibFileキーが含まれてい
る場合、UIApplicationオブジェクトは初期化処理の一部としてそのキーで指定されたnibファイル
をロードします。メインnibファイルは自動的にロードされる唯一のnibファイルです。ただし、必
要に応じて追加のnibファイルをロードすることができます。

nibファイルは、ディスクベースのリソースファイルで、1つ以上のオブジェクトのスナップショッ
トを保存しています。iPhoneアプリケーションのメインnibファイルには、通常、ウインドウオブ
ジェクト、アプリケーションデリゲートオブジェクト、およびウインドウを管理するためのその他
の重要なオブジェクトがおそらく1つ以上含まれています。nibファイルをロードすると、そのnib
ファイル内のオブジェクトが再構成されます。つまり、各オブジェクトは、ディスク上の表現か
ら、アプリケーションによる操作が可能な実際のメモリ内バージョンに変換されます。nibファイル
からロードされたオブジェクトは、プログラムで作成したオブジェクトとまったく違いはありませ
ん。ただし、ユーザインターフェイスに関しては、(Interface Builderアプリケーションを使用して)
ユーザインターフェイスに関連付けられたオブジェクトをグラフィカルに作成して、それをnibファ
イルに保存する方が、プログラムでオブジェクトを作成するよりも通常は便利です。

nibファイルおよびiPhoneアプリケーションでのその使用の詳細については、「nibファイ
ル」 (29 ページ)を参照してください。アプリケーションのメインnibファイルを指定する方法の
詳細については、「情報プロパティリスト」 (26 ページ)を参照してください。

イベント処理サイクル
UIApplicationMain関数は、アプリケーションの初期化が終わると、アプリケーションのイベント
および描画サイクルを管理するために必要なインフラストラクチャを起動します。その様子を図 1-2
に示します。ユーザがデバイスとやり取りすると、iPhone OSはタッチイベントを検出し、それをア
プリケーションのイベントキューに配置します。UIApplicationオブジェクトのイベント処理イン
フラストラクチャは、このキューの先頭からイベントを取り出して、それを処理するのに最も適し
たオブジェクトに送付します。たとえば、ボタンで発生したタッチイベントは、それに対応するボ
タンオブジェクトに送付されます。イベントが、コントロールオブジェクトや、アプリケーション
内でタッチイベントの処理を間接的に担当するその他のオブジェクトに送付される場合もありま
す。

18 コアアプリケーションアーキテクチャ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

図 1-2 イベントと描画サイクル

Event queue Application

Application
object

Operating
system

Core objects

iPhone OSのMulti-Touchイベントモデルでは、タッチデータは1つのイベントオブジェクト(UIEvent)
にカプセル化されます。個々のタッチを追跡するために、このイベントオブジェクトには、画面に
タッチしている指ごとに1つずつ,タッチオブジェクト(UITouch)が含まれています。ユーザが画面
上に指を置いて移動してから、最後に画面から指を離すと、システムは、各指の変化をそれに対応
するタッチオブジェクト内で報告します。

システムは、アプリケーションを起動するときに、そのアプリケーション用に1つのプロセスと1つ
のスレッドの両方を作成します。最初のスレッドは、アプリケーションのメインスレッドになり、
そこに、UIApplicationオブジェクトがメイン実行ループをセットアップして、アプリケーション
のイベント処理コードを設定します。図 1-3は、イベント処理コードとメイン実行ループの関係を
表しています。システムによって送信されたタッチイベントは、アプリケーションのメイン実行
ループで処理できるようになるまで順番待ちをします。

図 1-3 メイン実行ループでのイベント処理

Main run loop

Event source
event
event Port System
event
event
event

コアアプリケーションアーキテクチャ 19
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

注: 実行ループは、与えられた実行スレッドに対する入力ソースを監視します。入力ソースに処
理すべきデータがあると、実行ループはそのスレッドをウェイクアップして、その入力ソース用の
ハンドラに制御を渡します。ハンドラが終了すると、実行ループに制御が戻ります。実行ループは
次のイベントを処理するか、これ以上何もすることがなければそのスレッドをスリープさせます。
FoundationフレームワークのNSRunLoopクラスを使用して、メインループにポートやタイマーなど
の独自の入力ソースをインストールすることもできます。NSRunLoopおよび実行ループの詳細につ
いては、『Threading Programming Guide』を参照してください。

UIApplicationオブジェクトは、1つの入力ソースを持つメイン実行ループを構成します。この実
行ループは、タッチイベントを適切なレスポンダオブジェクトに送付することによって、処理しま
す。レスポンダオブジェクトは、UIResponderクラスから派生したオブジェクトで、1つのタッチイ
ベントのさまざまなフェーズを処理するために、1つ以上のメソッドを実装しています。アプリケー
ション内のレスポンダオブジェクトには、UIApplication、UIWindow、UIView、およびすべての
UIViewサブクラスのインスタンスが含まれます。アプリケーションは、通常、アプリケーションの
メインウインドウを表すUIWindowオブジェクトにイベントを送付します。次に、このウインドウオ
ブジェクトは、そのイベントをファーストレスポンダに転送します。通常、ファーストレスポンダ
は、タッチが発生した場所のビューオブジェクト(UIView)です。

イベントを処理するために使用するメソッドを定義しているだけでなく、UIResponderクラスは、
レスポンダチェーンのプログラム構造も定義しています。レスポンダチェーンは、協調的なイベン
ト処理のためのCocoaメカニズムです。レスポンダチェーンは、1つのアプリケーション内のレスポ
ンダオブジェクトの連鎖で、通常は、ファーストレスポンダから始まります。ファーストレスポン
ダオブジェクトは、イベントを処理できない場合、そのイベントをチェーン内の次のレスポンダに
渡します。メッセージは、イベントが処理されるまで、ウインドウ、アプリケーション、アプリ
ケーションのデリゲートなど、上位レベルのレスポンダオブジェクトに向かってチェーン内で渡さ
れ続けます。イベントが処理されなかった場合、そのイベントは破棄されます。

イベントを処理するレスポンダオブジェクトは、一連のプログラムアクションを起動する役割をし
ます。その結果、アプリケーションは、ユーザインターフェイスの全体または一部を再描画します
(サウンドの再生など、その他の結果が生じる場合もあります)。たとえば、コントロールオブ
ジェクト(UIControlのサブクラス)は、別のオブジェクト(通常は、現在のアクティブビューセッ
トを管理するコントローラ)にアクションメッセージを送信することによってイベントを処理しま
す。アクションメッセージを処理している間に、コントローラは、ユーザインターフェイスを変更
したり、いくつかのビューを再描画するためにビューの位置を調整します。これが実行されると、
ビューおよびグラフィックスのインフラストラクチャは、それを引き継ぎ、必要な再描画イベント
を最も効率的な方法で処理します。

イベント、レスポンダ、およびカスタムオブジェクト内でイベントを処理する方法の詳細について
は、「イベント処理」 (79 ページ)を参照してください。ウインドウとビューが、どのようにし
てイベント処理スキームに適応するかの詳細については、「ビューの対話モデル」 (52 ページ)
を参照してください。グラフィックスのインフラストラクチャとビューの更新方法の詳細について
は、「ビューの描画サイクル」 (91 ページ)を参照してください。

基礎となるデザインパターン
UIKitフレームワークの設計には、Mac OS XのCocoaアプリケーションに見られるデザインパターンが
数多く組み込まれています。これらのデザインパターンを理解することは、iPhoneアプリケーショ
ンを作成するために非常に重要です。したがって、少し時間を取ってこれらについて学ぶだけの価
値はあります。以下に、これらのデザインパターンの概要を示します。

20 コアアプリケーションアーキテクチャ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

表 1-1 iPhoneアプリケーションで使われるデザインパターン

デザインパターン 説明

Model-View-Controller Model-View-Controller (MVC)デザインパターンは、コードを独立した機能


領域に分割する方法の1つです。Model部分は、アプリケーションのベース
となるデータエンジンを定義し、そのデータの完全性を維持する役割を果
たします。View部分は、アプリケーションのユーザインターフェイスを定
義し、そのインターフェイスに表示されるデータの出所についての明確な
知識を持っていません。Controller部分は、モデルとビューの橋渡しとして
の役割を果たし、これらの間の更新を容易にします。

デリゲーション デリゲーションデザインパターンは、複雑なオブジェクトをサブクラス化
せずに変更する方法の1つです。サブクラス化する代わりに、複雑なオブ
ジェクトをそのまま使用し、そのオブジェクトの動作を変更するためのカ
スタムコードを別のオブジェクト(これを、デリゲートオブジェクトと呼
ぶ)の内部に配置します。あらかじめ定義されたタイミングで、この複雑
なオブジェクトは、デリゲートオブジェクトのメソッドを呼び出して、カ
スタムコードを実行する機会を提供します。

ターゲット/アク コントロールは、ターゲット/アクションデザインパターンを使用して、
ション ユーザとの対話をアプリケーションに通知します。ユーザがあらかじ決め
られた方法で(ボタンをタップするなど)コントロールと対話すると、コ
ントロールは、指定されたオブジェクト(ターゲット)にメッセージを送
信(アクション)します。ターゲットオブジェクトは、アクションメッセー
ジを受信するとすぐに、適切な方法で応答します(ボタンの押下に反応し
てアプリケーションの状態を更新するなど)。

マネージドメモリモ Objective-C言語は、オブジェクトをメモリから解放するタイミングを決定
デル するために、参照カウントの仕組みを使用します。オブジェクトが初めて
作成されたときに、そのオブジェクトには参照カウント1が与えられます。
ほかのオブジェクトは、そのオブジェクトのretain、release、または
autoreleaseの各メソッドを使用して、参照カウントを適切に増減させま
す。オブジェクトの参照カウントが0になると、Objective-Cランタイムはオ
ブジェクトのクリーンアップルーチンを呼び出し、次にメモリ割り当てを
解除します。

これらのデザインパターンの詳細については、『Cocoa Fundamentals Guide』を参照してください。

アプリケーションのランタイム環境

iPhone OSのランタイム環境は、プログラムを高速かつ安全に実行できるように設計されています。
以降の各セクションでは、ランタイム環境の主要な側面について説明し、その環境の中で最善の動
作をさせるためのガイダンスを示します。

アプリケーションのランタイム環境 21
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

すばやい起動、短時間の使用
iPhone OSベースのデバイスの強みは、即時性です。一般的なユーザは、ポケットや鞄からデバイス
を取り出して数秒間(または数分間)使用したら、再びそれをしまいます。その間にユーザは、電
話を受けたり、連絡先を検索したり、現在聴いている曲を変えたり、いくつかの情報を取得したり
します。

iPhone OSでは、一度に実行するフォアグラウンドアプリケーションは1つだけです。つまり、ユー
ザがホーム(Home)画面上でアプリケーションのアイコンをタップするたびに、アプリケーションが
起動し、遅延が最小になるようにすばやく初期化されなければなりません。アプリケーションの起
動に長時間かかると、ユーザはそのアプリケーションを使う気がなくなってしまうかもしれませ
ん。

アプリケーションは、起動がすばやくできるだけでなく、終了もすばやくできるようにしておかな
ければなりません。ユーザが、ホーム(Home)ボタンを押すか、または別のアプリケーションのコン
テンツを開く機能を使用してアプリケーションのコンテキストを離れる場合は、iPhone OSがアプリ
ケーションに終了を通知します。その時点で、未保存の変更をディスクに保存し、できるだけすば
やく終了する必要があります。アプリケーションの終了に5秒以上かかると、システムが即座にア
プリケーションを強制終了します。

ユーザが別のアプリケーションに切り替えたときに、アプリケーションがバックグラウンドで実行
されていないにもかかわらず、あたかも実行されているかのように見せることが奨励されます。ア
プリケーションが終了した場合は、未保存のデータだけでなく、アプリケーションの現在の状態に
関する情報も保存する必要があります。起動時には、この状態情報を検索し、それを使用してアプ
リケーションを最後に使用したときの状態に復元する必要があります。これによって、ユーザがそ
のアプリケーションを最後に使用したときの状態にすぐに戻ることができるので、より一貫性のあ
るユーザ体験を提供できます。このようにユーザの場所を保存することによって、アプリケーショ
ンを起動するたびに、複数の画面に相当する情報を通過して元の場所に戻る必要がなくなるので、
時間の節約にもなります。

アプリケーションサンドボックス
セキュリティ上の理由から、iPhone OSは、アプリケーション(アプリケーションの環境設定とデー
タも含む)をファイルシステム内の一意の場所に配置するよう制限しています。この制限は、アプ
リケーションの「サンドボックス」と呼ばれるセキュリティ機能の一部です。サンドボックスと
は、ファイル、環境設定、ネットワークリソース、ハードウェアなどに対するアプリケーションの
アクセスをきめ細かく制限する一連のコントロールです。iPhone OSでは、アプリケーションとその
データは、ほかのアプリケーションからはアクセスできないセキュアな場所に置かれています。ア
プリケーションがインストールされると、そのアプリケーションを表す、一意で不透過な識別子を
システムが算出します。システムは、ルートアプリケーションディレクトリとこの識別子を使用し
て、アプリケーションのホームディレクトリのパスを作成します。このため、アプリケーションの
ホームディレクトリは次の構造を持つものとして表せます。

/ ApplicationRoot / ApplicationID /

インストール処理中に、システムはアプリケーションのホームディレクトリといくつかの重要なサ
ブディレクトリを作成し、アプリケーションのサンドボックスを設定します。そして、そのホーム
ディレクトリにアプリケーションバンドルをコピーします。アプリケーションとそのデータごとに
一意の場所を使用することで、バックアップと復元の操作やアンインストールが簡単になります。
アプリケーションごとに作成されるアプリケーション固有のディレクトリの詳細については、「よ
く使われるディレクトリ」 (123 ページ)を参照してください。

22 アプリケーションのランタイム環境
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

重要: サンドボックスによって、攻撃者がほかのアプリケーションやシステムに与える被害を抑
えることができます。ただし、サンドボックスでは、攻撃そのものを防止することはできません。
つまり、サンドボックスは、悪意のある者による直接攻撃からアプリケーションを保護するもので
はありません。たとえば、入力処理コードの中に悪用可能なバッファオーバーフローが存在して
ユーザ入力の検証ができない場合、攻撃者は、プログラムをクラッシュさせたり、それを利用して
攻撃者のコードを実行できる可能性があります。

仮想メモリシステム
プログラムのメモリを管理するために、iPhone OSではMac OS Xと本質的に同じ仮想メモリシステム
を使用します。iPhone OSでは、プログラムごとに固有の仮想アドレス空間を持ちますが、(Mac OS
Xとは違って)使用可能な仮想メモリは、使用可能な物理メモリの量によって制限されます。これ
は、iPhone OSがメモリを使い切ると揮発性のページをディスクに書き込まないからです。その代わ
りに、仮想メモリシステムは、必要に応じて不揮発性メモリを解放してアプリケーションの実行に
必要なメモリ容量を確保します。そのために、現在使われていないメモリページや、コードページ
などの読み取り専用コンテンツを含むメモリページを削除します。このようなページは、後で再び
必要なときにいつでもメモリにロードしなおせます。

メモリ不足の状態が続くと、システムは実行中のアプリケーションに通知を送って、メモリをさら
に解放するように依頼します。すべてのアプリケーションは、この通知に対応して、メモリ不足を
解消するためにそれぞれの責務を果たさなければなりません。アプリケーションでこのような通知
を処理する方法については、「メモリ不足警告を監視する」 (33 ページ)を参照してください。

自動スリープタイマー
iPhone OSが消費電力を節約する方法の1つに、自動スリープタイマーがあります。システムは、長
時間タッチイベントを検出しないと、まず画面を暗くし、やがては電源を完全にオフにします。ほ
とんどのデベロッパは、このタイマーをオンのままにしておくべきです。ただし、ゲームのデベ
ロッパや、タッチ入力を使用しないアプリケーションのデベロッパは、このタイマーを無効にし
て、アプリケーションの実行中は画面が暗くならないようにできます。このタイマーを無効にする
には、共有のUIApplicationオブジェクトのidleTimerDisabledプロパティをYESに設定します。

その結果、電力消費が増加するので、スリープタイマーを無効にするのは極力避けるべきです。ス
リープタイマーの使用を検討しなければならないのは、マッピングアプリケーション、ゲーム、お
よびタッチ入力に依存せずにデバイスの画面にビジュアルコンテンツを表示する必要があるアプリ
ケーションだけです。オーディオアプリケーションでは、このタイマーを無効にする必要はありま
せん。オーディオコンテンツは、画面が暗くなった後も再生され続けます。このタイマーを本当に
無効にする場合は、できるだけ早く有効に戻して、システムが電力消費を抑えられるようにしてく
ださい。アプリケーションで電力を節約する方法の詳細については、「電力消費を抑える」 (44 ペー
ジ)を参照してください。

アプリケーションバンドル

iPhoneアプリケーションをビルドすると、Xcodeはアプリケーションをバンドルとしてパッケージ化
します。バンドルとは、関連のあるリソースを1つの場所に集めた、ファイルシステム上のディレ
クトリです。iPhoneアプリケーションバンドルには、アプリケーションの実行可能ファイル、およ
びアプリケーションが使用するリソース(たとえば、アプリケーションアイコン、その他の画像、

アプリケーションバンドル 23
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

ローカライズされたコンテンツ)が格納されています。表 1-2に、標準的なiPhoneアプリケーション
バンドルの内容を示します。この例では、MyAppという名前のアプリケーションの場合を示します
が、説明のみを目的としたものです。この表に示すファイルの一部は、実際のアプリケーションバ
ンドルには含まれない場合があります。

表 1-2 標準的なアプリケーションバンドル

ファイル 説明

MyApp アプリケーションのコードが格納された実行可能ファイル。このファイル
の名前は、アプリケーションの名前から.app拡張子を取り除いたものです。
このファイルは必須です。

Settings.bundle Settingsバンドルは、アプリケーションの環境設定を「設定(Settings)」アプ
リケーションに追加するために使用するファイルパッケージです。このバ
ンドルには、プロパティリスト、および環境設定を構成、表示するその他
のリソースファイルが格納されます。詳細については、「アプリケーショ
ン環境設定の表示」 (39 ページ)を参照してください。

Icon.png デバイスのホーム(Home)画面でアプリケーションを示すために使用される、
57×57ピクセルのアイコン。このアイコンに、光沢のエフェクトを含めては
なりません。光沢のエフェクトはシステムが自動的に付加します。このファ
イルは必須です。この画像ファイルの詳細については「アプリケーション
アイコンと起動画像」 (29 ページ)を参照してください。

Icon-Settings.png 「設定(Settings)」アプリケーション内でアプリケーションを示すために使
用される、29×29ピクセルのアイコン。アプリケーションにSettingsバンド
ルが含まれる場合、このアイコンは「設定(Settings)」アプリケーションで
はアプリケーション名の横に表示されます。このアイコンファイルを指定
しない場合は、Icon.pngファイルが拡大縮小されて代わりに使用されま
す。この画像ファイルの詳細については、「アプリケーション環境設定の
表示」 (39 ページ)を参照してください。

MainWindow.nib アプリケーション起動時にロードされるデフォルトのインターフェイスオ
ブジェクトが格納されているアプリケーションのメインnibファイル。通
常、このnibファイルにはアプリケーションのメインウインドウオブジェク
トと、アプリケーションデリゲートオブジェクトのインスタンスが格納さ
れます。その他のインターフェイスオブジェクトは、追加のnibファイルか
らロードされるか、プログラミングによってアプリケーションが作成しま
す(メインnibファイルの名前は、Info.plistファイルのNSMainNibFile
キーに別の値を割り当てることにより変更できます。詳細については、「情
報プロパティリスト」 (26 ページ)を参照してください)。

Default.png アプリケーション起動時に表示される、480×320ピクセルの画像。システム
は、アプリケーションがウインドウとユーザインターフェイスをロードす
るまでの間、このファイルを一時的な背景として使用します。この画像ファ
イルの詳細については「アプリケーションアイコンと起動画像」 (29 ペー
ジ)を参照してください。

24 アプリケーションバンドル
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

ファイル 説明

iTunesArtwork この512×512のアプリケーション用アイコンは、アドホック配布を使用して
配布されます。このアイコンは、通常App Storeによって提供されます。た
だしアドホック形式で配布されるアプリケーションはApp Storeを経由しな
いため、アプリケーションバンドルで提供する必要があります。iTunesは、
このアイコンを使用してアプリケーションを表示します(このプロパティ
に指定したファイルは、App Storeに投稿したものと同じでなければなりま
せん(通常は、JPEGまたはPNGファイル)。また、そのようにしてアプリ
ケーションを配布するのはデベロッパの責任です。ファイル名は、左側に
表示されるものだけにし、ファイル名の拡張子を含めてはいけません)。

Info.plist このファイルは、バンドルID、バージョン番号、表示名など、アプリケー
ションの主要な値を定義するプロパティリストで、情報プロパティリスト
とも呼ばれます。詳細については、「情報プロパティリスト」 (26 ペー
ジ)を参照してください。このファイルは必須です。

sun.png(またはそ 非ローカライズリソースは、バンドルディレクトリの最上位に置かれます
の他のリソースファ (sun.pngは、この例における非ローカライズ画像ファイルを表します)。
イル) アプリケーションは、ユーザが選択した言語設定に関係なく、非ローカラ
イズリソースを使用します。

en.lproj ローカライズされたリソースは、ISO 639-1で規定された言語略称に.lproj


fr.lproj という接尾辞を加えた名前のサブディレクトリに置かれます(たとえば、
en.lprojディレクトリ、fr.lprojディレクトリ、es.lprojディレクトリ
es.lproj にはそれぞれ、英語、フランス語、スペイン語のローカライズされたリソー
その他の言語固有の スが格納されます)。詳細については、「アプリケーションの国際
プロジェクトディレ 化」 (40 ページ)を参照してください。
クトリ

iPhoneアプリケーションは、国際化されている必要があり、サポート対象の言語ごとにlanguage
.lprojフォルダを持っています。アプリケーションのカスタムリソースのローカライズバージョン
を提供するだけでなく、アプリケーションアイコン(Icon.png)、デフォルト画像(Default.png)、設
定アイコン(Icon-Settings.png)も、そのファイルを言語固有のプロジェクトディレクトリに配置
することによってローカライズできます。ただし、ローカライズバージョンを提供した場合でも、
これらのファイルのデフォルトバージョンは、常にアプリケーションバンドルの最上位レベルに含
まれます。デフォルトバージョンは、特定のローカライズが利用できない場合に使用されます。

NSBundleクラスのメソッド、またはCFBundleRef不透過型の関数を使用して、アプリケーションバ
ンドルに格納されている、画像とサウンドの、ローカライズされたリソースと非ローカライズリ
ソースへのパスを取得します。たとえば、画像ファイルsun.png(「割り込みへの応答」 (31 ペー
ジ)を参照)へのパスを取得し、それをもとに画像ファイルを作成するには、次に示す2行の
Objective-Cコードが必要です。

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"sun"


ofType:@"png"];
UIImage* sunImage = [[UIImage alloc] initWithContentsOfFile:imagePath];

mainBundleクラスメソッドを呼び出すと、アプリケーションバンドルを表すオブジェクトが返され
ます。リソースのロードの詳細については『Resource Programming Guide』を参照してください。

アプリケーションバンドル 25
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

情報プロパティリスト
情報プロパティリストは、Info.plistという名前がつけられたファイルで、Xcodeで作成するすべ
てのiPhoneアプリケーションプロジェクトに含まれます。このファイルは、キー値のペアによって、
アプリケーションの重要なランタイム設定情報を指定するプロパティの一覧です。情報プロパティ
リストの要素は階層構造になっており、階層内の各ノードは、配列、辞書、文字列、その他のスカ
ラー型などのエンティティです。

Xcodeでは、「プロジェクト(Project)」メニューの「アクティブターゲットTargetNameを編集(Edit
Active Target TargetName)」を選択することで、情報プロパティリストにアクセスできます。次にター
ゲットの情報ウインドウで、「プロパティ(Properties)」コントロールをクリックします。Xcodeに、
図 1-4の例に示すような情報が含まれるペインが表示されます。

図 1-4 ターゲットの情報ウインドウの「プロパティ(Properties)」ペイン

「プロパティ(Properties)」ペインには、アプリケーションバンドルのプロパティの一部が表示され
ます。「ファイルとして開く(Open Info.plist as File)」ボタンをクリックするか、またはXcodeプロジェ
クト内でInfo.plistファイルを選択すると、Xcodeにより、図 1-5に示すような、プロパティリス
トの編集用ウインドウが表示されます。このウインドウを使用して、プロパティの値を編集した
り、新規のキー値ペアを追加したりできます。

26 アプリケーションバンドル
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

図 1-5 情報プロパティリストエディタ

これらのプロパティの中には、Xcodeによって自動的に値が設定されるものもありますが、明示的
に設定する必要があるものもあります。表 1-3に、アプリケーションのInfo.plistファイルで指定
することが推奨される重要なキーの一部を示します。このファイルで指定できるプロパティの網羅
的なリストについては、『Runtime Configuration Guidelines』を参照してください。

表 1-3 Info.plistファイルの重要なキー

キー 値

CFBundleDisplayName アプリケーションアイコンの下に表示する名前。この値は、サポートす
るすべての言語についてローカライズしてください。

CFBundleIdentifier バンドルのアプリケーションタイプを指定する、識別子文字列。この文
字列は、UTI (Uniform Type Identifier)です。たとえば、会社名がAjaxで、
アプリケーションの名前がHelloの場合、バンドル識別子は
com.Ajax.Helloとなります。
バンドル識別子は、アプリケーションの署名の検証に使用します。

CFBundleURLTypes アプリケーションが処理可能な、URLタイプの配列。URLタイプはそれ
ぞれ、アプリケーションが処理可能なスキーム(例:http、mailto)
を定義する辞書となっています。このプロパティを使用することによ
り、アプリケーションは独自のURLスキームを登録できます。

アプリケーションバンドル 27
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

キー 値

CFBundleVersion バンドルのビルドバージョン番号を指定する文字列。この値は、単純増
加していく値を示す文字列で、ピリオドで区切られた1個以上の整数で
構成されます。この値はローカライズできません。

LSRequiresIPhoneOS バンドルがiPhone OSでのみ実行可能かどうかを示すブール値。Xcodeは


このキーを自動的に追加し、値をtrueに設定します。このキーの値は変
更してはいけません。

NSMainNibFile アプリケーションのメインnibファイルの名前を示す文字列。プロジェ
クトのために作成されたデフォルトのもの以外のnibファイルを使用す
る場合は、そのnibファイルの名前をこのキーに関連付けます。nibファ
イルの名前にはファイル名拡張子の.nibを含めないようにします。

UIStatusBarStyle アプリケーション起動時のステータスバーのスタイルを示す文字列。こ
の値は、UIApplication.hヘッダファイルで宣言されている、
UIStatusBarStyle定数に基づいています。デフォルトのスタイルは
UIBarStyleDefaultです。アプリケーションは、起動処理が完了した
ときに、この初期のステータスバーのスタイルを変更できます。

UIStatusBarHidden アプリケーション起動時に、ステータスバーの初期状態を、表示または
非表示のどちらにするかを指定するブール値。ステータスバーを非表示
にするにはこれをtrueに設定します。デフォルト値はfalseです。

UIInterface- アプリケーションのユーザインターフェイスの最初の向きを示す文字
Orientation 列。この値は、UIApplication.hヘッダファイルに宣言されている、
UIInterfaceOrientation定数に基づいています。デフォルトのスタイ
ルはUIInterfaceOrientationPortraitです。
横長モードでのアプリケーションの起動の詳細については、「横長モー
ドでの起動」 (34 ページ)を参照してください。

UIPrerenderedIcon アプリケーションアイコンにすでに光沢やベベルエフェクトが含まれて
いるかを示すブール値。デフォルトのプロパティはfalseです。システム
でこれらのエフェクトをアートワークに追加しない場合は、値をtrueに
設定します。

UIRequiresPersistent- アプリケーションが通信にWi-Fiネットワークを使用していることをシ
WiFi ステムに通知するブール値。一定の時間Wi-Fiを使用するアプリケーショ
ンは、このキーをtrueに設定する必要があります。そうしないと、デバ
イスは30分経過すると、節電のためWi-Fi接続を停止します。このフラ
グを設定することで、現在Wi-Fiを利用していなくても利用可能であれ
ば、ネットワーク選択のダイアログを表示する必要があることもシステ
ムに知らせます。デフォルト値はfalseです。

ユーザインターフェイスに表示する文字列を指定するプロパティはローカライズしてください。特
に、Info.plistの文字列は、ローカライズする言語のサブディレクトリにあるInfoPlist.strings
ファイル内のローカライズされた文字列を指すキーとなります。詳細については、「アプリケー
ションの国際化」 (40 ページ)を参照してください。

28 アプリケーションバンドル
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

アプリケーションアイコンと起動画像
ユーザのホーム(Home)画面に表示されるアイコンのファイルには、Icon.pngというデフォルトの名
前が付いています(Info.plistファイルのCFBundleIconFileプロパティで名前を変更できます)。
このファイルは、PNG形式の画像ファイルで、アプリケーションバンドルの最上位に置きます。ア
プリケーションアイコンは、光沢やラウンドベベルのエフェクトが適用されていない、57×57ピク
セルの画像です。通常、システムはこれらのエフェクトを、表示前にアイコンに適用します。ただ
し、アプリケーションのInfo.plistファイルにUIPrerenderedIconキーを含めることによって、
この動作をオーバーライドすることができます。詳細については、表 1-3 (27 ページ)を参照して
ください。

注: (App Store経由ではなく)アドホック配布を使用してローカルユーザにアプリケーションを
配布する場合は、アプリケーションバンドルのiTunesArtworkと呼ばれるファイルに、512×512ピ
クセルバージョンのアプリケーションアイコンも含める必要があります。このファイルは、アプリ
ケーションを配布するときにiTunesによって表示されるアイコンを提供します。

アプリケーションの起動画像に使用するファイルにはDefault.pngという名前を付けます。この画
像は、アプリケーションの最初のユーザインターフェイスによく似た画像にする必要があります。
システムは、アプリケーションがユーザインターフェイスを表示する準備ができるまで起動画像を
表示することで、アプリケーションがすばやく起動された印象をユーザに与えます。起動画像も、
PNG形式の画像ファイルとして、アプリケーションバンドルの最上位に置きます。アプリケーショ
ンがURLを使用して起動された場合、システムはDefault- scheme .pngという名前の起動画像を検
索します(schemeはURLのスキームです)。このファイルが存在しない場合、Default.pngが代わ
りに選択されます。

Xcodeのプロジェクトに画像ファイルを追加するには、「プロジェクト(Project)」メニューの「プロ
ジェクトに追加(Add to Project)」を選択し、ブラウザでファイルを指定して、「追加(Add)」をクリッ
クします。

注: アプリケーションバンドルの最上位レベルにあるアイコンと起動画像のほかに、これらの画
像のローカライズバージョンをアプリケーションの言語固有のプロジェクトサブディレクトリに置
くこともできます。アプリケーションでのリソースのローカライズについては、「アプリケーショ
ンの国際化」 (40 ページ)を参照してください。

nibファイル
nibファイルは、アプリケーションで後から使用する予定のオブジェクトを「フリーズドライ」にし
たものを格納しておくデータファイルです。アプリケーションは、ユーザインターフェイスを構成
するウインドウやビューを保存するために、nibファイルを最もよく使用します。nibファイルをア
プリケーションにロードすると、nibロード用のコードによって、その内容がアプリケーションで操
作可能な実際のオブジェクトに展開されます。このため、nibファイルを利用すると、コードを記述
してプログラムによってオブジェクトを作成する必要がなくなります。

Interface Builderは、nibファイルを作成するために使用するビジュアル設計環境です。標準オブジェ
クト(UIKitフレームワークで提供されるウインドウやビューなど)とXcodeプロジェクトからのカ
スタムオブジェクトを組み合わせて、nibファイルを組み立てます。Interface Builder内でビュー階層
を作成するには、決まった場所にビューをドラッグアンドドロップするだけです。また、インスペ

アプリケーションバンドル 29
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

クタウインドウを使用して各オブジェクトの属性を設定したり、オブジェクトの実行時の関係を定
義するために、オブジェクト間に接続を作成することもできます。ここで行ったすべての変更は、
その後、nibファイルの一部として保存されます。

実行時に、nibファイルに含まれているオブジェクトが必要になったときは、そのnibファイルをア
プリケーションにロードします。通常、nibファイルをロードするのは、ユーザインターフェイスが
変更されたときや、画面上に新しいビューを表示する必要があるときです。アプリケーションがView
Controllerを使用する場合は、View Controllerが自動的にnibロードプロセスを処理します。ただし、
NSBundleクラスのメソッドを使用してnibファイルをデベロッパが自分でロードすることもできま
す。

アプリケーションのユーザインターフェイスの設計方法については、『iPhone Human Interface


Guidelines』を参照してください。nibファイルの作成方法については、『InterfaceBuilderUserGuide』
を参照してください。

重要なアプリケーションタスクの処理

このセクションでは、すべてのiPhoneアプリケーションが実行しなければならない、いくつかのタ
スクについて説明します。これらのタスクは、アプリケーションのライフサイクル全体の不可欠な
要素であり、iPhone OSとアプリケーションを統合する重要な方法の一部です。最悪の場合、これら
のタスクのいくつかの処理に失敗すると、オペレーティングシステムによってアプリケーションが
強制終了させられることもあります。

初期化と終了
初期化と終了の間、UIApplicationクラスは、アプリケーションデリゲートが必要なタスクを実行
できるように、適切なメッセージを送ります。アプリケーションは、これらのメッセージに応答す
る必要はありませんが、ほとんどすべてのiPhoneアプリケーションがこれらのメッセージを処理す
る必要があります。初期化時は、アプリケーションのユーザインターフェイスを準備し、アプリ
ケーションを初期実行状態にする期間です。同様に、終了時は、未保存のデータと主要なアプリ
ケーション状態をディスクに書き込む期間です。

iPhoneアプリケーションは、ほかのアプリケーションが起動される前に終了しなければならないの
で、初期化と終了のコードを実行するのにかかる時間はできる限り短くする必要があります。初期
化時は、すぐには使用しない大きなデータ構造のロードを始めるときではありません。起動時の目
標は、アプリケーションのユーザインターフェイスをできるだけすばやく、できればそのアプリ
ケーションを前回終了したときと同じ状態にして表示することです。アプリケーションが起動時に
ネットワークからデータをロードしたり、時間のかかるその他のタスクを実行するためにさらに時
間が必要な場合は、まずインターフェイスを立ち上げて実行させた後で、バックグラウンドスレッ
ドで時間のかかるタスクを起動します。それには、進捗インジケータやその他のフィードバックを
ユーザに表示して、アプリケーションが必要なデータをロード中であることや、重要な処理を実行
中であることを示す必要があります。

表 1-4は、初期化と終了のタスクを処理するためにアプリケーションデリゲートに実装する、
UIApplicationDelegateプロトコルのメソッドの一覧を示しています。この表には、各メソッド内
で実行しなければならない重要な処理も列挙されています。

30 重要なアプリケーションタスクの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

表 1-4 アプリケーションデリゲートの責務

デリゲートメソッド 説明

applicationDidFinish- このメソッドは、アプリケーションを前回のセッション中の状態に復
Launching: 元するために使用します。また、このメソッドは、アプリケーション
のデータ構造やユーザインターフェイスを独自に初期化するためにも
使用できます。

applicationWill- このメソッドは、未保存のデータや主要なアプリケーション状態をディ
Terminate: スクに保存するために使用します。一時ファイルの削除などの追加の
クリーンアップ操作を実行するために、このメソッドを使用すること
もできます。

割り込みへの応答
アプリケーションを終了するホーム(Home)ボタンのほかに、ユーザが重要なイベントに応答できる
ように、システムは、アプリケーションに一時的に割り込みをかけることができます。たとえば、
アプリケーションは電話の着信、SMSメッセージ、カレンダー通知、またはユーザがデバイス上の
スリープ(Sleep)ボタンを押す操作によって中断される可能性があります。ホーム(Home)ボタンを押
すとアプリケーションが終了しますが、このような割り込みが一時的なだけの場合もあります。
ユーザが割り込みを無視した場合、アプリケーションは今までどおり実行し続けます。しかし、
ユーザが電話を受けたり、SMSメッセージに応答すると、システムは実行中のアプリケーションを
終了させます。

図 1-6は、電話の着信、SMSメッセージ、またはカレンダー通知を受けている間に発生するイベント
のシーケンスを示しています。このすぐ後に示す手順で、このシーケンスのキーポイントを詳しく
説明します。また、アプリケーションが、各イベントに応答して実行しなければならない処理につ
いても説明します。このシーケンスには、ユーザがスリープ/スリープ解除(Sleep/Wake)ボタンを押
したときの反応は反映されていません。この場合のシーケンスについては、手順の後で説明しま
す。

重要なアプリケーションタスクの処理 31
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

図 1-6 割り込みの間のイベントの流れ

UIKit Your code

App launch

Event
Loop

A phone, SMS or Calendar


applicationWillResignActive:
notification arrives

Yes
Ignore? applicationDidBecomeActive:

No

Begin termination sequence applicationWillTerminate:

Application terminates

1. システムは、電話の着信、SMSメッセージ、またはカレンダーイベントが発生したことを検出
します。

2. システムがアプリケーションデリゲートのapplicationWillResignActive:メソッドを呼び出
します。システムは、アプリケーションに対するタッチイベントの送信も無効にします。

割り込みによって、アプリケーションによる制御が一時的に失われます。制御が失われること
によって、アプリケーションの動作に影響したり、ユーザ体験に悪影響が生じる可能性がある
場合は、それを避けるために、デリゲートメソッド内で適切な手順を実行する必要があります。
たとえば、ゲームアプリケーションの場合は、ゲームを一時停止する必要があります。また、
タイマーを無効にし、(OpenGLを使っている場合は)OpenGLフレームレートを落として、ア
プリケーションを全体としてスリープ状態にすることもできます。休止状態の間、アプリケー
ションは実行されていますが、何も重要な仕事はしません。

3. システムが、イベントに関する情報を警告パネルに表示します。ユーザはイベントを無視する
か、イベントに応答するかを選択できます。

4. ユーザがイベントを無視すると、システムはアプリケーションデリゲートの
applicationDidBecomeActive:メソッドを呼び出し、アプリケーションへのタッチイベントの
配信を再開します。

32 重要なアプリケーションタスクの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

このデリゲートメソッドを使用して、タイマーを再度有効にし、OpenGLフレームレートを上げ
て、アプリケーションをスリープ状態から戻すことができます。停止状態のゲームの場合は、
ユーザがゲームを再開するまでは、ゲームを停止状態のままにしておくことを考慮する必要が
あります。たとえば、プレイを再開するためのコントロールが付いた警告パネルを表示するこ
ともできます。

5. ユーザが、イベントを無視せずにイベントに応答すると、システムはアプリケーションデリゲー
トのapplicationWillTerminate:メソッドを呼び出します。アプリケーションは、次回起動時
にアプリケーションの同じ場所にユーザを戻せるように、必要な文脈情報をすべて保存して通
常どおりに終了します。

アプリケーションが終了した後は、システムは、割り込みの処理を担当するアプリケーション
を起動します。

割り込みに応答している間のユーザの操作によっては、システムは、割り込みが終了するとアプリ
ケーションを再び起動します。たとえば、ユーザが電話の着信を受けた後、電話を切ると、システ
ムはアプリケーションを再び起動します。通話の間に、ユーザがホーム(Home)画面に戻るか別のア
プリケーションを起動した場合、システムは着信時に起動していたアプリケーションを再び起動し
ません。

重要: ユーザが電話を受けてから、通話中にアプリケーションを起動しなおすと、ユーザが通話
中であることを示すためにステータスバーの高さが高くなります。同様に、ユーザが通話を終了す
ると、ステータスバーの高さは標準のサイズに縮小します。アプリケーションは、ステータスバー
のこうした変化に備え、コンテンツ領域を適宜調整する必要があります。View Controllerは、この動
作を自動的に処理します。ただし、ユーザインターフェイスをプログラミングによってレイアウト
する場合、ビューをレイアウトする際にステータスバーの高さを考慮し、layoutSubviewsメソッ
ドを実装してレイアウトの動的な変化に対応する必要があります。

アプリケーションの実行中にユーザがデバイスのスリープ/スリープ解除(Sleep/Wake)ボタンを押し
た場合は、システムはアプリケーションデリゲートのapplicationWillResignActive:メソッドを
呼び出し、タッチイベントの配信を停止してデバイスをスリープ状態にします。その後、ユーザが
デバイスのスリープ状態を解除すると、システムは、アプリケーションデリゲートの
applicationDidBecomeActive:メソッドを呼び出して、アプリケーションへのイベントの配信を
再開します。その他の割り込みを処理するときは、これらのメソッドを使用して、アプリケーショ
ンをスリープ状態にして(または、ゲームを中止して)から再度スリープを解除します。スリープ
状態の間は、アプリケーションの消費電力をできるだけ少なくする必要があります。

メモリ不足警告を監視する
システムがメモリ不足の通知をアプリケーションに送ってきた場合は、その警告に注意を払う必要
があります。空きメモリの容量が安全しきい値を下回ると、iPhone OSは最前面のアプリケーション
に通知をします。アプリケーションがこの通知を受け取った場合は、不要になったオブジェクトを
解放したり、後から簡単に作成しなおせるメモリキャッシュを空にするなどして、できる限り多く
のメモリを解放する必要があります。

UIKitでは、メモリ不足の通知を受け取るための方法をいくつか提供しています。以下の方法が含ま
れます。

■ アプリケーションデリゲートのapplicationDidReceiveMemoryWarning:メソッドを実装する。

重要なアプリケーションタスクの処理 33
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

■ UIViewControllerのカスタムサブクラスで、didReceiveMemoryWarningメソッドをオーバー
ライドする。
■ UIApplicationDidReceiveMemoryWarningNotification通知を受け取るように登録する。

このような通知を受け取ったら、ハンドラメソッドではただちに不要なメモリを解放して対応する
必要があります。View Controllerでは、現在オフスクリーンのビューをすべて消去します。また、ア
プリケーションデリゲートでは、解放できるデータ構造をすべて解放したり、ほかのアプリケー
ションオブジェクトにメモリを解放するように通知します。

カスタムオブジェクトが既知の消去可能なリソースを持つ場合は、これらのオブジェクトが
UIApplicationDidReceiveMemoryWarningNotification通知を受け取れるように登録して、消去
可能なリソースを直接解放させることもできます。消去可能なリソースのほとんどを管理するオブ
ジェクトが少数で、これらのすべてのリソースを消去するのが適切な場合は、これらのオブジェク
トを登録します。ただし、消去可能なオブジェクトがたくさんある場合や、これらのオブジェクト
のサブセットだけを解放するように調整したい場合は、アプリケーションデリゲートを使用して希
望のオブジェクトを解放します。

重要: テスト中にメモリ不足の警告を受けなかったとしても、システムアプリケーションと同様
にアプリケーションでは常にメモリ不足の警告に対応する必要があります。システムアプリケー
ションでは、さまざまな要求を処理する間、少量のメモリを消費します。メモリ不足の状態が検出
されると、システムはメモリ不足を緩和するために(読者の作ったアプリケーションを含め)実行
中のすべてのプログラムにメモリ不足の警告を送ります。また、いくつかのバックグラウンドアプ
リケーションを終了させる場合があります。アプリケーションにメモリリークがあったり、アプリ
ケーションが依然として大量のメモリを消費しつづけているなどの理由で、十分なメモリが解放さ
れなかった場合、システムによってアプリケーションが強制終了される場合があります。

アプリケーションの動作のカスタマイズ

基本的なアプリケーションの動作をカスタマイズして、希望通りのユーザ体験を提供するには、さ
まざまな方法があります。以降のセクションでは、アプリケーションレベルで行う必要があるカス
タマイズについて説明します。

横長モードでの起動
iPhone OSのアプリケーションは、通常、ホーム(Home)画面の向きに合わせるために縦長モードで起
動します。縦長と横長の両方のモードで実行されるアプリケーションの場合、最初は常に縦長モー
ドで起動し、その後で、View Controllerによってデバイスの向きに基き、必要に応じてインターフェ
イスを回転します。ただし、アプリケーションを横長モードでのみ実行する場合は、最初から横長
モードで起動するために次の手順を実行する必要があります。

■ アプリケーションのInfo.plistファイルに、UIInterfaceOrientationキーを追加し、その値
を横長モードに設定する。このキーの値は、UIInterfaceOrientationLandscapeLeftまたは
UIInterfaceOrientationLandscapeRightに設定できます。

■ ビューを横長モードにレイアウトし、ビューの自動サイズ変更オプションを確実に正しく設定
する。

34 アプリケーションの動作のカスタマイズ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

■ View ControllerのshouldAutorotateToInterfaceOrientation:メソッドをオーバーライドし
て、希望する横長の向きの場合にのみYESを返し、縦長の向きの場合はNOを返す。

重要: 前述の手順は、アプリケーションが、ビュー階層を管理するためにView Controllerを使用し


ていることを前提としています。View Controllerは、その他の複雑なビュー関連イベントだけでな
く、向きの変化を処理するために相当な量のインフラストラクチャを提供しています。アプリケー
ションでView Controllerを使用していない場合は(ゲームや、OpenGL ESベースのその他のアプリケー
ション)、横長モードでコンテンツを表示するために、必要に応じて描画サーフェイスを回転する
のはデベロッパの責任になります。

UIInterfaceOrientationキーは、アプリケーションのステータスバー(ステータスバーが表示さ
れている場合)と任意のView Controllerのビューの方向を起動時に設定するためのヒントをiPhone
OSに与えます。iPhone OS 2.1以降では、View Controllerがこのキーを尊重して、それに合わせてビュー
の向きの初期値を設定します。このキーを使用することは、UIApplicationの
setStatusBarOrientation:animated:メソッドを、applicationDidFinishLaunching:メソッド
の実行の初期に呼び出すことと同等です。

注: iPhone OS v2.1より前のバージョンで、View Controllerベースのアプリケーションを横長モード


で起動するには、前述のすべての手順に加えて、アプリケーションのルートビューの変換に90度の
回転を適用する必要があります。iPhone OS 2.1より前のバージョンでは、View Controllerは、
UIInterfaceOrientationキーの値に基づいて自動的にビューを回転しません。ただし、iPhone OS
2.1以降では、この手順は不要です。

他のアプリケーションとのやり取り
アプリケーションが既知の型のURLを扱う場合は、そのURLスキームを使用してそのアプリケーショ
ンとやり取りができます。ただし、ほとんどの場合、URLは、別のアプリケーションを起動して、
自分のアプリケーションに関連する情報を表示させるためだけに使われます。たとえば、アプリ
ケーションでアドレス情報を管理する場合は、与えられたアドレスを含むURLを「マップ(Maps)」ア
プリケーションに送って、その場所を表示することができます。このレベルのやり取りによって、
ユーザのためのより統合された環境を作ることができます。また、自分のアプリケーションでデバ
イス上のほかの場所に存在する機能を実行することが容易になります。

Appleでは、http、mailto、tel、およびsmsのURLスキームを組み込みでサポートしています。ま
た、「マップ(Maps)」、「YouTube」、および「iPod」アプリケーションを対象にしたhttpベースの
URLもサポートしています。アプリケーション固有のカスタムURLスキームを登録することもできま
す。アプリケーションとやり取りするには、適切な形式のコンテンツを含むNSURLオブジェクトを
作成し、それを共有のUIApplicationオブジェクトのopenURL:メソッドに渡します。openURL:メ
ソッドは、このタイプのURLを受け取るように登録されているアプリケーションを起動し、それに
URLを渡します。その後、ユーザがこのアプリケーションを終了すると、通常、システムは元のア
プリケーションを起動しなおします。ただし、常にそうするとは限りません。アプリケーションを
起動しなおすかどうかの決定は、ハンドラアプリケーションでのユーザの動作に基づいて行われま
す。元のアプリケーションに戻るかどうかは、ユーザの立場からは意味があります。

次のコード例では、あるアプリケーションが別のアプリケーションのサービスを要求する方法を示
します(この例に示す「todolist」は、アプリケーションによって登録された架空のカスタムスキー
ムです)。

NSURL *myURL = [NSURL


URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"];

アプリケーションの動作のカスタマイズ 35
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

[[UIApplication sharedApplication] openURL:myURL];

重要: デベロッパのURLタイプにAppleが定義したものと同じスキームが含まれている場合は、デ
ベロッパのアプリケーションではなく、Appleが提供するアプリケーションが起動されます。複数の
サードパーティアプリケーションが、同じURLスキームを処理するよう登録されている場合は、こ
のタイプのURLを処理するために、どのアプリケーションがピックアップされるかは未定義になり
ます。

アプリケーションで固有のカスタムURLスキームを定義する場合は、「カスタムURLスキームの実
装」 (36 ページ)で説明するような、そのスキーム用のハンドラを実装する必要があります。シ
ステムがサポートするURLスキームの詳細(URLの書式化方法の情報を含む)については、『Apple
URL Scheme Reference』を参照してください。

カスタムURLスキームの実装
アプリケーションで使用するカスタムURLスキームを含むURLタイプを登録することができます。カ
スタムURLスキームは、サードパーティアプリケーションどうし、およびサードパーティアプリケー
ションとシステムとの間でのやりとりを可能にする仕組みです。カスタムURLスキームを利用する
ことで、アプリケーションは、自身のサービスをほかのアプリケーションに利用させることができ
ます。

カスタムURLスキームの登録

アプリケーションのURLタイプを登録するには、「情報プロパティリスト」 (26 ページ)で紹介し


たCFBundleURLTypesプロパティのサブプロパティを指定する必要があります。CFBundleURLTypes
プロパティは、アプリケーションのInfo.plistファイル内の辞書の配列です。それぞれの辞書は、
アプリケーションがサポートするURLタイプを定義します。表 1-5は、CFBundleURLTypes辞書のキー
と値の説明です。

表 1-5 CFBundleURLTypesプロパティのキーと値

キー 値

CFBundleURLName URLタイプを示す抽象名文字列。一意性を確保するため、
com.acme.myschemeのように、DNSの逆順形式の識別子を指定することを
お勧めします。
この文字列値として指定するURLタイプ名は、ローカライズされた言語の
バンドルのサブディレクトリに格納されているInfoPlist.stringsファ
イルに含まれる、ローカライズされた文字列を指すキーとして使用されま
す。ローカライズされた文字列は、URLタイプを示す、所定の言語で人が
読める形式で表した名前です。

CFBundleURLSchemes このURLタイプに属するURLを表すURLスキームの配列。それぞれのスキー
ムは文字列です。あるURLタイプに属するURLは、スキームの構成要素に
よって特徴付けられます。

36 アプリケーションの動作のカスタマイズ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

図 1-7は、組み込みのXcodeエディタを使用して編集中の、アプリケーションのInfo.plistファイ
ルを示しています。この図では、左の列のURLタイプエントリが、Info.plistファイルに直接追加した
CFBundleURLTypesキーに相当します。同様に、「URL identifier」エントリと「URL Schemes」エン
トリは、CFBundleURLNameキーとCFBundleURLSchemesキーに相当します。

図 1-7 Info.plistファイルにおけるカスタムURLスキームの定義

CFBundleURLTypesプロパティを定義することによって、カスタムスキームのURLタイプを登録した
ら、次の方法でスキームをテストできます。

1. アプリケーションをビルドし、インストールして実行します。

2. ホーム(Home)画面を表示し、Safariを起動します(iPhone Simulatorでは、メニューから「ハード
ウェア(Hardware)」>「ホーム(Home)」を選択することで、ホーム(Home)画面を表示できます)。

3. Safariのアドレスバーに、カスタムスキームを使用するURLを入力します。

4. アプリケーションが起動し、アプリケーションデリゲートにapplication:handleOpenURL:メッ
セージが送信されたことを確認します。

URLリクエストの処理

アプリケーションのデリゲートでは、application:handleOpenURL:メソッドを実装することでア
プリケーションに送信されたURLリクエストを処理します。アプリケーション用にカスタムURLス
キームを登録している場合は、特別にこのメソッドを実装したデリゲートが必要になります。

カスタムスキームに基づいたURLリクエストは、読者のアプリケーションが提供するサービスを要
求するアプリケーションが理解できる一種のプロトコルを想定します。URLには、スキームを登録
したアプリケーションが何らかの方法で処理または応答することが期待される、何らかの情報が含
まれます。application:handleOpenURL:メソッドに渡されるNSURLクラスは、Cocoa Touchフレー
ムワークのURLを表します。NSURLは、RFC 1808仕様に準拠し、RFC 1808で定義されている、ユーザ、
パスワード、クエリ、コード、およびパラメータの文字列など、URLのさまざまな部分を返すメソッ
ドが含まれています。カスタムスキームの「protocol」で、さまざまな種類の情報を伝えるために
URLのこうした部分を使用できます。

アプリケーションの動作のカスタマイズ 37
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

リスト 1-2に示すapplication:handleOpenURL:メソッドの実装では、渡されたURLオブジェクト
が、クエリおよびコードの部分を使ってアプリケーション固有の情報を伝えます。デリゲートは、
この情報(この例では、to-doタスクの名前とタスクの実行日時)を抽出し、それを使ってアプリ
ケーションのモデルオブジェクトを作成します。

リスト 1-2 カスタムスキームに基づいたURLリクエストの処理


- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
if ([[url scheme] isEqualToString:@"todolist"]) {
ToDoItem *item = [[ToDoItem alloc] init];
NSString *taskName = [url query];
if (!taskName || ![self isValidTaskString:taskName]) { // タスク名を持っ
ている必要がある
[item release];
return NO;
}
taskName = [taskName
stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

item.toDoTask = taskName;
NSString *dateString = [url fragment];
if (!dateString || [dateString isEqualToString:@"today"]) {
item.dateDue = [NSDate date];
} else {
if (![self isValidDateString:dateString]) {
[item release];
return NO;
}
// 形式:yyyymmddhhmm(24時間)
NSString *curStr = [dateString substringWithRange:NSMakeRange(0,
4)];
NSInteger yeardigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(4, 2)];
NSInteger monthdigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(6, 2)];
NSInteger daydigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(8, 2)];
NSInteger hourdigit = [curStr integerValue];
curStr = [dateString substringWithRange:NSMakeRange(10, 2)];
NSInteger minutedigit = [curStr integerValue];

NSDateComponents *dateComps = [[NSDateComponents alloc] init];


[dateComps setYear:yeardigit];
[dateComps setMonth:monthdigit];
[dateComps setDay:daydigit];
[dateComps setHour:hourdigit];
[dateComps setMinute:minutedigit];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDate *itemDate = [calendar dateFromComponents:dateComps];
if (!itemDate) {
[dateComps release];
return NO;
}
item.dateDue = itemDate;
[dateComps release];
}

[(NSMutableArray *)self.list addObject:item];

38 アプリケーションの動作のカスタマイズ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

[item release];
return YES;
}
return NO;
}

アプリケーションに渡されたURLから取得した入力は必ず検証してください。URL処理に関連する問
題を回避する方法については、『Secure Coding Guide』の「Validating Input」を参照してください。
Appleが定義したURLスキームについては、『Apple URL Scheme Reference』を参照してください。

アプリケーション環境設定の表示
環境設定を使用して、アプリケーションの動作のさまざまな側面を制御する場合、この環境設定を
どのようにユーザに公開するかは、プログラムにとってそれがどのくらい重要かによって異なりま
す。

■ アプリケーションを使用するのに不可欠な(また、直接実装するだけで十分な)環境設定は、
カスタムインターフェイスを使用して、アプリケーションで直接提示します。
■ 不可欠でない環境設定や、比較的複雑なインターフェイスを必要とする環境設定は、システム
の「設定(Settings)」アプリケーションに入れます。

一連の環境設定が不可欠かどうかを判断するときは、意図した使用形態を考慮します。ユーザが比
較的頻繁に環境設定を変更することが予想される場合や、環境設定がアプリケーションの動作の仕
方に比較的重要な役割を果たす場合は、多分それらは不可欠です。たとえば、ゲームの設定は、一
般に、ゲームのプレイに不可欠なので、ユーザはすばやくそれを変更したいと思います。一方、
「設定(Settings)」アプリケーションは独立したアプリケーションなので、ユーザが頻繁にはアクセ
スしないと思われる環境設定のみに使用します。

アプリケーション内に環境設定を実装する場合は、これらの環境設定を管理するためのインター
フェイスの定義とコードの記述はデベロッパの責任になります。一方、「設定(Settings)」アプリケー
ションを使用する場合は、環境設定を管理するためのSettingsバンドルをアプリケーション側が提供
しなければなりません。

Settingsバンドルは、アプリケーションのバンドルディレクトリの最上位に含めるカスタムリソー
スです。Settings.bundleという名前の不透過ディレクトリ(Settingsバンドル)は、「設定
(Settings)」アプリケーションに環境設定の表示方法を知らせる特別な形式のデータファイル(およ
びサポートリソース)を含んでいます。このデータファイルは、「設定(Settings)」アプリケーショ
ンに、設定結果の値を環境設定データベースのどこに格納するかを知らせる役割もします。環境設
定データベースには、NSUserDefaultsAPIまたはCFPreferencesAPIを使用してアプリケーションか
らアクセスします。

Settingsバンドルを使用して環境設定を実装する場合は、環境設定用のカスタムアイコンも提供する
必要があります。「設定(Settings)」アプリケーションは、アプリケーションバンドルの最上位レベ
ルにあるIcon-Settings.pngという名前の画像ファイルを検索し、その画像をアプリケーション名
の横に表示します。この画像ファイルは29×29ピクセルのPNG画像ファイルにします。アプリケー
ションバンドルの最上位レベルにこのファイルを提供しないと、「設定(Settings)」アプリケーショ
ンは、デフォルトで、アプリケーションアイコン(Icon.png)の縮小版を使用します。

アプリケーション用のSettingsバンドルの作成の詳細については、「アプリケーション環境設
定」 (161 ページ)を参照してください。

アプリケーションの動作のカスタマイズ 39
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

アプリケーションの国際化

iPhoneアプリケーションがユーザに表示するテキスト、画像、およびその他のコンテンツは、複数
言語にローカライズするのが理想的です。たとえば、警告を促すダイアログが表示するテキスト
は、ユーザが選択した言語であるべきです。特定の言語に合わせてローカライズされたコンテンツ
のためのプロジェクトを作成するプロセスを、国際化と呼びます。ローカライズの候補となるプロ
ジェクトコンポーネントには次のものがあります。

■ コードが生成するテキスト(日付、時刻、数値表記に関するロケール固有の側面など)
■ 静的テキスト(例:アプリケーションのヘルプを表示するためにWebビューにロードされるHTML
ファイル)
■ アイコン(アプリケーションアイコンを含む)およびその他の画像(テキストが含まれている
場合や特定の文化に固有の意味を表現する場合)
■ 話し言葉を含むサウンドファイル
■ nibファイル

ユーザは、「設定(Settings)」アプリケーションを使用して、アプリケーションのユーザインターフェ
イスに表示する言語を言語の環境設定ビュー(図 1-8参照)から選択します。このビューは、「一
般(General)」の設定の「言語環境(International)」からアクセスできます。

図 1-8 言語の環境設定ビュー

選択する言語は、バンドルのサブディレクトリに対応します。サブディレクトリの名前は、ISO 639-1
言語コードと.lprojという接尾辞で構成されます。言語コードは、アンダースコアに続けてISO
3166-1の地域指示子を付加することで、特定の地域で修飾できます。たとえば、米国で話されてい
る英語にローカライズされたリソースを指定するには、バンドルの名前はen_US.lprojとなります。
ローカライズされた言語のサブディレクトリは、慣例でlprojフォルダと呼ばれます。

40 アプリケーションの国際化
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

注: ISO 639-1で定義されたコードの代わりに、ISO 639-2言語コードを使用することもできます。言


語および地域を表すコードについては、『Internationalization Programming Topics』の「Language and
Locale Designations」を参照してください。

各lprojフォルダには、特定言語(場合によっては、特定の地域)に対応してローカライズされた
すべてのコンテンツが格納されます。現在選択されている言語についてローカライズされているリ
ソースの場所(アプリケーションのlprojフォルダのいずれか)を指定するには、NSBundleクラ
ス、またはCFBundle不透過型の機能を使用します。リスト 1-3は、英語(en)にローカライズされた
コンテンツを格納するディレクトリの例です。

リスト 1-3 ローカライズされた言語のサブディレクトリ


en.lproj/
InfoPlist.strings
Localizable.strings
sign.png

このサブディレクトリの例には次の項目が存在します。

■ InfoPlist.stringsファイルには、プロジェクトのInfo.plistファイル(CFBundleDisplayName
など)内の特定のプロパティをローカライズした値として割り当てられている文字列が格納さ
れています。たとえば、Battleshipという名前の英語版のアプリケーションを表す
CFBundleDisplayNameキーについて、fr.lprojサブディレクトリのInfoPlist.stringsには
次のようなエントリがあります。

CFBundleDisplayName = "Cuirassé";

■ Localizable.stringsファイルには、アプリケーションコードが生成した文字列をローカライ
ズしたものが格納されます。
■ この例のsign.pngファイルは、ローカライズされた画像を格納しているファイルです。

ローカライズのために、コードに含まれる文字列を国際化するには、その文字列の代わりに
NSLocalizedStringマクロを使用します。このマクロの宣言は次のとおりです。

NSString *NSLocalizedString(NSString *key, NSString *comment);

最初のパラメータは、所定のlprojフォルダに配置されたLocalizable.stringsファイルに含まれ
る、ローカライズされた文字列に対する一意のキーです。2番目のパラメータは、この文字列がど
のように使われるかを示すコメントで、翻訳者に追加コンテキストを提供します。たとえば、ユー
ザインターフェイスにおいて、ラベル(UILabelオブジェクト)の内容を設定するとします。次の
コードにより、ラベルのテキストが国際化されます。

label.text = NSLocalizedString(@"City", @"Label for City text field");

次に、与えられた言語のLocalizable.stringsファイルを作成して、適切なlprojフォルダに追加
します。上記のキーの場合、このファイルには次のようなエントリが含まれます。

"City" = "Ville";

アプリケーションの国際化 41
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

注: また、NSLocalizedString呼び出しをコードの適切な場所に挿入し、genstringsコマンドラ
インツールを実行することができます。このツールは、翻訳が必要な各文字列のキーとコメントを
含んだLocalizable.stringsテンプレートを生成します。genstringsの詳細については、
genstrings(1)のmanページを参照してください。

国際化の詳細については、『Internationalization Programming Topics』を参照してください。

パフォーマンスと応答性のチューニング

アプリケーション開発の各ステップでは、アプリケーションのパフォーマンス全体に対する設計選
択の意味を考慮する必要があります。iPhoneアプリケーションの操作環境は、iPhoneデバイスとiPod
touchデバイスのモバイルという性質上、より制約されます。以降のセクションでは、開発プロセス
をとおして考慮しなければならない要因について説明します。

メモリを効率的に使用する
iPhone OSの仮想メモリモデルには、ディスクのスワップ領域が含まれていないため、アプリケー
ションには、使用可能なメモリ量について何らかの制限があります。大量のメモリを使用すると、
深刻なシステムパフォーマンスの低下が生じ、システムがアプリケーションを強制終了する結果に
なります。したがって、設計するときは、アプリケーションが使用するメモリ量を削減することに
高い優先度を置きます。

利用可能な空きメモリの量と、アプリケーションの相対的なパフォーマンスの間には、直接の相関
があります。空きメモリがほとんどないと、システムが将来のメモリ要求を満たすことができない
可能性が高くなります。この状態が発生した場合は、システムは常にメモリからコードページとそ
の他の不揮発性リソースを削除できます。ただし、これらのリソースを削除することは一時的な解
決にしかなりません。特に、リソースがすぐあとで必要になる場合はそうです。その代わり、まず
第一にメモリの使用を最小限にすることと、本当に使用するメモリを適切なタイミングでクリーン
アップすることです。

以降の各セクションでは、メモリを効率的に使用する方法と、利用可能なメモリが少量しかない場
合の対応方法についての詳細なガイドラインを示します。

アプリケーションのメモリ占有量を削減する

表 1-6に、アプリケーションの全体的なメモリ占有量を削減するためのヒントを示します。少ない
メモリ占有量で起動すれば、操作対象のデータにより多くのメモリを割り当てることができます。

42 パフォーマンスと応答性のチューニング
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

表 1-6 アプリケーションのメモリ占有量を削減するためのヒント

ヒント 取るべきアクション

メモリリークをなくす iPhone OSでは、メモリはきわめて重要なリソースなので、アプリケーショ


ンにメモリリークがあってはなりません。リークがあると、後から必要と
なるメモリが得られない可能性があります。Instrumentsアプリケーション
を使用すると、シミュレータと実際のデバイスの両方で、コード内にある
メモリリークを追跡できます。Instrumentsの使用方法の詳細については、
『Instruments User Guide』を参照してください。

リソースファイルをで ファイルはディスク上に存在しますが、使用する前にはメモリにロードし
きる限り小さくする なければなりません。プロパティリストファイルと画像の2つは、非常に
簡単な操作でメモリを節約できる種類のリソースです。プロパティリスト
ファイルが使用するメモリを削減するには、NSPropertyList-
Serializationクラスを使用して、これらのファイルをバイナリ形式で保
存します。画像については、すべての画像ファイルをできる限り小さくな
るように圧縮します(PNG画像(iPhoneアプリケーションで推奨される画
像形式)を圧縮するには、pngcrushツールを使用します)。

大きなデータセットに アプリケーションで、大量の構造化データを扱う場合は、そのデータをフ
はSQLiteを使用する ラットなファイルではなく、SQLiteデータベースに保存します。SQLiteは、
データセット全体を一度にメモリにロードせずに、大容量のデータセット
を管理する効率的な方法を提供しています。

リソースは後からロー 実際に必要になるまでは、リソースファイルをロードしてはいけません。
ドする リソースファイルを事前にロードすることは時間を節約する方法のように
思えますが、実際には、すぐにアプリケーションの速度が遅くなります。
また、そのリソースを使用せずに終わった場合は、リソースのロードは単
なるメモリの無駄使いです。

Thumbを使用してプロ コンパイラフラグに-mthumbを追加すると、コードサイズを最大35%まで
グラムをビルドする 削減できます。ただし、浮動小数点数を多用するコードモジュールでは、
Thumbを使用するとパフォーマンスが低下する可能性があるため、このオ
プションをオフにしてください。

メモリを賢く割り当てる

iPhoneアプリケーションでは、マネージドメモリモデルを使用します。このモデルでは、オブジェ
クトの保持と解放を明示的に行わなければなりません。表 1-7は、プログラム内でメモリを割り当
てる際のヒントを示しています。

パフォーマンスと応答性のチューニング 43
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

表 1-7 メモリ割り当てのヒント

ヒント 取るべきアクション

自動解放オブジェ autoreleaseメソッドを使用して解放されたオブジェクトは、自動解放プー
クトの使用を減ら ルを明示的に空にするか次のイベントループに入るときまで、メモリに残り
す ます。できる限り、autoreleaseメソッドの使用は避けて、代わりに、オブ
ジェクトが占有していたメモリがすぐに解放されるreleaseメソッドを使用
します。ある程度の数の自動解放オブジェクトを作成しなければならない場
合は、ローカルの自動解放プールを作成し、定期的にそれを空にすること
で、次のイベントループに入る前にこれらのオブジェクトに割り当てられた
メモリを解放します。

リソースにサイズ 小さなリソースファイルで済む場合は、大きなリソースファイルのロードは
の上限を設ける 避けます。高解像度の画像を使用する代わりに、iPhone OSベースのデバイス
に適したサイズの画像を使用します。大きなリソースファイルを使用しなけ
ればならない場合は、その時に必要なファイルの部分だけをロードする方法
を見つけます。たとえば、ファイル全体をメモリにロードする代わりに、
mmap関数とmunmap関数を使用して、ファイルの一部をメモリにマップした
りアンマップしたりします。メモリへのファイルのマッピングの詳細につい
ては、『File-System Performance Guidelines』を参照してください。

無限問題セットは 無限問題セットは、際限なく大量のデータの計算を必要とする可能性があり
避ける ます。このセットが、利用可能な量よりも多くのメモリを必要とした場合、
アプリケーションは計算を完了できなくなります。このようなセットの使用
はできる限り避け、メモリの上限が明確な問題を処理すべきです。

iPhoneアプリケーションでのメモリ割り当て方法の詳細、および自動解放プールの詳細については、
『Cocoa Fundamentals Guide』の「Cocoa Objects」を参照してください。

浮動小数点演算の留意点
iPhone OSベースのデバイスのプロセッサは、浮動小数点演算をハードウェアで実行することができ
ます。ソフトウェアベースの固定小数点算術ライブラリを使用して計算を実行する既存のプログラ
ムがある場合は、その代わりに浮動小数点算術ライブラリを使用するように変更することを検討す
べきです。ハードウェアベースの浮動小数点演算は、一般に、それと同等のソフトウェアベースの
固定小数点演算よりもはるかに高速です。

重要: もちろん、コード内で浮動小数点演算を広範囲に使用する場合は、-mthumbコンパイラオプ
ションを付けずにコンパイルすることを忘れないでください。Thumbオプションを利用すると、コー
ドモジュールのサイズは削減できますが、浮動小数点コードのパフォーマンスが低下する可能性が
あります。

電力消費を抑える
モバイルデバイスでの電力消費は、常に問題になります。iPhone OSの電源管理システムは、現在使
われていないハードウェア機能をすべて停止することによって電力を節約します。CPUを多用する
演算や、高いグラフィックスフレームレートに関与する演算を避けることに加えて、次の機能の使
用を最小限に抑えることによって、バッテリの持続時間を向上させることができます。

44 パフォーマンスと応答性のチューニング
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

■ Wi-Fi無線
■ 携帯電話用ベースバンド無線
■ Core Locationフレームワーク
■ 加速度センサー
■ ディスク

これらの機能の使用を最小限にするという目標は、アプリケーションを作成する際にむやみに制限
を加えることではありません。ただし、設計のときに、デバイス上で実行するすべての処理は、
ユーザの全体的なバッテリー持続時間に影響することを忘れないでください。アプリケーションを
実行するコードが多いほど、CPUが消費する電力も増加します。ネットワークに伝送するデータが
多いほど、無線を実行するために使用する電力は増加します。実際、ネットワークアクセスは、デ
バイス上で実行できる操作の中で最も電力を消費します。このため、次のガイドラインに従って最
小限に抑える必要があります。

■ 外部ネットワークサーバには必要なときだけ接続し、ポーリングは行わない。
■ ネットワークに接続しなければならない場合は、伝送するデータ量を最小限に抑える。
■ データは、伝送パケットに分けて時間をかけて伝送するのではなく、一気に伝送する。システ
ムは、Wi-Fi無線や携帯電話用無線が使われていないことを検出すると、それをオフにします。
同じ量のデータを伝送した場合、伝送時間が長いほど、短い時間で伝送したときよりも多くの
電力を消費します。
■ Core Locationフレームワークを使用して位置データを収集する場合は、必要なデータを取得し
たらできるだけ早く位置データの更新を無効にします。Core Locationは、利用可能なGPS、携帯
電話、およびWi-Fiネットワークを使用して、ユーザの位置を決定します。Core Locationは、こ
れらの無線の使用を最小限に抑えるように努力していますが、この機能を完全にオフにするこ
とが、電力を節約するための最善の方法です。

アプリケーションのパフォーマンスを最適化することは、消費電力を最小にするもう1つの方法で
す。処理を抑えて、最小限のコードを使用するアプリケーションは、最適化されていないアプリ
ケーションよりもはるかに効率的に電力を消費します。優れた設計は、アプリケーション内でユー
ザが費やす時間を最小にするのにも役立ちます。これは、バッテリー持続時間を長くするための良
い方法でもあります。

コードをチューニングする
iPhone OSには、アプリケーションのパフォーマンスをチューニングするためのアプリケーションが
いくつか付属しています。これらのツールのほとんどはMac OS Xで動作するため、シミュレータで
アプリケーションを実行しながらコードのいくつかの側面をチューニングするのに適しています。
たとえば、シミュレータを使用して、メモリリークをなくしたり、全体的なメモリ使用を最小限に
抑えるようにしたりできます。また、効率の悪いアルゴリズムや、未知のボトルネックに起因する
コード内の処理上のホットスポットを取り除くこともできます。

シミュレータでコードをチューニングした後は、Instrumentsアプリケーションを使用して、デバイ
ス上でさらにコードをチューニングする必要があります。実際のデバイス上でコードを実行するこ
とが、コードを完全にチューニングするための唯一の方法です。シミュレータはMac OS Xで動作す
るので、実際のデバイスよりもCPUは高速で、使用可能なメモリも豊富です。そのため、一般的に、
実際のデバイス上でのパフォーマンスよりも、ずっと良い結果になります。Instrumentsを使用して、
実際のデバイス上でのコードを追跡することによって、チューニングが必要なパフォーマンスボト
ルネックがさらに検出される可能性があります。

パフォーマンスと応答性のチューニング 45
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第1章
コアアプリケーション

Instrumentsの使用方法の詳細については、『Instruments User Guide』を参照してください。

46 パフォーマンスと応答性のチューニング
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章

ウインドウとビュー

ウインドウとビューは、iPhoneアプリケーションのインターフェイスを構成するために使用する、
ビジュアルコンポーネントです。ウインドウは、コンテンツを表示するための背景プラットフォー
ムを提供します。一方、ビューは、コンテンツの描画、およびユーザ操作への応答に関する処理の
ほとんどを実行します。この章では、ウインドウとビューの両方に関連する概念について説明しま
すが、システムにとって重要な役割を果たすビューの方に重点を置きます。

iPhoneアプリケーションでは、ビューは非常に重要な役割を果たすため、1つの章でそのすべての側
面を説明することはできません。この章では、ウインドウとビューの基本的な特性、ウインドウと
ビューの関係、およびアプリケーションでそれらを作成したり操作したりする方法に焦点を当てて
説明します。この章では、ビューがタッチイベントに対してどのように応答するか、またカスタム
コンテンツをどのように描画するかについては言及しません。これらの内容の詳細については、
「イベント処理」 (79 ページ)および「グラフィックスと描画」 (91 ページ)を参照してくだ
さい。

ウインドウとビューとは?

Mac OS Xと同様に、iPhone OSではウインドウとビューを使用してグラフィックコンテンツを画面に


表示します。ウインドウオブジェクトとビューオブジェクトは、どちらのプラットフォームにおい
ても互いに多くの類似点がありますが、ウインドウとビューの両方が果たす役割は、それぞれのプ
ラットフォームで少し異なります。

UIWindowの役割
Mac OS Xアプリケーションとは対照的に、iPhoneアプリケーションは、通常、UIWindowクラスのイ
ンスタンスで表わされるウインドウを1つだけ持っています。アプリケーションは、起動時にこの
ウインドウを作成し(または、nibファイルからウインドウをロードし)、1つ以上のビューをそこ
に追加して表示します。その後は、このウインドウオブジェクトを再び参照することはほとんどあ
りません。

iPhone OSでは、ウインドウオブジェクトには「閉じる」ボタンやタイトルバーなどの視覚的な装飾
はありません。したがって、ユーザが直接ウインドウを閉じたり操作したりすることはできませ
ん。ウインドウに対するすべての操作は、プログラムインターフェイスを通して行います。また、
アプリケーションは、イベントの送付を円滑に行うためにウインドウを使用します。たとえば、ウ
インドウオブジェクトは、現在のファーストレスポンダオブジェクトを常に追跡しており、
UIApplicationオブジェクトからの依頼があると、そのレスポンダにイベントを送ります。

経験豊富なMac OS Xデベロッパは、UIWindowクラスの継承関係に違和感を覚えるかもしれません。
Mac OS Xでは、NSWindowの親クラスはNSResponderです。iPhone OSでは、UIWindowの親クラスは
UIViewです。したがって、iPhone OSでは、ウインドウはビューオブジェクトでもあります。親ク
ラスは異なりますが、一般に、iPhone OSでのウインドウの扱いはMac OS Xと同様です。つまり、通
常はUIWindowオブジェクトのビュー関連プロパティを直接操作することはありません。

ウインドウとビューとは? 47
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

アプリケーションウインドウを作成するとき、ウインドウの最初のフレームサイズは、必ず画面全
体を覆うように設定するべきです。nibファイルからウインドウをロードする場合、Interface Builder
が、画面サイズより小さいウインドウの作成を許可しません。しかし、プログラミングによってウ
インドウを作成する場合は、作成時に望みのフレーム矩形を明示的に渡さなければなりません。画
面の矩形と異なる矩形は渡さないでください。画面の矩形は、UIScreenオブジェクトから次のよう
にして取得できます。

UIWindow* aWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen]


bounds]] autorelease];

iPhone OSでは、ウインドウを互いに重ねることが可能ですが、アプリケーションで複数のウインド
ウを作成するべきではありません。システム自体が、システムステータスバー、重要な警告、その
他のメッセージをアプリケーションウインドウの手前に表示するために、追加のウインドウを使用
します。アプリケーションコンテンツの手前に警告を表示したい場合は、追加のウインドウを作成
するのではなく、UIKitによって提供されている警告ビューを使用します。

UIViewの役割
UIViewクラスのインスタンスであるビューは、画面上の矩形領域を定義します。iPhoneアプリケー
ションでは、ユーザインターフェイスの表示と、そのインターフェイスを対象とした操作への応答
の両面において、ビューは中心的な役割を果たします。各ビューオブジェクトは、その矩形領域内
にコンテンツを表示する責務と、その領域内で発生したタッチイベントに応答する責務を負ってい
ます。この2つの振る舞いから、ビューが、アプリケーションにおいてユーザと対話するための主
要なメカニズムであることがわかります。Model-View-Controllerアプリケーションでは、ビューオブ
ジェクトは、まさしくアプリケーションのView部分に該当します。

コンテンツの表示とイベント処理のほかに、ビューは、1つ以上のサブビューを管理できます。サ
ブビューとは、元のビューオブジェクト(親ビューまたはスーパービューと呼ばれる)のフレーム
内に埋め込まれたビューオブジェクトのことです。ビューは、ビュー階層と呼ばれる階層構造に
なっており、階層には任意の数のビューを含めることができます。また、サブビューにさらにサブ
ビューを追加して、ビューを何階層にもネストさせることができます。各サブビューは、その親
ビューの手前に表示されるので、画面への表示はビュー階層内のビューの構成によって決まりま
す。また、この構成によって、ビューがイベントや変更にどのように対応するかも決まります。各
親ビューは、その直下のサブビューの管理を担当し、必要に応じてサブビューの位置やサイズを調
整したり、サブビューで処理できないイベントに応答したりします。

ビューオブジェクトは、アプリケーションがユーザと対話するための主な手段となるので、たくさ
んの責務を負っています。以下に、その責務のほんの一部を示します。

■ 描画とアニメーション
❏ ビューは、その矩形領域にコンテンツを描画します。
❏ ビューのプロパティには、新しい値への変化をアニメーション化できるものもあります。

■ レイアウトとサブビューの管理
❏ ビューは、サブビューのリストを管理します。
❏ ビューは、親ビューを基準にして自身のサイズ変更動作を定義します。
❏ ビューは、必要に応じて、手動でサブビューのサイズや位置を変更できます。
❏ ビューは、そのビューの座標系で表された点を、ほかのビューやウインドウの座標系に変
換できます。

48 ウインドウとビューとは?
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

■ イベント処理
❏ ビューはタッチイベントを受け取ります。
❏ ビューは、レスポンダチェーンに含まれています。

iPhoneアプリケーションでは、ビューは、View Controllerと密接に連携して、ビューの動作のさまざ
まな側面を管理します。View Controllerは、ビューのロードおよびアンロード、ユーザが物理的にデ
バイスを回転したことによるインターフェイスの回転、複雑なユーザインターフェイスを構成する
ために使われる高度なナビゲーションオブジェクトとの対話を処理します。詳細については、「View
Controllerの役割」 (52 ページ)を参照してください。

この章のほとんどの部分は、これらの責務の説明と、自分のコードをUIViewの既存の動作と連携さ
せる方法を示すことに当てられています。

UIKitのビュークラス
UIViewクラスは、ビューの基本プロパティを定義しますが、ビジュアル表現は定義しません。その
代わりに、UIKitではサブクラスを使用して、テキストフィールド、ボタン、ツールバーなどの標準
的なシステム要素に固有の外観や動作を定義します。図 2-1に、UIKitのすべてのビュークラスの階
層図を示します。UIViewクラスとUIControlクラスを除いて、この階層内のほとんどのビューは、
そのまま使用するか、デリゲートオブジェクトと組み合わせて使用するように設計されています。

ウインドウとビューとは? 49
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

図 2-1 ビュークラスの階層

NSObject

UIResponder

UIView UIWindow

UILabel

UIPickerView

UIProgressView

UIActivityIndicatorView

UIImageView

UITabBar

UIToolbar

UINavigationBar

UITableViewCell

UIActionSheet

UIAlertView

UIScrollView UITableView

UISearchBar UITextView

UIWebView

UIControl UIButton

UIDatePicker

UIPageControl

UISegmentedControl

UITextField

UISlider

UISwitch

このビュー階層は、大きく以下のカテゴリに分類できます。

■ コンテナ

50 ウインドウとビューとは?
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

コンテナビューは、ほかのビューの機能を拡張したり、コンテンツを視覚的に区切ったりする
働きをします。たとえば、UIScrollViewクラスは、コンテンツが大きすぎて一度にすべてを画
面上に表示できないようなビューを表示するために使用します。UITableViewクラスは
UIScrollViewのサブクラスで、データのリストを管理します。テーブルの行は選択可能なた
め、テーブルは、階層的なナビゲーション(たとえば、オブジェクトの階層を掘り下げる場合
など)によく使用されます。
UIToolbarは、特殊なタイプのコンテナで、ボタンのようなアイテムをビジュアルにグループ
化します。通常、ツールバーは画面の下端に沿って表示されます。「Safari」、「メール(Mail)」、
「写真(Photos)」の各アプリケーションでは、よく使うコマンドを表すボタンを表示するために
ツールバーを使用しています。ツールバーは、常に表示しておくことも、アプリケーションで
必要なときだけ表示することもできます。
■ コントロール
コントロールは、典型的なアプリケーションユーザインターフェイスのほとんどを作成するた
めに使われます。コントロールは、UIControlスーパークラスを継承する特殊なビューです。
コントロールは一般に、特定の値を表示し、その値を変更するために必要なすべてのユーザ操
作を処理します。また、コントロールは、ユーザ操作が発生したことを、標準的なシステムパ
ラダイム(ターゲット/アクション、デリゲーションなど)を使用してアプリケーションに通
知します。コントロールには、ボタン、テキストフィールド、スライダ、スイッチなどがあり
ます。
■ 表示ビュー
コントロールおよびその他の多くのビューは、対話的な動作を提供しますが、情報を表示する
だけのビューもあります。このような動作をするUIKitクラスには、UIImageView、UILabel、
UIProgressView、およびUIActivityIndicatorViewなどがあります。

■ Text ViewとWeb View


Text ViewとWeb Viewは、アプリケーション内の複数行のテキストコンテンツを表示するための、
より高度な手段を提供します。UITextViewクラスは、複数行のテキストをスクロール可能な領
域に表示したり、それらを編集したりする機能をサポートします。UIWebViewクラスは、HTML
コンテンツを表示する手段を提供します。これを利用して、グラフィックスや高度なテキスト
書式オプションを組み込んだり、コンテンツを独自の方法でレイアウトできます。
■ Alert ViewとAction Sheet
Alert ViewとAction Sheetは、ユーザの注意をすばやく喚起するために使用します。これらのビュー
は、ユーザに対してメッセージと共に1つ以上のオプションボタンを提示します。ユーザはこの
ボタンを使用して、メッセージに応答できます。Alert ViewとAction Sheetは、機能的には似てい
ますが、外観と動作は異なります。たとえば、UIAlertViewクラスは、画面上にポップアップ
する青い警告ボックスを表示し、UIActionSheetクラスは、画面の下端からスライドして出て
くるボックスを表示します。
■ ナビゲーションビュー
タブバーとナビゲーションバーは、View Controllerと連携して動作し、ユーザインターフェイス
のある画面から別の画面へナビゲートするためのツールを提供します。通常は、UITabBarと
UINavigationBarの各項目を直接作成することはしません。その代りに、適切なコントローラ
インターフェイス、またはInterface Builderを使用してそれらを設定します。
■ ウインドウ
ウインドウは、ほかのすべてのビューのルートコンテナであり、コンテンツの描画サーフェス
を提供します。通常、1つのアプリケーションにつきウインドウは1つだけです。詳細について
は、「UIWindowの役割」 (47 ページ)を参照してください。

ウインドウとビューとは? 51
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ビューのほかに、UIKitには、それらのオブジェクトを管理するView Controllerがあります。詳細につ
いては、「View Controllerの役割」 (52 ページ)を参照してください。

View Controllerの役割
iPhone OSで実行されるアプリケーションには、コンテンツを整理してユーザに表示するためのさま
ざまなオプションが用意されています。たくさんのコンテンツを含むアプリケーションでは、コン
テンツを複数の画面の情報に分割することもできます。実行時には、各画面は、その特定の画面用
のデータの表示を担当する一連のビューオブジェクトによって支えられています。1つの画面の
ビューは、1つのView Controllerオブジェクトによって支えられています。View Controllerの仕事は、
ビューに表示するデータを管理することと、更新をアプリケーションのほかの部分と調整すること
です。

UIViewControllerクラスは、自身が管理する一連のビューを作成したり、メモリ不足状態のとき
にビューをメモリから削除する責務を負っています。また、View Controllerは、いくつかのシステム
動作に自動的に応答します。たとえば、デバイスの向きが変更になったことに応答して、View
Controllerは、その向きがサポートされている場合は、新しい向きに適合するように自身が管理する
ビューのサイズを変更します。また、View Controllerを使用して、現在のビューの前面に新規のモー
ダルビューを表示することもできます。

UIViewController基本クラスのほかに、UIKitには、このプラットフォームに共通する複雑なイン
ターフェイス動作を処理する、より高度なサブクラスが含まれています。特に、ナビゲーションコ
ントローラは、階層的な複数の画面におよぶコンテンツの表示を管理します。タブバーコントロー
ラは、ユーザがアプリケーションの異なる操作モードを表す画面セット間を切り替えることを可能
にします。

View Contollerを使用してユーザインターフェイス内のビューを管理する方法については、『View
Controller Programming Guide for iPhone OS』を参照してください。

ビューのアーキテクチャとジオメトリ

ビューは、iPhoneアプリケーションの中心的なオブジェクトなので、ビューがシステムのほかの部
分とどのように相互に作用するかを、少し理解しておくことは重要です。UIKitの標準ビュークラス
は、かなりの数の動作をアプリケーションに無償で提供します。また、これらのビュークラスは、
その動作をカスタマイズして、アプリケーションに必要な処理を実行するための、明確に定義され
た統合点を備えています。

以降の各セクションでは、ビューの標準的な動作について説明し、カスタムコードと統合できる場
所を示します。特定のクラスの統合点の詳細については、そのクラスのリファレンス文書を参照し
てください。クラスリファレンス文書の網羅的なリストは、『UIKit Framework Reference』から入手
できます。

ビューの対話モデル
ユーザがユーザインターフェイスを操作をしたり、自分のコードでプログラムの中で何らかの変更
を加えたりしたときは、それらの操作を処理するために、UIKitの内部で複雑なイベントシーケンス
が発生します。そのシーケンス内の特定の時点で、UIKitは、ビュークラスを呼び出して、アプリケー
ションとして応答を行う機会をビューに与えます。これらの呼び出し点を理解することは、ビュー

52 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

をシステムに適合させる場所を理解するために重要です。図 2-2は、ユーザが画面に触れることに
よって始まり、それに応じてグラフィックスシステムが画面内容を更新することによって終わる、
基本的なイベントシーケンスを示します。プログラムによるイベントも、最初のユーザ操作以外
は、同じ基本ステップをたどります。

図 2-2 UIKitとビューオブジェクトとの対話

iPhone OS
Your Application
Touch Framework
touches
Touches setNeedsLayout
UIKit setNeedsDisplay
frame, alpha, etc.

layoutSubviews

• Buffers setNeedsDisplay
• Images frame, alpha, etc.
• Attributes
• Geometry drawRect
• Animations
Compositor Draw images, text, etc.

Graphics hardware

以下のステップは、図 2-2 (53 ページ)のイベントシーケンスをさらに細分化して、各ステージで


何が発生し、それに応答してアプリケーションでどのように反応できるかを示します。

1. ユーザが画面に触れます。

2. ハードウェアは、そのタッチイベントをUIKitフレームワークに報告します。

3. UIKitフレームワークは、そのタッチを1つのUIEventオブジェクトにまとめて、適切なビューに
送付します(UIKitがイベントをビューに送付する方法の詳細については、「イベントの送
付」 (81 ページ)を参照してください)。

4. ビューのイベント処理メソッドは、以下のいずれかを実行して、そのイベントに応答します。

■ ビューまたはサブビューのプロパティ(frame、bounds、alphaなど)を調整する。
■ ビュー(またはサブビュー)に、レイアウトの変更が必要であるというマークを付ける。
■ ビュー(またはサブビュー)に、再描画が必要であるというマークを付ける。
■ データの一部が変更されたことをコントローラに通知する。

もちろん、これらの処理のどれを実行すべきかを判断し、それを実行するための適切なメソッ
ドを呼び出すのは、ビューの責任です。

5. レイアウトが必要であるというマークがビューに付いている場合、UIKitは、そのビューの
layoutSubviewsメソッドを呼び出します。

カスタムビューでこのメソッドをオーバーライドし、それを使用して任意のサブビューの位置
とサイズを調整できます。たとえば、大きなスクロール領域を提供するビューでは、メモリに
収まる可能性の低い大きなビューを1つ作成するのではなく、複数のサブビューを「タイル」の

ビューのアーキテクチャとジオメトリ 53
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ようにして使用する必要があります。このメソッドの実装の中で、ビューは、現在オフスクリー
ンにあるサブビューを非表示にしたり、サブビューを配置しなおしたりします。また、サブ
ビューを使用して新たに表示するコンテンツを描画します。この処理の一部として、ビューは、
新しいタイルに再描画が必要であるというマークを付けることもできます。

6. ビューの一部に再描画が必要であるというマークが付いている場合、UIKitは、そのビューの
drawRect:メソッドを呼び出します。

UIKitは、再描画が必要なビューに対してのみ、このメソッドを呼び出します。各ビューのこの
メソッドの実装では、指定された領域をできる限り迅速に再描画しなければなりません。各
ビューは、そのビューに固有のコンテンツのみを描画し、サブビューのコンテンツは描画しま
せん。この時点で、ビューは、プロパティやレイアウトにそれ以上の変更を加えようとしては
なりません。

7. 更新されたビューは、残りの表示コンテンツと合成され、表示のためにグラフィックスハード
ウェアに送られます。

8. グラフィックスハードウェアは、レンダリングされたコンテンツを画面に転送します。

注: 上で述べた更新モデルは、主に、ネイティブなビューおよび描画テクノロジーを使用するア
プリケーションに適用されます。アプリケーションが、OpenGL ESを使用してコンテンツを描画す
る場合は、通常、フルスクリーンビューを1つ設定して、OpenGLのグラフィックスコンテキストに
直接描画します。ビューは依然としてタッチイベントを処理しますが、サブビューをレイアウトし
たり、drawRect:メソッドを実装する必要がありません。OpenGL ESの使用の詳細については、
「OpenGL ESを使用した描画」 (101 ページ)を参照してください。

前述の一連のステップを踏まえ、カスタムビューのための主な統合点は以下のとおりです。

1. 以下のイベント処理メソッド:

■ touchesBegan:withEvent:

■ touchesMoved:withEvent:

■ touchesEnded:withEvent:

■ touchesCancelled:withEvent:

2. layoutSubviewsメソッド

3. drawRect:メソッド

これらは、ほとんどのカスタムビューで、独自の動作を実行するために実装するメソッドです。た
だし、これらすべてをオーバーライドする必要はありません。たとえば、サイズ変更が生じない
ビューを実装する場合は、layoutSubviewsメソッドをオーバーライドする必要はありません。同
様に、テキストや画像などの単純なコンテンツを表示するビューを実装する場合は、UIImageView
オブジェクトやUILabelオブジェクトをサブビューとして組み込むだけで、描画をまったく行わず
に済む場合もあります。

これらは、主な統合点であって、統合点はこれだけではないということを忘れないでください。
UIViewクラスのメソッドのなかには、サブクラスでオーバーライドされることを前提に設計されて
いるものもあります。カスタム実装でオーバーライドするのに適したメソッドであるかどうかを判
断するには、『UIView Class Reference』に記載されているメソッドの説明を参照してください。

54 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ビューのレンダリングアーキテクチャ
画面上にコンテンツを表示するにはビューを使用しますが、UIViewクラス自体は、実際には、その
基本的な動作のほとんどを別のオブジェクトに依存しています。UIKitのビューオブジェクトはすべ
て、Core Animationレイヤオブジェクト(CALayerクラスのインスタンス)に支えられています。こ
のレイヤクラスは、ビューのコンテンツのレイアウトとレンダリング、およびそのコンテンツの合
成とアニメーション化の基本部分をサポートします。

Mac OS X(Core Animationのサポートはオプション)とは対照的に、iPhone OSでは、Core Animation


がビューのレンダリング実装の中心に組み込まれています。Core Animationは中心的な役割を果たし
ますが、UIKitは、Core Animationの最上位に透過的なレイヤを提供して、プログラミング作業を効率
化します。この透過的なレイヤによって、Core Animationレイヤに直接アクセスする必要はほとんど
なくなります。その代わりに、UIViewクラスのメソッドとプロパティを使用して、同様の動作にア
クセスできます。Core Animationが重要になるのは、UIViewクラスではアプリケーションのニーズ
をすべて満たすことができない場合です。その場合は、Core Animationレイヤの内部に入り込んで、
アプリケーションのために非常に高度なレンダリングを行うことができます。

以降の各セクションでは、Core Animationの基礎的な情報を提供し、UIViewクラスを通じて無償で
提供されるいくつかの機能について説明します。Core Animationを使用して高度なレンダリングを行
う方法の詳細については、『Core Animation Programming Guide』を参照してください。

Core Animationの基礎

Core Animationは、ハードウェアの高速性と最適化されたアーキテクチャを利用して、高速なレンダ
リングとリアルタイムアニメーションを実現します。ビューのdrawRect:メソッドが初めて呼び出
されたときに、レイヤはその結果をキャプチャしてビットマップに変換します。その後の再描画呼
び出しでは、このキャッシュされたビットマップが使用され、負荷がかかるdrawRect:メソッドの
呼び出しはできる限り回避されます。このプロセスによって、Core Animationは、合成操作を最適化
して望みどおりのパフォーマンスを実現します。

Core Animationは、ビューオブジェクトに関連付けられたレイヤを、レイヤツリーと呼ばれる階層に
格納します。ビューと同様に、レイヤツリー内の各レイヤは、1つの親を持ち、任意の数のサブレ
イヤを組み込むことができます。デフォルトでは、レイヤツリー内のオブジェクトは、ビュー階層
内のビューとまったく同じ構成になります。ただし、対応するビューを追加せずに、レイヤを追加
することもできます。ビューを必要としない特殊な視覚効果を実装するために、このような追加を
行う場合があります。

レイヤオブジェクトは、iPhone OSのレンダリングおよびレイアウトシステムの背後で、実際にそれ
を推進する働きをします。ほとんどのビュープロパティは、実際には、この基盤レイヤオブジェク
トのプロパティを包む薄いラッパーです。(CALayerオブジェクトを直接使用して)レイヤツリー
内のレイヤのプロパティを変更した場合は、変更した値が、すぐにそのレイヤオブジェクトに反映
されます。ただし、変更がアニメーションをトリガする場合、その変更はすぐには画面に反映され
ず、アニメーションによって一定の時間をかけて画面に反映されます。この種のアニメーションを
管理するために、Core Animationは、プレゼンテーションツリーとレンダリングツリーという2つの
レイヤオブジェクトのセットを保持しています。

プレゼンテーションツリーは、レイヤの状態を、現在ユーザに提示されているとおりに反映しま
す。レイヤ値の変更をアニメーション化する場合は、プレゼンテーションレイヤには、アニメー
ションが始まるまで古い値が反映されます。アニメーションが進むにつれて、Core Animationは、ア
ニメーションの現在のフレームに基づいてプレゼンテーションツリーレイヤの値を更新します。レ
ンダリングツリーは、プレゼンテーションツリーと連動して、画面上の変化をレンダリングしま

ビューのアーキテクチャとジオメトリ 55
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

す。レンダリングツリーは、独立のプロセスまたはスレッドで実行されるので、その処理は、アプ
リケーションのメイン実行ループに影響を与えません。レイヤツリーとプレゼンテーションツリー
は共に公開(public)のAPIですが、レンダリングツリーは非公開(private)のAPIです。

ビューの背後にあるレイヤオブジェクトの配置は、描画コードのパフォーマンスに重要な影響を与
えます。レイヤを使用することの有利な点は、ビューに対するジオメトリ変更のほとんどを、再描
画する必要がないことです。たとえば、ビューの位置とサイズを変更しても、システムはビューの
コンテンツを再描画する必要はありません。レイヤによって作成されたキャッシュ済みのビット
マップを再利用するだけで済みます。このキャッシュされたコンテンツをアニメーション化すれ
ば、毎回そのコンテンツを再描画するのに比べて大幅な効率化になります。

レイヤを使用することの不利な点は、キャッシュデータが増えることで、アプリケーションのメモ
リが圧迫される可能性があることです。アプリケーションが作成するビューが多すぎたり、非常に
大きかったりすると、すぐにメモリ不足になります。アプリケーション内でビューを使用すること
を控える必要はありませんが、既存のビューを再利用できる場合は、新規のビューを作成しないよ
うにします。言い換えれば、同時にメモリ内に保持するビューの数を最小にするようなアプローチ
を追求しましょう。

Core Animationの概要、オブジェクトツリー、およびアニメーションの作成方法の詳細については、
『Core Animation Programming Guide』を参照してください。

ビューのレイヤの変更

iPhone OSでは、ビューは対応するレイヤを1つ持つ必要があります。このため、UIViewクラスは初
期化時にこのレイヤを自動的に作成します。このようにして作成されたレイヤには、ビューのlayer
プロパティを介してアクセスできます。ただし、ビューが作成された後でこのレイヤオブジェクト
を変更することはできません。

ビューで異なる種類のレイヤを使用するには、そのビューのlayerClassクラスメソッドをオーバー
ライドして、ビューで使用したいレイヤのクラスオブジェクトを返す必要があります。異なるレイ
ヤクラスを返すようにする理由として一番よくあるのは、OpenGLベースのアプリケーションを実装
するためです。OpenGLの描画コマンドを使用するには、基盤となるビューのレイヤはCAEAGLLayer
クラスのインスタンスでなければなりません。この種類のレイヤは、OpenGLのレンダリング呼び出
しとやり取りをして、望みのコンテンツを画面に表示します。

重要: ビューのレイヤのデリゲートプロパティを変更してはいけません。このプロパティはビュー
へのポインタを格納しており、非公開と考えるべきです。同様に、ビューは、1つだけのレイヤの
デリゲートとして動作するので、ビューをほかのレイヤオブジェクトのデリゲートとして割り当て
てはいけません。このようなことを行うと、アプリケーションがクラッシュする原因になります。

アニメーションのサポート

iPhone OSのすべてのビューの背後にレイヤオブジェクトを持つことの利点の1つは、コンテンツを
アニメーション化しやすくなることです。アニメーションは、必ずしも視覚的な楽しみを演出する
ためのものではありません。アニメーションは、アプリケーションのユーザインターフェイスで生
じた変更のコンテキストをユーザに提供します。たとえば、トランジションを使用して、ある画面
から別の画面に移動すると、これらの画面に関連があることをユーザに示すことができます。シス
テムは、最もよく使われるアニメーションの多くを自動的にサポートします。しかし、インター
フェイスのその他の部分のためにアニメーションを作成することもできます。

56 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

UIViewクラスのプロパティの多くは、アニメーション化できます。アニメーション化可能なプロパ
ティとは、ある値から別の値へのアニメーション化が半自動的にサポートされているプロパティで
す。その場合も、UIKitにアニメーションの実行を指示する必要があります。しかし、アニメーショ
ンが開始されると、それを実行するすべての責任はCore Animationが負います。UIViewオブジェク
トでアニメーション化可能なプロパティには、以下のものが含まれます。

frame
bounds
center
transform
alpha

その他のビュープロパティは、直接アニメーション化できませんが、明示的にアニメーションを作
成できるものもあります。明示的なアニメーションを作成するには、アニメーションとレンダリン
グされるコンテンツの管理にかかわる処理の多くを自分で行う必要があります。ただし、その場合
も、すぐれたパフォーマンスを得るために基盤となるCore Animationインフラストラクチャを使用し
ます。

UIViewクラスを使用したアニメーションの作成の詳細については、「ビューのアニメーション
化」 (70 ページ)を参照してください。明示的なアニメーションの作成の詳細については、『Core
Animation Programming Guide』を参照してください。

ビューの座標系
UIKitの座標は、左上隅を原点とし、下方向と右方向に伸びる座標軸をもつ座標系に基づいています。
座標の値は、浮動小数点数を使用して表されます。これによって、コンテンツの正確なレイアウト
と位置決めが可能になり、解像度からの独立性を維持できます。図 2-3 (58 ページ)は、この座標
系を、画面を基準にして示します。ただし、この座標系は、UIWindowクラスおよびUIViewクラス
でも使用されます。この特殊な向きは、QuartzやMac OS Xで使われているデフォルトの座標系とは
異なりますが、ユーザインターフェイスにコントロールとコンテンツを配置しやすくするために選
択されました。

ビューのアーキテクチャとジオメトリ 57
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

図 2-3 ビューの座標系

Standard coordinates

(0,0)
x

インターフェイスのコードを記述する際には、現在有効になっている座標系に注意します。どのウ
インドウオブジェクトやビューオブジェクトも、固有のローカルな座標系を持っています。ビュー
内での描画はすべて、そのビューのローカルな座標系に基づいて行われます。ただし、各ビューの
フレーム矩形は、その親ビューの座標系を使用して指定します。また、イベントオブジェクトの一
部として送付される座標は、それを含んでいるウインドウの座標系に基づいています。便利なよう
に、UIWindowクラスとUIViewクラスは、異なるオブジェクトの座標系の間で相互に変換を行うメ
ソッドを備えています。

Quartzで使用される座標系は、左上隅を原点として使用しませんが、ほとんどのQuartz呼び出しで
は、それは問題になりません。ビューのdrawRect:メソッドを呼び出す前に、UIKitが、左上隅を原
点として使用するように、自動的に描画環境を設定します。この環境内で行われたQuartz呼び出し
は、ビュー内に正しく描画されます。座標系の違いを考慮する必要があるのは、Quartzを使用して
描画環境を自分でセットアップするときだけです。

座標系、Quartz、および描画全般の詳細については、「グラフィックスと描画」 (91 ページ)を


参照してください。

フレーム(frame)、境界(bounds)、および中心(center)の関係
ビューオブジェクトは、frame、bounds、およびcenterの各プロパティを使用して、そのサイズと
位置を決定します。frame(フレーム)プロパティは、親ビューの座標系に基づいて、そのビューの
位置とサイズを定義した矩形(フレーム矩形)を表します。bounds(境界)プロパティは、ビュー
固有のローカルな座標系に基づいて、ビューの位置とサイズを定義した矩形(境界矩形)を表しま
す。境界矩形の原点は、通常(0, 0)に設定されますが、必ずしもその必要はありません。center(中
心)プロパティは、フレーム矩形の中心点を表します。

frame、bounds、およびcenterの各プロパティは、コード内で異なる目的で使用します。境界矩形
は、そのビューのローカルな座標系を表すので、描画やイベント処理のコードの中で、何らかの変
化がビュー内のどこで発生したかを知る必要があるときに、最もよく使います。中心点は、ビュー

58 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

の既知の中心点を表すので、ビューの位置を操作するのに最適な方法です。フレーム矩形は、bounds
とcenterを使用して計算される便利な値です。これは、ビューの変換が、恒等変換に設定されてい
る場合にのみ有効です。

図 2-4に、フレーム矩形と境界矩形の関係を表します。右側の完全な画像は、(0, 0)を起点とする
ビューに描画されています。一方、境界のサイズが、画像全体のサイズと一致しないため、境界矩
形の外側にある画像部分だけが、自動的にクリッピングされます。このビューが親ビューと合成さ
れると、親ビュー内のビューの位置は、そのビューのフレーム矩形の原点(この例では、(5, 5))に
よって決まります。その結果、このビューのコンテンツは、親ビューの原点から右下にずれた場所
に表示されます。

図 2-4 ビューのフレームと境界の関係

Superview

Frame rectangle at (5.0, 5.0), size (73.0, 98.0) Bounds rectangle at (0.0, 0.0), size (73.0, 98.0)

ビューに対して変形がいっさい適用されない場合、ビューの位置とサイズは、上記の相互に関連す
る3つのプロパティによって決まります。ビューのframeプロパティは、initWithFrame:メソッド
を使用してビューオブジェクトをプログラミングによって作成した場合に設定されます。また、こ
のメソッドは、bounds矩形を初期化して、(0.0, 0.0)を原点として、ビューのフレームと同じサイズ
になるようにします。次に、centerプロパティが、そのフレームの中心点に設定されます。

これらのプロパティを別々に設定することもできますが、値の1つを設定すると、それ以外の値は
次のように変化します。

■ frameプロパティを設定すると、boundsプロパティのサイズは、frameプロパティのサイズと一
致するように設定されます。また、centerプロパティは、その新しいフレームの中心点に一致
するように調整されます。
■ centerプロパティを設定すると、それに応じて、frameプロパティの原点が変更されます。

■ bounds矩形のサイズを設定すると、frame矩形のサイズは、それに一致するように変更されま
す。

ほかの2つのプロパティを変えずに、boundsの原点を変更することもできます。その場合、ビュー
には、既に確認している基盤になる画像の一部が表示されます。図 2-4 (59 ページ)では、元の
boundsの原点は(0.0, 0.0)に設定されています。図 2-5では、この原点が(8.0, 24.0)に移動されていま
す。その結果、基盤になる画像の別の部分がビューに表示されます。ただし、フレーム矩形は変化
していないので、新しいコンテンツは、親ビュー内の以前と同じ位置に表示されます。

ビューのアーキテクチャとジオメトリ 59
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

図 2-5 ビューの境界の変更

注: デフォルトでは、ビューのフレームは、親ビューのフレームに合わせてクリッピングされま
せん。サブビューを強制的にクリッピングするには、親ビューのclipsToBoundsプロパティをYES
に設定します。

座標系の変換
座標系の変換は、描画をしやすくするために、ビューのdrawRect:メソッドでよく使用されますが、
iPhone OSでは、ビューに対する視覚効果を実現するために使用することもできます。たとえば、
UIViewクラスには、さまざまな種類の変換、拡大縮小効果などをビュー全体に適用できるようにす
るtransformプロパティがあります。デフォルトでは、このプロパティの値は、ビューの変更が行
われない恒等変換に設定されています。変換を追加するには、このプロパティに格納されている
CGAffineTransform構造体を取得し、該当するCore Graphics関数を使用して変換を適用します。そ
の後、変更を加えた変換構造体を、ビューのtransformプロパティに代入し直します。

注: 変換をビューに適用すると、すべての変換は、そのビューの中心点を基準にして実行されま
す。

ビューを変換すると、そのビューのコンテンツの描画に伴って、すべてのサブビューが移動しま
す。サブビューの座標系にもこれらの変換が継承されるため、拡大縮小はサブビューの描画にも影
響します。ビューのコンテンツの拡大縮小の制御方法の詳細については、「コンテンツモードと拡
大縮小」 (61 ページ)を参照してください。

重要: transformプロパティが恒等変換でない場合は、frameプロパティの値は未定義となるた
め、無視する必要があります。変換を設定した後は、boundsプロパティとcenterプロパティを使用
して、ビューの位置とサイズを取得します。

drawRect:メソッドと組み合わせて変換を使用する方法については、「座標と座標変換」 (92 ペー
ジ)を参照してください。CGAffineTransform構造体を変更するために使用する関数については、
『CGAffineTransform Reference』を参照してください。

60 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

コンテンツモードと拡大縮小
ビューの境界を変更したり、ビューのtransformプロパティに倍率を適用した場合、フレーム矩形
もそれに応じた量だけ変化します。ビューに関連付けられているコンテンツモードによって、その
ビューのコンテンツが、変更に対応するために拡大縮小されたり、再配置される場合もあります。
ビューのcontentModeプロパティによって、境界の変化および拡大縮小操作がビューに与える影響
が決まります。デフォルトでは、このプロパティの値はUIViewContentModeScaleToFillに設定さ
れています。このため、ビューのコンテンツは、常に新しいフレームサイズに合わせて拡大縮小さ
れます。たとえば、図 2-6は、ビューの水平方向の倍率を2倍にしたときの様子を示します。

図 2-6 scale-to-fillコンテンツモードを使用して拡大されたビュー

Superview

View with transform set Bounds rectangle at (0.0, 0.0), size (73.0, 98.0)

初めてビューが表示されたときに、レンダリングされたコンテンツが基盤レイヤにキャッシュされ
ているので、このビューのコンテンツは拡大されます。ビューの境界が変化したり、倍率が適用さ
れるたびに、強制的にビューそのものを再描画する代わりに、UIKitは、そのビューのコンテンツモー
ドを使用して、キャッシュされているコンテンツの表示方法を決定します。図 2-7は、異なるコン
テンツモードを使用して、ビューの境界を変更したり、ビューに倍率を適用したりした結果を比較
したものです。

ビューのアーキテクチャとジオメトリ 61
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

図 2-7 コンテンツモードの比較

UIViewContentModeScaleToFill

Distorting

UIViewContentModeScaleAspectFit

Nondistorting

UIViewContentModeScaleAspectFill

Nondistorting

拡大縮小倍率を適用すると、ビューのコンテンツは常に拡大縮小されますが、ビューの境界が変化
したときには、ビューのコンテンツを拡大縮小しないコンテンツモードもあります。
UIViewContentMode定数の中には、UIViewContentModeTopやUIViewContentModeBottomRightの
ように、現在のコンテンツを、ビューの別の角や、別の辺に沿って表示するものもあります。コン
テンツをビューの中央に表示するモードもあります。これらのコンテンツモードのいずれかに設定
した状態で、境界矩形を変更すると、既存のコンテンツは、単純に新しい境界矩形の適切な場所に
移動するだけです。

アプリケーション内にサイズ変更可能なコントロールを実装する場合は、コンテンツモードの使用
を検討します。これによって、コントロールのゆがみを回避できると同時に、カスタム描画コード
を記述しなくても済みます。ボタンや区切りのあるコントロールは、コンテンツモードに基づく描
画に特に適しています。通常、これらは複数の画像を使用してコントロールの外観を作成します。
水平方向に伸縮するボタンでは、固定サイズの2つの終端画像のほかに、1ピクセルの幅の伸縮可能
な中央画像を使用します。各画像をそれぞれのビューに表示し、伸縮可能な中央画像のコンテンツ
モードをUIViewContentModeScaleToFillに設定することによって、両端画像をゆがめることな
く、ボタンのサイズを大きくできます。さらに重要なことは、各画像ビューに関連付けられている
画像はCore Animationによってキャッシュされるので、独自の描画コードを書かなくてもアニメー
ション化できる点です。その結果パフォーマンスも向上します。

62 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

コンテンツモードは、ビューのコンテンツの再描画を避けるための優れた方法ですが、拡大縮小や
サイズ変更の操作中にビューの外観を特別に制御したい場合は、UIViewContentModeRedrawコンテ
ンツモードを使用することもできます。ビューのコンテンツモードをこの値に設定すると、コンテ
ンツの拡大縮小やサイズ変更を自動的に行う代わりに、強制的にビューのコンテンツを無効して、
ビューのdrawRect:メソッドを呼び出すように、Core Animationに指示することができます。

自動サイズ変更動作
ビューのフレーム矩形を変更した場合、通常は、それに含まれているサブビューの位置とサイズ
も、親ビューの新しいサイズに合わせて変更する必要があります。ビューのautoresizesSubviews
プロパティがYESに設定されている場合、そのビューのサブビューは、autoresizingMaskプロパ
ティの値に応じて、自動的にサイズ変更されます(デフォルトでは、autoresizesSubviewsプロパ
ティはNOに設定されているため、この機能を使用するには、この値をYESに設定する必要がありま
す)。多くの場合、ビューに対して自動サイズ変更マスクを設定するだけで、アプリケーションの
ための適切な動作が提供されます。適切な動作が提供されない場合は、layoutSubviewsメソッド
をオーバーライドして、アプリケーションの責任で、サブビューの位置とサイズを変更する必要が
あります。

ビューの自動サイズ変更動作を設定するには、ビット単位のORを使用して望みの自動サイズ変更定
数を組み合わせて、その結果をビューのautoresizingMaskプロパティに代入します。表 2-1に、自
動サイズ変更定数の一覧を示し、それぞれの定数が、ビューのサイズと配置に与える効果を説明し
ます。たとえば、ビューを親ビューの左下隅に固定するには、
UIViewAutoresizingFlexibleRightMargin定数とUIViewAutoresizingFlexibleTopMargin定数
を追加し、それをautoresizingMaskプロパティに代入します。ある軸に沿って複数の側面を可変
にした場合、サイズ変更の量は、それぞれの側面に均等に配分されます。

表 2-1 自動サイズ変更マスク定数

自動サイズ変更マスク 説明

UIViewAutoresizingNone この定数を設定すると、ビューの自動サイズ変更は行われません。

UIViewAutoresizing- この定数を設定すると、ビューの高さは、スーパービューの高さの
FlexibleHeight 変化に比例して変更されます。設定しない場合、スーパービューの
高さの変化に比例したビューの高さの変更は行われません。

UIViewAutoresizing- この定数を設定すると、ビューの幅は、スーパービューの幅の変化
FlexibleWidth に比例して変更されます。設定しない場合、スーパービューの幅の
変化に比例したビューの幅の変更は行われません。

UIViewAutoresizing- この定数を設定すると、ビューの左端は、スーパービューの幅の変
FlexibleLeftMargin 化に比例して再配置されます。設定しない場合、ビューの左端とスー
パービューの左端との距離は変更されません。

UIViewAutoresizing- この定数を設定すると、ビューの右端は、スーパービューの幅の変
FlexibleRightMargin 化に比例して再配置されます。設定しない場合、ビューの右端とスー
パービューの右端との距離は変更されません。

UIViewAutoresizing- この定数を設定すると、ビューの下端は、スーパービューの高さの
FlexibleBottomMargin 変化に比例して再配置されます。設定しない場合、ビューの下端と
スーパービューの下端との距離は変更されません。

ビューのアーキテクチャとジオメトリ 63
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

自動サイズ変更マスク 説明

UIViewAutoresizing- この定数を設定すると、ビューの上端は、スーパービューの高さの
FlexibleTopMargin 変化に比例して再配置されます。設定しない場合、ビューの上端と
スーパービューの上端との距離は変更されません。

図 2-8に、この定数値の位置を図で表します。これらの定数の1つが省略された場合、ビューのレイ
アウトはその側面については固定されます。定数がマスクに含まれていると、ビューのレイアウト
はその側面については可変になります。

図 2-8 ビューの自動サイズ変更マスク定数

(0.0, 0.0)

UIViewAutoresizingFlexibleTopMargin

UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleWidth

UIViewAutoresizingFlexibleHeight
UIViewAutoresizingFlexibleRightMargin
View

UIViewAutoresizingFlexibleBottomMargin
Superview

Interface Builderを使用して、ビューを設定する場合は、「Size」インスペクタの「Autosizing」コン
トロールを使用して、各ビューの自動サイズ変更動作を設定できます。上の図の可変の幅と高さを
表す定数は、Interface Builderの同じ場所にあるバネと同じ動作をします。マージン関係の定数は、
それと逆の動作をします。つまり、可変の右マージン自動サイズ変更動作を、Interface Builder内の
ビューに適用するには、「Autosizing」コントロールの右側のスペースを空のままにし、そこにスト
ラット(柱)を置かないようにする必要があります。幸い、Interface Builderは、自動サイズ変更動
作の変更が、ビューにどのような影響を与えるかをアニメーションとして示します。

ビューのautoresizesSubviewsプロパティがNOに設定されている場合は、そのビューの直下のサブ
ビューに設定されている自動サイズ変更動作はすべて無視されます。同様に、サブビューの自動サ
イズ変更マスクがUIViewAutoresizingNoneに設定されている場合は、そのサブビューのサイズは
変化しません。したがって、その直下のサブビューのサイズも変更されません。

注: 自動サイズ変更が正しく動作するには、ビューのtransformプロパティが恒等変換に設定され
ていなければなりません。恒等変換に設定されていない場合、自動サイズ変更動作は未定義となり
ます。

自動サイズ変更動作は、いくつかのレイアウトのニーズに適していますが、ビューのレイアウトを
より細かく制御したい場合は、適切なビュークラスのlayoutSubviewsメソッドをオーバーライド
する必要があります。ビューのレイアウト管理の詳細については、「レイアウト変更への対
応」 (72 ページ)を参照してください。

64 ビューのアーキテクチャとジオメトリ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ビュー階層の作成と管理

ユーザインターフェイスのビュー階層の管理は、アプリケーションのユーザインターフェイスの開
発において極めて重要な部分です。ビューをどのように構成するかによって、アプリケーションの
表示だけでなく、変更に対するアプリケーションの応答方法が決まります。ビュー階層の親子関係
は、アプリケーションにおいてタッチイベントの処理を担うオブジェクトのチェーンを定義するの
に役立ちます。また、親子関係は、ユーザがデバイスを回転したときに、ユーザインターフェイス
の向きの変化に応じて、各ビューのサイズと位置を変更する方法を定義するのにも寄与します。

図 2-9は、ビューをレイヤ化して、望みどおりの視覚効果を得る様子を示す簡単な例です。この「時
計(Clock)」アプリケーションでは、タブバービューとナビゲーションバービューをカスタムビュー
と合成して、インターフェイス全体を実現しています。

図 2-9 「時計(Clock)」アプリケーションのレイヤ化されたビュー

Status bar

Navigation bar

Window

Tab bar

Custom view

「時計(Clock)」アプリケーションにおけるビューのオブジェクトの関係を見ると、「ビューのレイ
ヤの変更」で示した関係に似ています。ウインドウオブジェクトが、このアプリケーションのタブ
バー、ナビゲーションバー、およびカスタムビューのルートビューとしての役割を果たします。

ビュー階層の作成と管理 65
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

図 2-10 「時計(Clock)」アプリケーションのビュー階層

UIWindow

UITabBar UINavigationBar UIView

iPhoneアプリケーションでビュー階層を作成するには、Interface Builderでグラフィカルに行う方法
や、コード内でプログラミングによる方法など、いくつかの方法があります。以降の各セクション
では、ビュー階層の組み立て方を示します。また、ビュー階層を作成した後で、階層内のビューを
検索する方法、異なるビュー座標系の間の変換を行う方法についても説明します。

ビューオブジェクトの作成
ビューを作成する最も簡単な方法は、Interface Builderを使用して、その結果生成されたnibファイル
からビューをロードすることです。Interface Builderのグラフィック環境で、ライブラリから新規
ビューをドラッグして、ウインドウまたはビューにドロップすることで、ビュー階層をすばやく作
成できます。Interface Builderは、実際のビューオブジェクトを使用するので、インターフェイスを
グラフィカルに作成すると、実行時にビューがロードされたときの様子がそのまま表示されます。
また、各ビューをビュー階層に配置して初期化するための煩雑なコードを記述する必要もありませ
ん。

Interface Builderとnibファイルを使用してビューを作成せずに、プログラミングによってビューを作
成することもできます。ビューオブジェクトを新しく作成するには、そのビューオブジェクトのた
めのメモリを割り当てて、そのオブジェクトにinitWithFrame:メッセージを送信して初期化しま
す。たとえば、UIViewクラスのインスタンスを新規に作成し、ほかのビューのコンテナとして使用
するには、次のようなコードを使用します。

CGRect viewRect = CGRectMake(0, 0, 100, 100);


UIView* myView = [[UIView alloc] initWithFrame:viewRect];

注: すべてのシステムオブジェクトは、initWithFrame:メッセージをサポートしますが、代わり
に優先して使用すべき初期化メソッドを持たせることもできます。独自の初期化メソッドの詳細に
ついては、そのクラスのリファレンス文書を参照してください。

ビューを初期化するときに指定するフレーム矩形の位置とサイズは、親ビュー候補の座標系で表し
ます。ビューを画面に表示するには、そのビューをウインドウまたは別のビューに追加する必要が
あります。それによって、UIKitは、指定されたフレーム矩形を使用して、親ビュー内にそのビュー
を配置します。ビューをビュー階層に追加する方法については、「サブビューの追加と削
除」 (66 ページ)を参照してください。

サブビューの追加と削除
Interface Builderは、ビュー階層を作成するための最も便利な方法です。これを利用すると、実行時
にビューが表示される様子をそのまま見ることができます。Interface Builderは、ビューオブジェク
トと、それらのビューの階層関係をnibファイルに保存します。システムは、実行時にこのファイル

66 ビュー階層の作成と管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

を使用して、ビューオブジェクトとその関係をアプリケーション内に再現します。nibファイルが
ロードされると、システムは、ビュー階層を再現するために必要なUIViewメソッドを自動的に呼び
出します。

Interface Builderとnibファイルを使用してビュー階層を作成したくない場合は、プログラミングに
よって作成することもできます。ビューが必須のサブビューを持つ場合は、そのビューと一緒に確
実にサブビューを作成して初期化するために、そのビューのinitWithFrame:メソッドでそれらの
サブビューを作成します。アプリケーション設計の一部ではあるが、ビュー操作のために必須では
ないサブビューは、ビューの初期化コード以外の場所で作成します。iPhoneアプリケーションで、
プログラミングによってビューやサブビューを最もよく作成する場所は、アプリケーションデリ
ゲートのapplicationDidFinishLaunching:メソッドと、View ControllerのloadViewメソッドの2つ
です。

ビュー階層内のビューを操作するには、以下のメソッドを使用します。

■ 親ビューにサブビューを追加するには、親ビューのaddSubview:メソッドを呼び出します。こ
のメソッドは、親のサブビューリストの末尾に、サブビューを追加します。
■ 親のサブビューリストの中間にサブビューを挿入するには、親ビューのinsertSubview:...メ
ソッドのいずれかを呼び出します。
■ 親ビュー内の既存のサブビューの順番を変更するには、親ビューのbringSubviewToFront:メ
ソッド、sendSubviewToBack:メソッド、または
exchangeSubviewAtIndex:withSubviewAtIndex:メソッドを呼び出します。サブビューを削除
して挿入し直すよりも、これらのメソッドを使用した方が高速です。
■ 親ビューからサブビューを削除するには、(親ビューではなく)サブビューの
removeFromSuperviewメソッドを呼び出します。

サブビューを追加すると、そのサブビューの現在のフレーム矩形が、親ビュー内でのそのビューの
初期位置として使われます。この位置は、サブビューのframeプロパティを変更することで、いつ
でも変更できます。親ビューの表示領域の外側にはみ出しているフレームを持つサブビューは、デ
フォルトではクリッピングされません。クリッピングを有効にするには、親ビューのclipsToBounds
プロパティをYESに設定する必要があります。

リスト 2-1は、アプリケーションデリゲートオブジェクトのapplicationDidFinishLaunching:メ
ソッドの例を示します。この例では、アプリケーションデリゲートが、起動時にユーザインター
フェイス全体をプログラムで作成します。このインターフェイスは、原色を表示する2つの汎用
UIViewオブジェクトで構成されます。次に、各ビューをウインドウに組み込んでいます。このウイ
ンドウもUIViewのサブクラスなので、親ビューになることができます。親はサブビューを保持する
ので、このメソッドでは、新しく作成したビューが重複して保持されることのないように、それら
を解放します。

リスト 2-1 ビューを含むウインドウの作成


- (void)applicationDidFinishLaunching:(UIApplication *)application {
// ウインドウオブジェクトを作成して
// それをアプリケーションデリゲートのwindowインスタンス変数に代入する
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.backgroundColor = [UIColor whiteColor];

// 単純な赤い四角形を作成する
CGRect redFrame = CGRectMake(10, 10, 100, 100);
UIView *redView = [[UIView alloc] initWithFrame:redFrame];
redView.backgroundColor = [UIColor redColor];

ビュー階層の作成と管理 67
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

// 単純な青い四角形を作成する
CGRect blueFrame = CGRectMake(10, 150, 100, 100);
UIView *blueView = [[UIView alloc] initWithFrame:blueFrame];
blueView.backgroundColor = [UIColor blueColor];

// これらの四角形ビューをウインドウに追加する
[window addSubview:redView];
[window addSubview:blueView];

// ビューをウインドウに追加したら、各ビューの保持カウントが
// 増えないように、そのビューを解放する
[redView release];
[blueView release];

// ウインドウを表示する
[window makeKeyAndVisible];
}

重要: メモリ管理を考慮するときには、サブビューを、ほかの任意のコレクションオブジェクト
と同等なものとして考えます。特に、addSubview:を使用して、サブビューとしてビューを挿入す
ると、そのサブビューはスーパービューによって保持されます。逆に、removeFromSuperviewメ
ソッドを使用して、スーパービューからサブビューを削除すると、そのサブビューは自動的に解放
されます。ビュー階層にビューを追加した後で、ビューを解放することによって、ビューが重複し
て保持されるのを防止できます。重複保持はメモリリークの原因になります。
Cocoaのメモリ管理規則の詳細については、『Memory Management Programming Guide for Cocoa』を
参照してください。

親ビューにサブビューが追加されると、UIKitは、何が起こっているかを知らせるために、親ビュー
と子ビューの両方にいくつかのメッセージを送信します。カスタムビューで、
willMoveToSuperview:、willMoveToWindow:、willRemoveSubview:、didAddSubview:、
didMoveToSuperview、didMoveToWindowなどのメソッドをオーバーライドして、変更が生じる前
や後にそれらに変更を処理したり、その変更に応じてビューの状態情報を更新したりできます。

ビュー階層を作成したら、ビューのsuperviewプロパティを使用してその親を取得したり、subviews
プロパティを使用してその子を取得したりできます。isDescendantOfView:メソッドを使用して、
特定のビューが、親ビューのビュー階層内に含まれているかどうかを判別することもできます。
ビュー階層のルートビューには親はないので、そのsuperviewプロパティはnilに設定されていま
す。現在オンスクリーンのビューの場合、通常は、ウインドウオブジェクトがその階層のルート
ビューです。

ビューのwindowプロパティを使用して、(もし存在すれば)そのビューを現在保持しているウイン
ドウへのポインタを取得することもできます。ビューが現在ウインドウに保持されていない場合、
このプロパティはnilに設定されます。

ビュー階層での座標の変換
しばしば、特にイベント処理の際に、アプリケーションが座標値を参照フレームから別のフレーム
に変換しなければならない場合があります。たとえば、通常、タッチイベントでは、タッチ位置を
ウインドウの座標系を使用して報告しますが、ビューオブジェクトは、ビューのローカル座標(ウ
インドウの座標系とは異なる場合がある)で、その情報を必要とします。UIViewクラスには、ビュー
のローカル座標系との間で相互に座標変換を行うために、以下のメソッドが定義されています。

68 ビュー階層の作成と管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

convertPoint:fromView:
convertRect:fromView:
convertPoint:toView:
convertRect:toView:

convert...:fromView:メソッド群は、座標をそのビューのローカル座標系に変換します。一方、
convert...:toView:メソッド群は、座標をそのビューのローカル座標系から指定されたビューの
座標系に変換します。これらのメソッドの参照ビューとしてnilを指定すると、そのビューを含ん
でいるウインドウの座標系との間での変換が行われます。

UIViewの変換メソッドのほかに、UIWindowにも、いくつかの変換メソッドが定義されています。
これらのメソッドは、ビューのローカル座標系との間での変換の代わりに、ウインドウの座標系と
の間での変換を行うということ以外は、UIViewの変換メソッドと同様です。

convertPoint:fromWindow:
convertRect:fromWindow:
convertPoint:toWindow:
convertRect:toWindow:

どちらのビューも回転していない場合や、点のみを扱う場合は、座標の変換は簡単です。回転が異
なるビューの間で矩形やサイズを変換する場合は、変換後の座標が正しくなるように、ジオメトリ
構造を適切な方法で変更しなければなりません。矩形を変換する場合、UIViewクラスは、元の画面
領域をカバーすることを前提にします。このため、変換後の矩形は、適切なビューに配置されたと
きに、元の矩形を完全に覆うよう拡大されます。図 2-11は、rotatedViewオブジェクトの座標系の
矩形を、スーパービューであるouterViewの座標系の矩形に変換する様子を示します。

図 2-11 回転したビューの値の変換

outerView
superview
subviews
frame
Rectangle in
rotatedView
coordinate system
rotatedView
superview Rectangle converted to
subviews outerView
frame coordinate system

サイズ情報を変換するとき、UIViewはサイズ情報を単純に、あるビューから別のビューに変換する
必要のある、(0.0, 0.0)からのデルタオフセットとして扱います。オフセットの距離は同じに保たれま
すが、2つの軸とのバランスは回転に応じて変化します。サイズを変換するとき、UIKitは、常にサイ
ズを正の数で返します。

ビュー階層の作成と管理 69
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ビューのタグ付け
UIViewクラスには、個々のビューオブジェクトに整数値のタグを付けるために使用できるtagプロ
パティがあります。タグを使用して、ビュー階層内のビューを一意に識別したり、実行時のこれら
のビューを検索したりできます(タグを使用した検索は、ビュー階層そのものを走査するより高速
です)。tagプロパティのデフォルト値は0です。

タグ付きのビューを検索するには、UIViewのviewWithTag:メソッドを使用します。このメソッド
は、対象ビューを起点として、深さ優先探索を使用して、そのビューのサブビューを検索します。

実行時のビューの変更

アプリケーションは、ユーザからの入力を受け取ると、それに対応してユーザインターフェイスを
変更します。アプリケーションは、インターフェイス内のビューを再配置したり、変更されたデー
タを含む既存のビューを更新したり、まったく新しいビューをロードしたりします。どの手法を使
用するかを決定する場合は、インターフェイスや、実行しようとしている内容を考慮します。ただ
し、これらの手法を開始する方法は、どのアプリケーションでも同じです。以降の各セクションで
は、これらの手法と、これらを使用して実行時にユーザインターフェイスを更新する方法について
説明します。

注: UIKitとカスタムコードの間で、どのようにイベントとメッセージがやり取りされるかについて
は、前述の「ビューの対話モデル」 (52 ページ)を参照してください。

ビューのアニメーション化
アニメーションは、ユーザインターフェイスの異なる状態の間を流れるようにビジュアルに遷移さ
せます。iPhone OSでは、ビューの位置やサイズの変更、ビューをフェードインまたはフェードアウ
トするためのアルファ値の変更などに、アニメーションが幅広く使われています。アニメーション
のサポートは、アプリケーションを使いやすくするために極めて重要です。このため、UIKitでは、
アニメーションの作成処理を簡単にするために、そのサポートが直接UIViewクラスに組み込まれて
います。

UIViewクラスには、もとからアニメーション化可能なプロパティがいくつかあります。つまり、こ
れらのプロパティが、現在の値から新しい値に変化する様子をアニメーション化するためのサポー
ト機能がビューに組み込まれています。このアニメーションの実行に必要な作業は、UIViewクラス
によって自動的に処理されますが、それにはアニメーションを実際に実行したいということをビュー
に伝える必要があります。それには、対象プロパティに対する変更をアニメーションブロックで
ラップします。

アニメーションブロックは、UIViewのbeginAnimations:context:クラスメソッドの呼び出しで始
まり、commitAnimationsクラスメソッドの呼び出しで終わります。これらの呼び出しの間で、ア
ニメーションパラメータを設定したり、アニメーション化するプロパティを変更したりします。
commitAnimationsメソッドが呼び出されるとすぐに、UIKitは、アニメーションを実行し、現在の
値から、設定したばかりの新しい値への変更をアニメーション化します。アニメーションブロック
をネストさせることもできます。ただし、ネストされたアニメーションは、一番外側のアニメー
ションブロックがコミットされるまで開始されません。

表 2-2に、UIViewクラスのアニメーション化可能なプロパティを示します。

70 実行時のビューの変更
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

表 2-2 アニメーション化可能プロパティ

プロパティ 説明

frame スーパービューの座標系で表したビューのフレーム矩形。

bounds ビューの座標系で表したビューの境界矩形。

center スーパービューの座標系で表したフレームの中心。

transform 境界の中心を基準にしてビューに適用される変換。

alpha ビューの透明度を決定するビューのアルファ値。

アニメーションパラメータの設定

アニメーションブロック内で、プロパティ値を変更することのほかに、アニメーションの進め方を
決定する追加パラメータを設定することもできます。それには、UIViewクラスの以下のメソッドを
呼び出します。

■ commitAnimationsメソッドから戻った後に、アニメーションの開始日を設定するには、
setAnimationStartDate:メソッドを使用します。デフォルトの動作では、アニメーションス
レッドですぐにアニメーションが実行されるようにスケジュールされます。
■ commitAnimationsメソッドから戻ってから、実際にアニメーションを開始するまでの遅延時間
を設定するには、setAnimationDelay:メソッドを使用します。
■ アニメーションを実行する秒数を設定するには、setAnimationDuration:メソッドを使用しま
す。
■ アニメーション実行中の、アニメーションの相対的な速度を設定するには、setAnimationCurve:
メソッドを使用します。たとえば、最初は徐々に速度を上げていき、終わりに近づくにつれて
徐々に速度を落としたり、最初から最後まで同じ速度を保ったりすることができます。
■ アニメーションの繰り返し回数を設定するには、setAnimationRepeatCount:メソッドを使用
します。
■ アニメーションが目標値に達したら、自動的に巻き戻すかどうかを設定するには、
setAnimationRepeatAutoreverses:メソッドを使用します。このメソッドを
setAnimationRepeatCount:メソッドと組み合せて使用すると、一定の時間の間に各プロパティ
を初期値と最終値の間で滑らかに切り替えることができます。

commitAnimationsクラスメソッドは、アニメーションの開始前に即座に戻ります。UIKitは、アプ
リケーションのメインイベントループとは別のスレッドで、アニメーションを実行します。
commitAnimationsメソッドは、この独立したスレッドにアニメーションをポストします。アニメー
ションは、このスレッドで実行の準備が整うまで待機させられます。デフォルトでは、Core Animation
は、現在実行中のアニメーションブロックが終了してから、待機中のアニメーションを開始しま
す。ただし、アニメーションブロック内でsetAnimationBeginsFromCurrentState:クラスメソッ
ドにYESを渡すことによって、この動作をオーバーライドして、ただちにアニメーションを開始さ
せることもできます。これにより、現在実行中のアニメーションは停止し、新規のアニメーション
が現在の状態から開始されます。

デフォルトでは、アニメーションブロック内の、アニメーション化可能なプロパティのすべての変
更がアニメーション化されます。アニメーションブロック内の一部の変更をアニメーション化した
くない場合は、setAnimationsEnabled:メソッドを使用して、一時的にアニメーションを無効にし

実行時のビューの変更 71
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

てから、変更を行い、その後でアニメーションを再度有効にします。setAnimationsEnabled:が値
NOを指定して呼び出された後に行われた変更は、同じメソッドが値YESを指定して呼び出されるか、
アニメーションブロックがコミットされるまで、アニメーション化されません。アニメーションが
現在有効になっているかどうかを判別するには、areAnimationsEnabledメソッドを使用します。

アニメーションデリゲートの設定

アニメーションブロックにデリゲートを割り当て、そのデリゲートを使用して、アニメーションの
開始時と終了時にメッセージを受信できます。これによって、アニメーションの開始直前または終
了直後に追加タスクを実行することができます。UIViewのsetAnimationDelegate:クラスメソッ
ドを使用してデリゲートを設定し、setAnimationWillStartSelector:メソッドと
setAnimationDidStopSelector:メソッドを使用して、メッセージを受信するセレクタを指定しま
す。これらのメソッドのシグニチャは、以下のとおりです。

- (void)animationWillStart:(NSString *)animationID context:(void *)context;


- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished
context:(void *)context;

両方のメソッドに渡されるanimationIDパラメータとcontextパラメータは、アニメーションブロッ
クの先頭でbeginAnimations:context:メソッドに渡されたパラメータと同じです。

■ animationID—アプリケーションが提供する文字列で、アニメーションブロック内のアニメー
ションを識別するために使用されます。
■ context—アプリケーションが提供するもう1つのオブジェクトで、追加情報をデリゲートに渡
すために使用できます。

setAnimationDidStopSelector:セレクタメソッドには、もう1つ引数(ブール値)があります。
この値は、アニメーションが最後まで実行され、別のアニメーションによって途中でキャンセルま
たは停止されなかった場合にYESになります。

レイアウト変更への対応
ビューのレイアウトが変更されるたびに、UIKitは、各ビューに自動サイズ変更動作を適用します。
そして、layoutSubviewsメソッドを呼び出して、そのビューに含まれるサブビューの配置を調整
する機会を提供します。レイアウトの変更は、以下のいずれかの場合に発生します。

■ ビューの境界矩形のサイズが変化した場合。
■ スクロールビューのコンテンツのオフセット値、つまり、表示されているコンテンツ領域の原
点が変化した場合。
■ ビューに関連付けられている変換が変化した場合。
■ ビューのレイヤに関連付けられているCore Animationのサブレイヤセットが変化した場合。
■ ビューのsetNeedsLayoutメソッドまたはlayoutIfNeededメソッドの呼び出しによって、アプ
リケーションが強制的にレイアウトを実行した場合。
■ ビューの基盤レイヤオブジェクトのsetNeedsLayoutメソッドの呼び出しによって、アプリケー
ションが強制的にレイアウトを実行した場合。

72 実行時のビューの変更
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

ビューの自動サイズ変更動作は、サブビューを配置するという最初の処理を実行します。これらの
動作を適用することによって、ビューは、意図したサイズに近くなります。自動サイズ変更動作
が、ビューのサイズと位置にどのような影響を与えるかについては、「自動サイズ変更動
作」 (63 ページ)を参照してください。

自動サイズ変更動作にすべてを任せずに、layoutSubviewsを使用して手動でサブビューのレイア
ウトを調整したい場合もあります。たとえば、複数のサブビュー要素で構成されるカスタムコント
ロールを実装している場合は、サブビューを手動で調整した方が、コントロールの外観を一定の範
囲で正確に設定できます。あるいは、スクロール可能な大きなコンテンツ領域を表すビューを、一
連のサブビューを並べることによって表示することもできます。スクロール中は、画面の一方の端
から消えたビューが再利用されて、新しいコンテンツと共にもう一方の端から表示されます。

注: layoutSubviewsメソッドを使用して、ビューのレイヤにサブレイヤとして追加されたカスタ
ムCALayerオブジェクトの位置とサイズを調整することもできます。ビューの背後にあるカスタム
レイヤ階層を管理することによって、Core Animationを直接使用した高度なアニメーションを実行で
きます。Core Animationを使用してレイヤ階層を管理する方法の詳細については、『Core Animation
Programming Guide』を参照してください。

レイアウトコードを記述する際には、アプリケーションがサポートするインターフェイスの向きご
とに、コードをテストしてください。横長と縦長の両方の向きをサポートするアプリケーションで
は、それぞれの向きでレイアウトが正しく処理されることを確認する必要があります。同様に、ア
プリケーションは、ステータスバーの高さの変更など、その他のシステム変更にも対応できるよう
にしておく必要があります。このような状況は、ユーザが通話中にアプリケーションを使用し、そ
の後その通話を切ると発生します。電話を切った時点で、管理を行うView Controllerは、ステータス
バーの縮小に合わせて、ビューのサイズを変更します。このような変更は、アプリケーション内の
残りのビューにも上から順に適用されます。

ビューのコンテンツの再描画
時々、アプリケーションのデータモデルの変更によって、それに対応するユーザインターフェイス
の変更が必要になる場合があります。このような変更を行うには、対応するビューをダーティとし
てマークし、更新が必要であることを示します(setNeedsDisplayメソッドまた
setNeedsDisplayInRect:メソッドのいずれかを使用する)。ビューをダーティとしてマークする
と、単純にグラフィックスコンテキストを作成して描画するのに比べて、システムがより効率的に
描画操作を処理できる場合があります。たとえば、特定の周期において、同じビューの複数の領域
をダーティとしてマークすると、システムはこれらのダーティ領域をひとまとめにして、そのビュー
のdrawRect:メソッドを1回呼び出します。その結果、グラフィックスコンテキストを1つ作成すれ
ば、影響を受けるすべての領域を描画できます。このやり方は、立て続けに複数のグラフィックス
コンテキストを作成するよりもはるかに効率的です。

drawRect:メソッドを実装するビューは、常に、そのメソッドに渡された矩形をチェックし、それ
を使用して描画操作の範囲を制限すべきです。描画は比較的負荷のかかる操作なので、このように
描画を制限することは、パフォーマンスを向上させるためによい方法です。

デフォルトでは、ビューのジオメトリを変更しても、ビューは自動的には再描画されません。その
代わりに、ほとんどのジオメトリ変更は、Core Animationによって自動的に処理されます。特に、
ビューのframe、bounds、center、またはtransformの各プロパティを変更した場合、Core Animation
は、そのビューのレイヤに関連付けられているキャッシュ済みのビットマップに対してジオメトリ
変更を適用します。多くの場合、このアプローチで十分です。しかし、その結果では不十分な場合
は、UIKitを使用して強制的にビューを再描画することもできます。Core Animationが暗黙のうちにジ

実行時のビューの変更 73
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

オメトリ変更を適用するのを防止するには、ビューのcontentModeプロパティを
UIViewContentModeRedrawに設定します。コンテンツモードの詳細については、「コンテンツモー
ドと拡大縮小」 (61 ページ)を参照してください。

ビューの非表示
ビューのhiddenプロパティの値を変更することによって、ビューを表示したり非表示にしたりでき
ます。このプロパティをYESに設定するとビューが非表示になり、NOに設定すると表示されます。
ビューを非表示にすると、その内部に含まれるサブビューも、それらのhiddenプロパティを設定し
たかのように、非表示になります。

ビューを非表示にしても、そのビューはビュー階層内に残っています。ただし、そのコンテンツは
表示されず、タッチイベントも受信しません。ビュー階層内に残っているため、非表示のビュー
も、自動サイズ変更やその他のレイアウト操作の対象になります。現在ファーストレスポンダに
なっているビューを非表示にした場合、そのビューが自動的にファーストレスポンダでなくなるこ
とはありません。ファーストレスポンダ宛てのイベントは、非表示のビューに送られ続けます。レ
スポンダチェーンの詳細については、「レスポンダオブジェクトとレスポンダチェーン」 (82 ペー
ジ)を参照してください。

カスタムビューの作成

UIViewクラスは、画面にコンテンツを表示したり、タッチイベントを処理したりするための基本的
な仕組みを提供します。ただし、そのインスタンスは、背景色(アルファ値を使用)とサブビュー
以外は何も描画しません。アプリケーションが、特定の方法でコンテンツを表示したり、タッチイ
ベントを処理したりする必要がある場合は、UIViewのカスタムサブクラスを作成しなければなりま
せん。

以降の各セクションでは、カスタムビューオブジェクトで実装する候補となる主なメソッドとその
動作について説明します。サブクラス化の詳細については、『UIView Class Reference』を参照してく
ださい。

カスタムビューの初期化
新規に定義するビューオブジェクトには、それぞれカスタムのinitWithFrame:メソッドを含める
必要があります。このメソッドは、作成時にクラスを初期化して、ビューオブジェクトを既知の状
態に設定する処理を担当します。コード内でプログラムによってビューのインスタンスを作成する
場合に、このメソッドを使用します。

リスト 2-2に、標準的なinitWithFrame:メソッドの実装の骨格を示します。このメソッドでは、継
承した実装を最初に呼び出します。次に、このクラスのインスタンス変数と状態情報を初期化した
後、初期化済みのオブジェクトを返します。継承した実装の呼び出しは、慣例として最初に実行さ
れます。そこで問題が発生した場合に、初期化コードを中断して、nilを返せるようにするためで
す。

リスト 2-2 ビューのサブクラスの初期化


- (id)initWithFrame:(CGRect)aRect {
self = [super initWithFrame:aRect];

74 カスタムビューの作成
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

if (self) {
// ビューの初期プロパティを設定する
...
}
return self;
}

nibファイルからカスタムビュークラスのインスタンスをロードする予定の場合は、iPhone OSでは、
nibをロードするコードが、新規のビューオブジェクトをインスタンス化するためにinitWithFrame:
メソッドを使用しないことを認識しておく必要があります。その代わりに、NSCodingプロトコルの
一部として定義されているinitWithCoder:メソッドを使用します。

たとえビューがNSCodingプロトコルを採用していたとしても、Interface Builderはそのビューのカス
タムプロパティを知らないので、それらのプロパティをnibファイルにエンコードしません。その結
果、nibファイルからクラスがロードされたときに、カスタムのinitWithCoder:メソッドは、その
クラスを正しく初期化するのに必要な情報を得ることができません。この問題を解決するには、ク
ラスにawakeFromNibメソッドを実装して、nibファイルからロードされたときに、このメソッドを
使用してクラスを明示的に初期化するようにします。

ビューのコンテンツの描画
ビューのコンテンツを変更した場合は、setNeedsDisplayメソッドまたはsetNeedsDisplayInRect:
メソッドを使用して、そのビューの一部を再描画する必要があることをシステムに通知します。ア
プリケーションが実行ループに戻ると、アプリケーションは、すべての描画要求をまとめて、更新
が必要なインターフェイス部分を計算します。次に、ビュー階層を走査して、更新が必要なビュー
にdrawRect:メッセージを送ります。この走査は、ビュー階層のルートビューから始まって下位の
サブビューへと進み、背面から前面へ向って処理します。可視領域内にカスタムコンテンツを表示
するビューには、それらのコンテンツをレンダリングするためのdrawRect:メソッドを実装する必
要があります。

ビューのdrawRect:メソッドを呼び出す前に、UIKitは、ビューの描画環境を設定します。UIKitは、
グラフィックスコンテキストを作成して、ビューの座標系と境界に合わせて、座標系とクリッピン
グ領域を調整します。したがって、drawRect:メソッドが呼び出されたときには、UIKitのクラスと
関数、Quartz関数、またはそれらの組み合わせを使用して、描画を開始するだけで済みます。現在
のグラフィックスコンテキストにアクセスする必要がある場合は、UIGraphicsGetCurrentContext
関数を使用して、そのポインタを取得できます。

重要: 現在のグラフィックスコンテキストは、ビューのdrawRect:メソッドの1回の呼び出しの間
だけ有効です。UIKitは、このメソッドが呼び出されるたびに、別のグラフィックスコンテキストを
作成します。したがって、後から使用するために、このオブジェクトをキャッシュするべきではあ
りません。

リスト 2-3に、10ピクセルの幅の赤い境界をビューの周囲に描く処理を行うdrawRect:メソッドの簡
単な実装を示します。UIKitの描画操作は、内部の実装にQuartzを使用しているので、ここで示すよ
うに描画呼び出しを組み合わせた場合でも、期待どおりの結果を得ることができます。

リスト 2-3 描画メソッド


- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect myFrame = self.bounds;

カスタムビューの作成 75
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

CGContextSetLineWidth(context, 10);

[[UIColor redColor] set];


UIRectFrame(myFrame);
}

ビューの描画コードによって、不透明なコンテンツでビューのサーフェス全体が常に覆われること
がわかっている場合は、ビューのopaqueプロパティをYESに設定することによって、描画コード全
体の効率を向上させることができます。ビューを不透明としてマークすると、UIKitは、そのビュー
のすぐ背後にあるコンテンツの描画を行いません。これによって、描画にかかる時間が削減される
だけでなく、そのコンテンツを合成するために必要な作業が最小になります。ビューが不透明なコ
ンテンツを提供する場合にのみ、このプロパティをYESに設定してください。ビューのコンテンツ
が常に不透明であることを保証できない場合は、このプロパティをNOに設定してください。

特にスクロール中の描画パフォーマンスを向上させるもう1つの方法は、ビューの
clearsContextBeforeDrawingプロパティをNOに設定することです。このプロパティをYESに設定
すると、UIKItは、drawRect:メソッドが呼び出される前に、このメソッドによって更新される予定
の領域を透明な黒で自動的に塗りつぶします。このプロパティをNOに設定すると、この塗りつぶし
操作のためのオーバーヘッドがなくなります。ただし、drawRect:メソッドに渡された更新領域内
のビューの部分を完全に再描画するのはアプリケーションの責任になります。このような最適化
は、一般に、スクロールの際に検討に値します。

イベントへの応答
UIViewクラスは、UIResponderのサブクラスです。したがって、ビューのコンテンツに対するユー
ザ操作に対応するタッチイベントを受け取れます。タッチイベントは、タッチが発生したビューで
始まり、それが処理されるまで、レスポンダチェーンに沿って受け渡しされます。ビュー自体がレ
スポンダなので、ビューはレスポンダチェーンに含まれています。したがって、関連するサブビュー
から送付されたタッチイベントを受け取ることができます。

一般に、タッチイベントを処理するビューは、以下のメソッドをすべて実装しています。これらの
詳細については、「イベント処理」 (79 ページ)を参照してください。

touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:

デフォルトでは、ビューは1度に1つのタッチイベントにしか応答しないことを忘れないでくださ
い。ユーザが2番目の指を画面に置いても、システムはそのタッチイベントを無視し、ビューに報
告しません。ビューのイベント処理メソッドから複数の指によるジェスチャを追跡したい場合は、
ビューのmultipleTouchEnabledプロパティをYESに設定して、マルチタッチイベントを有効にする
必要があります。

ラベルや画像のように、最初からイベント処理が完全に無効になっているビューもあります。ビュー
がイベントを処理するかどうかは、そのビューのuserInteractionEnabledプロパティを変更する
ことによって制御できます。時間のかかる処理を実行している間、ユーザがビューのコンテンツを
操作できないようするには、このプロパティを一時的にNOに設定します。イベントがどのビューに
も届かないようにするには、UIApplicationオブジェクトのbeginIgnoringInteractionEventsメ
ソッドとendIgnoringInteractionEventsメソッドを使用することもできます。これらのメソッド
は、1つのビューだけでなく、アプリケーション全体のイベントの配信に影響を与えます。

76 カスタムビューの作成
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

タッチイベントを処理するとき、UIKitは、UIViewのhitTest:withEvent:メソッドと
pointInside:withEvent:メソッドを使用して、タッチイベントがそのビューで発生したかどうか
を判断します。これらのメソッドをオーバーライドする必要が生じることはほとんどありません
が、ビューに独自のタッチ動作を実装するために、オーバーライドすることもできます。たとえ
ば、これらのメソッドをオーバーライドして、サブビューがタッチイベントを処理しないようにす
ることができます。

ビュー使用後のクリーンアップ
ビュークラスが、メモリを割り当てたり、カスタムオブジェクトへの参照を格納したり、ビューが
解放されたときに解放しなければならないリソースを保持したりしている場合は、deallocメソッ
ドを実装する必要があります。ビューの保持カウントが0になり、そのビュー自体が解放されると
きに、システムはdeallocメソッドを呼び出します。このメソッドの実装では、リスト 2-4に示すよ
うに、オブジェクトとそのオブジェクトが保持しているリソースを解放した後に、継承した実装を
呼び出します。

リスト 2-4 deallocメソッドの実装

- (void)dealloc {
// 保持しているUIColorオブジェクトを解放する
[color release];

// 継承した実装を呼び出す
[super dealloc];
}

カスタムビューの作成 77
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第2章
ウインドウとビュー

78 カスタムビューの作成
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章

イベント処理

iPhone OSのイベントは、Multi-Touchモデルに基づいています。ユーザは、マウスとキーボードを使
用する代わりに、デバイスの画面をタッチしてオブジェクトを操作したりデータを入力したりその
他の意図を伝えたりします。iPhone OSは、1本以上の指で画面にタッチする操作をMulti-Touchシー
ケンスの一部として認識します。このシーケンスは、最初の指が画面に触れたときに始まって、最
後に指が画面から離れたときに終わります。iPhone OSは、マルチタッチシーケンスの間中、画面に
触れている指を追跡して、それぞれのタッチの特徴を記録します。それには、画面上での指の位置
と、タッチが発生した時間が含まれます。通常、アプリケーションは、複数のタッチの特定の組み
合わせをジェスチャとして認識して、ユーザに直観的にわかる方法でそれに応答します。たとえ
ば、ピンチジェスチャに応答してコンテンツを拡大したり、フリック(はじく)ジェスチャに応答
してコンテンツをスクロールしたりします。

注: 画面上の指は、マウスポインタとはかなり異なるレベルの精度を提供します。ユーザが画面
に触れたとき、その接触領域は実際には楕円形で、ユーザ自身が触れたと考えている点の下方にず
れている傾向があります。この「接触面」はまた、どの指が画面に触れたか、指のサイズ、画面上
の指の圧力、指の向き、その他の要因などによってもサイズや形状が変わります。基盤のMulti-Touch
システムは、このすべての情報を分析し、単一のタッチポイントを計算します。

UIKitのクラスの多くは、そのクラスのオブジェクト特有の方法でマルチタッチイベントを処理しま
す。このことは、特に、UIControlのサブクラス(UIButton、UISliderなど)に当てはまります。
これらのサブクラスのオブジェクト(コントロールオブジェクトと呼ばれる)は、タップや特定の
方向へのドラッグなど、特定のタイプのジェスチャを受け付けます。正しく設定されていれば、そ
のジェスチャが発生したときに対象となるオブジェクトにアクションメッセージを送信します。UIkit
のその他のクラスは、ジェスチャを別のコンテキストで処理します。たとえば、UIScrollViewは、
Table View、Text View、そして大きなコンテンツ領域を持つその他のビューに対してスクロール動作
を提供します。

アプリケーションによっては、自分で直接イベント処理を行わずに、この動作をUIKitのクラスに任
せることもできます。ただし、UIViewのカスタムサブクラスを作成し(iPhone OSの開発ではよく
あるケースです)、そのビューを特定のタッチイベントに応答させる場合は、それらのイベントを
処理するために必要なコードを実装しなければなりません。さらに、UIKitオブジェクトに、イベン
トに対して異なる対応をさせる場合は、そのフレームワーククラスのサブクラスを作成して適切な
イベント処理メソッドをオーバーライドする必要があります。

イベントとタッチ

iPhone OSでは、タッチとは画面上での1本の指の存在または移動を表し、一意のマルチタッチシー
ケンスに属します。たとえば、ピンチ-クローズジェスチャには、画面上で2本の指がそれぞれ反対
方向から互いに近づくという2つのタッチが含まれています。タップ、ダブルタップ、フリック(画
面上を1本の指ですばやくはじく)など、1本の指の単純なジェスチャもあります。アプリケーショ
ンが、それよりも複雑なジェスチャを認識することもあります。たとえば、アプリケーションにダ
イヤル型のカスタムコントロールを備え、ユーザがそれを複数の指で回して何らかの変数の微調整
を行えるようにすることが考えられます。

イベントとタッチ 79
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

イベントは、指が画面に触れたり、画面の表面を移動したりしたときに、システムが断続的にアプ
リケーションに送信するオブジェクトです。イベントは、1つのマルチタッチシーケンスの間のす
べてのタッチのスナップショットを提供します。最も重要なのは、特定のビューへの新規のタッチ
や、変化のあったタッチです。マルチタッチシーケンスは、1本の指が最初に画面に触れたときに
始まります。それに続けて、その他の指が画面に触れたり、すべての指が画面上を移動したりする
場合もあります。シーケンスは、最後の指が画面を離れたときに終了します。アプリケーション
は、すべてのタッチの各フェーズで、イベントオブジェクトを受け取ります。

タッチには、時間的な側面と空間的な側面の両方があります。フェーズと呼ばれる時間的な側面
は、タッチが始まったばかりのとき、移動しているか静止しているか、タッチが終わったとき(指
が画面から離れたとき)を表します(図 3-1を参照)。タッチは、ビューまたはウインドウ内での
現在位置と、(必要であれば)直前の位置も持っています。1本の指が画面に触れるとそのタッチ
はウインドウおよびビューに関連付けられます。その関連付けは、イベントが存続している間ずっ
と維持されます。複数のタッチが同時に行われた場合は、それらが同じビューに関連付けられてい
る場合にのみまとめて扱われます。同様に、2つのタッチがすばやく立て続けに行われた場合はそ
れらが同じビューに関連付けられている場合にのみ、マルチタップとして扱われます。

図 3-1 マルチタッチシーケンスとタッチフェーズ

Touch 1 Touch 2 Touch 1 and 2 Touch 1 and 2


down down moved up

UITouchPhaseBegan UITouchPhaseBegan UITouchPhaseMoved UITouchPhaseEnded

iPhone OSでは、UITouchオブジェクトがタッチを表し、UIEventオブジェクトがイベントを表しま
す。1つのイベントオブジェクトには、現在のマルチタッチシーケンスを構成するすべてのタッチ
オブジェクトが含まれ、1つのビューまたはウインドウに固有のタッチオブジェクトを提供します
(図 3-2を参照)。1つのタッチオブジェクトは、1つの指に対応してシーケンスの間中、存続しま
す。また、UIKitは、その間ずっとその指を追跡しながらタッチオブジェクトを変遷させます。変遷
するタッチ属性は、タッチのフェーズ、ビュー内の位置、直前の位置、およびタイムスタンプで
す。イベント処理コードは、これらの属性を評価してイベントへの対応方法を決定します。

80 イベントとタッチ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

図 3-2 UIEventオブジェクトとそれに対応するUITouchオブジェクトの関係

UIEvent

UITouch UITouch UITouch

phase = UITouchPhaseBegan phase = UITouchPhaseMoved phase = UITouchPhaseEnded


locationInView = (35,50) locationInView = (35,20) locationInView = (120,87)

view = ViewA view = ViewA view = ViewB

システムは、いつでもマルチタッチシーケンスをキャンセルできるため、イベント処理アプリケー
ションでは適切に対応できるように備えておく必要があります。キャンセルは、電話の着信など優
先されるシステムイベントによって発生します。

イベントの送付

イベント処理のためのオブジェクトへのイベントの送付は、特定の経路に沿って行われます。「コ
アアプリケーションアーキテクチャ」 (15 ページ)で説明したように、ユーザがデバイスの画面
にタッチすると、iPhone OSは一連のタッチを認識して、それらを1つのUIEventオブジェクトにま
とめ、それを現在のアプリケーションのイベントキューに入れます。このイベントオブジェクト
は、ある時点のマルチタッチシーケンスに対応するタッチをカプセル化しています。アプリケー
ションを管理しているUIApplicationシングルトンオブジェクトは、イベントキューの先頭からイ
ベントを1つ取り出して、処理のためにそれを送付します。通常、イベントは、そのアプリケーショ
ンの中心となるウインドウ(その時点でユーザイベントの対象となっているウインドウ)に送付さ
れます。そのウインドウを表すUIWindowオブジェクトは、イベント処理のために、そのイベントを
ファーストレスポンダに送ります(ファーストレスポンダについては、「レスポンダオブジェクト
とレスポンダチェーン」で説明しています)。

アプリケーションは、ヒットテストを使用してイベントのファーストレスポンダを探します。つま
り、ビュー階層内の各ビューを対象に、hitTest:withEvent:を再帰的に(階層の下へ向かって)
呼び出して、タッチが発生したサブビューを判断します。タッチは、後からビューの外に移動した
としても、そのビューが存続する限りそのビューに関連付けられています。「イベント処理のテク
ニック」 (88 ページ)では、ヒットテストのプログラム上の注意点について説明します。

UIApplicationオブジェクトとすべてのUIWindowオブジェクトは、sendEvent:メソッドの中でイ
ベントを送付します(両方のクラスに、同じ名前のメソッドが宣言されています)。これらのメ
ソッドは、アプリケーションが受け取るイベントの入口であるため、UIApplicationまたはUIWindow
のサブクラスを作成して、sendEvent:メソッドをオーバーライドし、イベントを監視したり特殊な
イベント処理を実行したりできます。ただし、ほとんどのアプリケーションではその必要はありま
せん。

イベントの送付 81
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

レスポンダオブジェクトとレスポンダチェーン
レスポンダオブジェクトは、イベントに対応し、それを処理することができるオブジェクトです。
すべてのレスポンダオブジェクトの基本クラスは、UIResponderです。このクラスには、イベント
処理だけでなくレスポンダに共通する動作のインターフェイスが定義されています。UIApplication、
UIView、およびUIViewから派生したすべてのUIKitクラス(UIWindowを含む)は、UIResponderを
直接または間接的に継承しています。

ファーストレスポンダは、アプリケーション内で最初にタッチを受け取るレスポンダオブジェクト
(通常は、UIViewオブジェクト)です。UIWindowオブジェクトは、メッセージにイベントを含め
てファーストレスポンダに送付し、そのイベントを最初に処理する機会を与えます。このファース
トレスポンダがそのイベントを処理しない場合は、レスポンダチェーン内の次のレスポンダにイベ
ントを(メッセージに含めて)渡し、イベントを処理できるかどうかを調べます。

レスポンダチェーンとは、一連のレスポンダオブジェクトが連結されたものです。これによって、
レスポンダオブジェクトは、イベント処理の役割をほかの上位レベルのオブジェクトに委任するこ
とができます。イベントは、アプリケーションがイベントを処理できるオブジェクトを見つけるま
で、レスポンダチェーンをさかのぼります。レスポンダチェーンは、以下の順番で並べられた「次
のレスポンダ」の連鎖で構成されます。

1. ファーストレスポンダは、自身のView Controllerにイベントを渡します(View Controllerを備えて


いる場合)。次に、イベントをスーパービューに渡します。

2. 階層内の以降の各ビューも、同様に、まず自身のView Controllerにイベントを渡してから(View
Controllerを備えている場合)、スーパービューに渡します。

3. 最上位の最後のビューは、イベントをUIWindowオブジェクトに渡します。

4. UIWindowオブジェクトは、そのイベントをUIApplicationシングルトンオブジェクトに渡しま
す。

イベントを処理するレスポンダオブジェクトが見つからない場合、アプリケーションはそのイベン
トを破棄します。

レスポンダチェーン内のどのレスポンダオブジェクトもUIResponderイベント処理メソッドを実装
できるため、イベントメッセージを受け取ることができます。しかし、レスポンダは、特定のイベ
ントの処理を辞退したりイベントの一部だけを処理したりすることができます。その場合は、以下
と同様のメッセージによって、次のレスポンダにイベントメッセージを転送できます。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {


UITouch* touch = [touches anyObject];
NSUInteger numTaps = [touch tapCount];
if (numTaps < 2) {
[self.nextResponder touchesBegan:touches withEvent:event];
} else {
[self handleDoubleTap:touch];
}
}

82 イベントの送付
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

注: レスポンダが、マルチタッチシーケンスの最初のフェーズ(touchesBegan:withEvent:)のイベ
ント処理メッセージを次のレスポンダに転送した場合は、そのシーケンスのほかのすべてのイベン
ト処理メッセージを転送しなければなりません。

アクションメッセージもレスポンダチェーンを利用します。ユーザが、ボタンやページコントロー
ルなどのUIControlオブジェクトを操作すると、(正しく設定されていれば)そのコントロールオ
ブジェクトは、アクションメッセージをターゲットオブジェクトに送信します。ただし、ターゲッ
トとしてnilが指定されている場合、アプリケーションは、イベントメッセージのときと同様に、
ファーストレスポンダにこのメッセージを転送します。ファーストレスポンダがアクションメッ
セージを処理しない場合は、それが次のレスポンダに送信され、次々とレスポンダチェーンをさか
のぼります。

イベント送付の制御
UIKitは、アプリケーションでのイベント処理を容易にしたり、イベントストリームを完全にオフに
するためのプログラミング手段を提供しています。以下に、これらのアプローチの概要を示しま
す。

■ イベントの送付を停止する。デフォルトでビューはタッチイベントを受け取りますが、
userInteractionEnabledプロパティをNOに設定してイベントの受け取りを停止することがで
きます。ビューはまた、非表示であったり透過的であったりすると、イベントを受け取りませ
ん。
■ 一定時間イベントの送付を停止する。アプリケーションは、UIApplicationの
beginIgnoringInteractionEventsメソッドを呼び出して、その後で
endIgnoringInteractionEventsメソッドを呼び出すことができます。最初のメソッドによっ
て、アプリケーションはタッチイベントメッセージの受け取りを完全に停止することができま
す。2番目のメソッドを呼び出すと、マルチタッチイベントメッセージの受け取りが再開されま
す。アニメーションを実行しているときは、イベントの送付を停止したい場合などに便利です。
■ 複数タッチの送付を有効にする。デフォルトでは、ビューは、マルチタッチシーケンスの間、
最初のタッチ以外のすべてのタッチを無視します。ビューで複数のタッチを処理する場合は、
ビューに対する複数タッチを有効にする必要があります。これは、プログラムでビューの
multipleTouchEnabledプロパティにYESを設定するか、Interface Builderで関連するビューの
Inspectorを使って行うことができます。
■ イベントの送付先を1つのビューに限定する。デフォルトでは、ビューのexclusiveTouchプロ
パティはNOに設定されています。このプロパティをYESに設定すると、このビューがタッチを
追跡している間、これがウインドウの中でタッチを追跡する唯一のビューとなります。ウイン
ドウ内のほかのビューはこれらのタッチを受け取れません。ただし、このように「排他的タッ
チ」のマークが付いたビューは、同じウインドウ内の別のビューに関連付けられているタッチ
は受け取りません。排他的タッチのビューに指が触れると、そのビューがウインドウ内で指を
追跡している唯一のビューである場合にのみ、そのタッチが送付されます。非排他的ビューに
指が触れると、排他的タッチのビューで別の指が追跡されていない場合にのみタッチが送付さ
れます。
■ イベントの送付先をサブビューに限定する。UIViewのカスタムクラスで、hitTest:withEvent:
をオーバーライドして、マルチタッチイベントの送付先をサブビューに限定することができま
す。この手法に関する詳細な解説については、「イベント処理のテクニック」 (88 ページ)
を参照してください。

イベントの送付 83
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

マルチタッチイベントの処理

マルチタッチイベントを処理するには、UIViewカスタムサブクラス(または、頻度は低いけれども
UIApplicationやUIWindowのカスタムサブクラスの場合もある)が、イベント処理用のUIResponder
メソッドを少なくとも1つ実装していなければなりません。以降の各セクションでは、これらのメ
ソッドについて説明し、一般的なジェスチャの処理方法を示します。さらに、複雑なマルチタッチ
イベントを処理するレスポンダオブジェクトの例も示します。最後に、イベント処理のテクニック
をいくつか提案します。

イベント処理メソッド
1つのマルチタッチシーケンスの間、アプリケーションは一連のイベントメッセージをディスパッ
チします。これらのメッセージを受け取って処理するには、レスポンダオブジェクトのクラスに、
UIResponderで宣言されている以下のメソッドを少なくとも1つ実装している必要があります。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

タッチフェーズにおいて新しいタッチまたは変化したタッチがあったときに、アプリケーションは
以下のようなメッセージを送付します。

■ 1本以上の指が画面に触れたときは、touchesBegan:withEvent:メッセージを送ります。
■ 1本以上の指が移動したときは、touchesMoved:withEvent:メッセージを送ります。
■ 1本以上の指が画面から離れたときは、touchesEnded:withEvent:メッセージを送ります。
■ タッチシーケンスが電話の着信などのシステムイベントによってキャンセルされたときは、
touchesCancelled:withEvent:メッセージを送ります。

これらのメソッドは、それぞれ1つのタッチフェーズ(たとえば、UITouchPhaseBegan)に関連付
けられています。どのUITouchオブジェクトの場合も、phaseプロパティを評価すればフェーズがわ
かります。

イベント処理メソッドを起動するメッセージは、2つのパラメータを渡します。第1のパラメータ
は、該当するフェーズの新規タッチ、または変化のあったタッチを表すUITouchオブジェクトのセッ
トです。第2のパラメータは、この特定のイベントを表すUIEventオブジェクトです。このイベント
オブジェクトから、イベントに対応するすべてのタッチオブジェクトを取得したり(allTouches)、
特定のビューまたはウインドウに対応するタッチオブジェクトだけを抽出したサブセットを取得し
たりできます。これらのタッチオブジェクトの中には、前回のイベントメッセージ以降変化のない
タッチや、変化はあったもののフェーズが異なるタッチを表すオブジェクトも含まれます。

レスポンダオブジェクトは、1つ以上のUITouchオブジェクトをパラメータとして受け取って、それ
らのプロパティを評価したり、位置を取得したりして、特定のフェーズのイベントを頻繁に処理し
ます(タッチオブジェクトを問わなければ、NSSetオブジェクトにanyObjectメッセージを送信で
きます)。重要なメソッドの1つに、locationInView:があります。このメソッドにselfというパ
ラメータを渡すと、そのタッチの位置をレスポンダオブジェクトの座標系で取得できます(ただ
し、このレスポンダオブジェクトがUIViewであり、パラメータとして渡されたビューがnilでない
場合)。同様のメソッドによって、そのタッチの以前の位置を取得できます

84 マルチタッチイベントの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

(previousLocationInView:)。UITouchインスタンスのプロパティによって、タップの回数
(tapCount)、そのタッチが作成また最後に変化した時点(timestamp)、およびそのタッチがどのフェー
ズ(phase)に属しているかがわかります。

レスポンダクラスが、上記の3つのイベントメソッドすべてを実装している必要はありません。た
とえば、指が画面から離れたことだけを検出したい場合は、touchesEnded:withEvent:だけを実装
します。

レスポンダがマルチタッチシーケンスでイベントを処理している間に永続オブジェクトを作成する
場合は、システムがそのシーケンスをキャンセルしたときに、そのオブジェクトを破棄できるよう
に、touchesCancelled:withEvent:を実装する必要があります。通常は、外部からのイベント(た
とえば、電話の着信)によって現在のアプリケーションのイベント処理が中断されたときにキャン
セルが発生します。レスポンダオブジェクトは、マルチタッチシーケンスの最後の
touchesEnded:withEvent:を受け取ったときにも、これらのオブジェクトを破棄しなければならな
い点に注意してください(シーケンス内の最後のタッチアップを判断する方法については、「イベ
ント処理のテクニック」 (88 ページ)を参照してください)。

単一のタップジェスチャと複数のタップジェスチャの処理
iPhoneアプリケーションでよく使われるジェスチャはタップです。タップは、ユーザが自分の指で
オブジェクトを軽くたたくことを指します。レスポンダオブジェクトは、シングルタップ、ダブル
タップ、場合によってはトリプルタップに対してそれぞれ別の方法で対応できます。ユーザがレス
ポンダオブジェクトをタップした回数を判断するには、UITouchオブジェクトのtapCountプロパ
ティの値を取得します。

この値を調べるのに最適な場所は、touchesBegan:withEvent:メソッドとtouchesEnded:withEvent:
メソッドです。多くの場合、ユーザがタップして指を離したときのタッチフェーズに対応している
ため、後者のメソッドの方が適しています。このタッチアップフェーズ(UITouchPhaseEnded)での
タップ回数を調べることによって、たとえば、指が画面に触れた後でドラッグしているのではな
く、指が本当にタップしていることを確認できます。

リスト 3-1に、ビューのいずれかにダブルタップが発生したかを検出する方法を示します。

リスト 3-1 ダブルタップジェスチャの検出


- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
{
UITouch *touch = [touches anyObject];

if([touch tapCount] == 2) {
//ダブルタップジェスチャの処理
}
}

難しいのはレスポンダオブジェクトで、シングルタップおよびダブルタップジェスチャを異なる方
法で処理する場合です。たとえば、シングルタップでオブジェクトを選択し、ダブルタップで、ダ
ブルタップされた項目を編集するためのビューを表示するようなケースです。レスポンダオブジェ
クトで、シングルタップと、ダブルタップの最初のタップをどうやって区別すればよいのでしょ
う。レスポンダオブジェクトが、先に説明したイベント処理メソッドを使用して、このような状況
を処理する方法を以下に示します。

マルチタッチイベントの処理 85
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

1. touchesEnded:withEvent:で、タップ回数が1の場合、レスポンダオブジェクトは自分自身に
performSelector:withObject:afterDelay:メッセージを送ります。セレクタは、このシング
ルタップジェスチャを処理するために、このレスポンダに実装されているもう1つのメソッドを
識別します。2番目のパラメータに対応するオブジェクトは、それに関連するUITouchオブジェ
クトです。遅延は、シングルタップとダブルタップジェスチャの間の妥当な間隔にします。

2. touchesBegan:withEvent:で、タップ回数が2の場合、レスポンダオブジェクトは自分自身に
cancelPreviousPerformRequestsWithTarget:メッセージを送って、保留中の遅延実行呼び出
しをキャンセルします。タップ回数が2でない場合は、前のステップでシングルタップジェス
チャ用としてセレクタによって識別されたメソッドが遅延の後に実行されます。

3. touchesEnded:withEvent:で、タップ回数が2の場合は、レスポンダはダブルタップジェスチャ
を処理するために必要なアクションを実行します。

スワイプジェスチャの検出
水平および垂直のスワイプは、コードの中で簡単に追跡してアクションに使用できる単純なジェス
チャです。スワイプジェスチャを検出するには、望みの移動軸に沿ってユーザの指の動きを追跡す
る必要がありますが、何がスワイプを構成するのかを決めるのはデベロッパ自身です。つまり、
ユーザの指が十分な距離を移動したか、きちんと直線的に移動したか、また十分な速度で移動した
かを判断する必要があります。これは、最初のタッチの場所を保存し、それを引き続くタッチ移動
イベントで報告される位置と比較して行います。

リスト 3-2に、ビュー内での水平スワイプを検出するために使用できる基本的な追跡手法を示して
います。この例では、ビューが、タッチの開始位置をstartTouchPositionメンバ変数に保存しま
す。ユーザの指の移動に伴って、コードはタッチの現在位置と開始位置とを比較してそれがスワイ
プかどうかを判断します。タッチの垂直方向の移動が大きすぎる場合は、スワイプではないとみな
されて別の処理が行われます。しかし、指が水平の軌道をたどっている場合は、それがスワイプで
あるとみなしてコードの処理が継続します。スワイプが水平方向に十分に移動してジェスチャが完
了したと見なされたときに、処理ルーチンはアクションをトリガします。垂直方向のスワイプジェ
スチャを検出するには、xコンポーネントとyコンポーネントを入れ替えただけの同様のコードを使
用します。

リスト 3-2 ビュー内のスワイプジェスチャの追跡


#define HORIZ_SWIPE_DRAG_MIN 12
#define VERT_SWIPE_DRAG_MAX 4

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event


{
UITouch *touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event


{
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];

// スワイプが正しい軌跡をたどっている場合
if (fabsf(startTouchPosition.x - currentTouchPosition.x) >=
HORIZ_SWIPE_DRAG_MIN &&

86 マルチタッチイベントの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

fabsf(startTouchPosition.y - currentTouchPosition.y) <=


VERT_SWIPE_DRAG_MAX)
{
// スワイプだとみなす
if (startTouchPosition.x < currentTouchPosition.x)
[self myProcessRightSwipe:touches withEvent:event];
else
[self myProcessLeftSwipe:touches withEvent:event];
}
else
{
// スワイプ以外のイベントの処理
}
}

複雑なマルチタッチシーケンスの処理
タップとスワイプは単純なジェスチャです。より複雑なマルチタッチシーケンスの処理(つまり、
アプリケーション固有のジェスチャの解釈)は、アプリケーションが実行しようとしている内容に
よって異なります。全フェーズを通してすべてのタッチを追跡して、変化のあったタッチ属性を記
録し、内部状態を適切に変更しなければならない場合もあります。

複雑なマルチタッチシーケンスをどのように処理したらよいかを伝えるのに一番よい方法は、例を
示すことです。リスト 3-3に、UIViewカスタムオブジェクトでどのようにタッチに対応するかを示
します。ここでは、指の動きに合わせて「Welcome」という掲示が画面の中を動き回る様子をアニ
メーション化し、ユーザのダブルタップジェスチャに応じて「Welcome」の言語を変化させること
でタッチに対応します(このコード例は、MoveMeサンプルコードプロジェクトに由来します。この
サンプルプロジェクトを参照することで、イベント処理のコンテキストについての理解を深めるこ
とができます)。

リスト 3-3 複雑なマルチタッチシーケンスの処理


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
// タッチがplacardビューの内側で生じた場合にのみplacardビューを移動する
if ([touch view] != placardView) {
// placardビューの外側でダブルタップが生じた場合、placardの表示文字列を更新する
if ([touch tapCount] == 2) {
[placardView setupNextDisplayString];
}
return;
}
// placardビューを拡大してから縮小することによって、placardビューの"脈動"を表す
// UIViewの組み込みアニメーション機能を使用する
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
CGAffineTransform transform = CGAffineTransformMakeScale(1.2, 1.2);
placardView.transform = transform;
[UIView commitAnimations];

[UIView beginAnimations:nil context:NULL];


[UIView setAnimationDuration:0.5];
transform = CGAffineTransformMakeScale(1.1, 1.1);
placardView.transform = transform;

マルチタッチイベントの処理 87
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

[UIView commitAnimations];

// placardViewをタッチの下に移動する
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.25];
placardView.center = [self convertPoint:[touch locationInView:self]
fromView:placardView];
[UIView commitAnimations];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event


{
UITouch *touch = [[event allTouches] anyObject];

// タッチがplacardView内で生じた場合には、その位置までplacardViewを移動する
if ([touch view] == placardView) {
CGPoint location = [touch locationInView:self];
location = [self convertPoint:location fromView:placardView];
placardView.center = location;
return;
}
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event


{
UITouch *touch = [[event allTouches] anyObject];

// タッチがplacardView内で生じた場合には、中央に戻す
if ([touch view] == placardView) {
// インタラクティブ操作を無効にして、以降のタッチがアニメーションに影響しないように
する
self.userInteractionEnabled = NO;
[self animatePlacardViewToCenter];
return;
}
}

注: 一般に、処理対象のイベントに応答して自分自身を再描画するようなカスタムビューは、イ
ベント処理メソッドの中では描画状態の設定だけを行い、すべての描画処理をdrawRect:メソッド
で実行するようにします。ビューコンテンツの描画の詳細については、「グラフィックスと描
画」 (91 ページ)を参照してください。

イベント処理のテクニック
ここでは、コードで使用できるイベント処理テクニックを示します。

■ UITouchオブジェクトの変化を追跡する
イベント処理コードで、タッチの関係する状態情報を保存しておき、後で、変遷後のUITouch
インスタンスと比較することができます。たとえば、各タッチの終了位置を開始位置と比較す
る場合を考えます。touchesBegan:withEvent:メソッド内で、locationInView:メソッドから
各タッチの開始位置を取得し、UITouchオブジェクトのアドレスをキーとして使用して
CFDictionaryオブジェクトに格納できます。次に、touchesEnded:withEvent:メソッド内で、
渡された各UITouchオブジェクトのアドレスを使用して、そのオブジェクトの開始位置を取得

88 マルチタッチイベントの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

し現在位置と比較します(その際、NSDictionaryオブジェクトではなく、CFDictionaryオブ
ジェクトを使用する必要があります。NSDictionaryはキーをコピーしますが、UITouchクラス
は、オブジェクトのコピーに必要なNSCopyingプロトコルを採用しません)。
■ サブビューまたはレイヤを対象としたタッチのヒットテストを行う
カスタムビューは、タッチを受け取ったサブビューまたはレイヤを見つけて、イベントを適切
に処理するために、UIViewのhitTest:withEvent:メソッド、またはCALayerビューのhitTest:
メソッドを使用できます。次の例は、カスタムビューのレイヤ内にある「Info」画像がタップさ
れたことを検出するコードです。

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
CGPoint location = [[touches anyObject] locationInView:self];
CALayer *hitLayer = [[self layer] hitTest:[self convertPoint:location
fromView:nil]];

if (hitLayer == infoImage) {
[self displayInfo];
}
}

カスタムビューがサブビューを持つ場合は、タッチをサブビューレベルで処理するか、スーパー
ビューレベルで処理するかを判断する必要があります。サブビューにおいて、
touchesBegan:withEvent:、touchesEnded:withEvent:、またはtouchesMoved:withEvent:
を実装してタッチを処理しない場合は、これらのメッセージはレスポンダチェーンに沿ってさ
かのぼり、スーパービューに送られます。ところが、マルチタップやマルチタッチは、それら
が最初に発生したサブビューに関連付けられているため、スーパービューではこれらのタッチ
を受け取ることができません。すべての種類のタッチを確実に受け取れるようにするには、スー
パービューでhitTest:withEvent:をオーバーライドして、サブビューではなく自分自身を返
すようにします。
■ マルチタッチシーケンスの最後の指が離れたことを検出する
マルチタッチシーケンスの最後の指がビューを離れたことを検出するには、渡されたUITouch
オブジェクトの数と、渡されたUIEventオブジェクトが管理しているビューのタッチ数を比較
します。意図とは、たとえば次のようなことです。

- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
if ([touches count] == [[event touchesForView:self] count]) {
// 最後の指が離れた...
}
}

マルチタッチイベントの処理 89
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第3章
イベント処理

90 マルチタッチイベントの処理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章

グラフィックスと描画

高品質のグラフィックスは、アプリケーションのユーザインターフェイスのなかで重要な部分を占
めます。高品質のグラフィックスを提供することでアプリケーションの外観がよくなるだけでな
く、アプリケーションをシステムのほかの部分の自然な延長のように見せることができます。iPhone
OSには、システムで高品質のグラフィックスを作成できるよう、Open GLのほかに、QuartzやCore
Animation、UIKitを使用したネイティブレンダリングという、2つの手段が用意されています。

Open GLフレームワークは主に、ゲームの開発や、高フレームレートを要求するアプリケーション
を対象にしています。Open GLは、デスクトップコンピュータ上で2Dや3Dのコンテンツを作成する
ために使用する、C言語ベースのインターフェイスです。iPhone OSは、OpenGL ESフレームワークを
通じてOpenGLの描画をサポートしています。OpenGL ESフレームワークは、OpenGL ES v1.1仕様に基
づいており、特に組み込みハードウェアシステム上での使用を念頭において設計されています。こ
のバージョンは、デスクトップバージョンのOpenGLとさまざまな点で異なっています。そのため、
この章の中で後で示すアドバイスに従うようにしてください。

よりオブジェクト指向の描画手法を望むデベロッパのため、iPhone OSはQuartz、Core Animation、そ


してUIKitのグラフィックスサポート機能を提供しています。Quartzはメインの描画インターフェイ
スで、パスベースの描画、アンチエイリアスを施したレンダリング、グラデーション付き塗りつぶ
しパターン、画像、カラー、座標空間変換、PDF文書の作成、表示、解析をサポートします。UIKit
は、Quartzの画像とカラーの操作向けにObjective-Cラッパーを提供します。Core Animationは、UIKit
の多くのビュープロパティについて変更をアニメーション化するための基盤をサポートします。カ
スタムアニメーションの実装に使用することもできます。

この章では、iPhoneアプリケーションの描画プロセスの概要を取り上げます。また、サポートする
描画テクノロジーごとに、描画テクニックも紹介します。さらに、iPhone OSプラットフォームの描
画コードを最適化するためのヒントやガイダンスも示します。

UIKitのグラフィックスシステム

iPhone OSでは、OpenGL、Quartz、UIKit、またはCore Animationのいずれによるものかに関係なく、


すべての描画がUIViewオブジェクトの範囲内で実行されます。ビューは、描画が発生する、画面内
の領域を規定します。システムに用意されているビューを使用する場合、ビューの描画は自動的に
処理されます。しかし、カスタムビューを定義する場合は、自ら描画コードを用意する必要があり
ます。OpenGLを使用して描画するアプリケーションでは、レンダリングサーフェスをセットアップ
したら、OpenGLが指定する描画モデルを使用します。

Quartz、Core Animation、およびUIKitの場合、以降の各セクションで説明する描画概念を用います。

ビューの描画サイクル
UIViewオブジェクトの基本的な描画モデルでは、要求に応じてコンテンツを更新します。ただし、
UIViewクラスでは、更新要求を集め、最も適切なタイミングで描画コードに引き渡すことにより、
更新プロセスをより簡単かつ効率的に実行できます。

UIKitのグラフィックスシステム 91
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ビューの一部が再描画を必要とする場合は必ず、そのUIViewオブジェクトに組み込まれている描画
コードが、このオブジェクトのdrawRect:メソッドを呼び出します。描画コードはこのメソッドに
対し、ビューのなかで再描画が必要な部分を示す矩形を渡します。カスタムビューサブクラスでは
このメソッドをオーバーライドして、ビューのコンテンツを描画するために使用します。初めて
ビューが描画されるとき、drawRect:メソッドに渡される矩形には、ビューの表示されている領域
全体が含まれています。しかし、この矩形はその後の呼び出しでは、ビューのなかで実際に再描画
が必要な部分だけを表します。次に示すアクションは、ビュー更新のトリガとなります。

■ ビューの一部を隠している別のビューの移動または除去
■ 非表示になっていたビューの再表示(hiddenプロパティをNOに設定)
■ ビューを画面外までスクロールし、スクロールし戻す
■ ビューのsetNeedsDisplayメソッドまたはsetNeedsDisplayInRect:メソッドの明示的な呼び
出し

drawRect:メソッドを呼び出した後、ビューは自らを更新済みとしてマークを付け、新たなアクショ
ンが到着して別の更新サイクルがトリガされるのを待機します。ビューに静的コンテンツが表示さ
れている場合、必要となるのは、スクロールやほかのビューの存在によって生じる、ビューの見え
方の変化に対応することだけです。しかし、ビューのコンテンツを定期的に更新する場合は、更新
をトリガするsetNeedsDisplayメソッドまたはsetNeedsDisplayInRect:メソッドを呼び出すタイ
ミングを指定しなければなりません。たとえば、1秒あたり数回コンテンツを更新する場合、タイ
マーを設定してビューを更新することができます。ビューを更新するタイミングとしては、ユーザ
によるインタラクティブな操作やビュー内での新しいコンテンツの作成に応答したりする場合も考
えられます。

座標と座標変換
「ビューの座標系」 (57 ページ)で説明したように、ウインドウまたはビューの原点は左上隅に
置かれ、正数の座標値は原点から下および右に向かって大きくなります。描画コードを記述すると
きは、この座標系を使用して、描画対象のコンテンツの個々の点の場所を指定します。

デフォルトの座標系を変更する必要がある場合は、現在の変換行列を変更します。現在の変換行列
(CTM:Current Transformation Matrix)は数学的行列で、ビューの座標系上の点をデバイスの画面上
の点に対応づけます。ビューのdrawRect:メソッドが最初に呼び出されるとき、座標系の原点が
ビューの原点と一致し、正数の座標値が下および右に向かって大きくなるように、CTMが設定され
ます。ただし、CTMに、拡大縮小、回転、変換などの係数を追加して変更を加えて、サイズ、向き、
そして基盤になるビューやウインドウを基準にしたデフォルトの座標系の位置を変更することがで
きます。

CTMに変更を加える方法は、手間が大幅に省けるため、ビューにコンテンツを描画する標準的手法
として用いられています。現行描画システムにおいて、座標点(20, 20)から始まる10×10の正方形を
描画する場合、(20, 20)に移動するパスを作成した後、必要な直線をひととおり描画して正方形を完
成させます。ただし、この正方形を後で点(10, 10)まで移動することにした場合は、新たな開始点を
指定してパスを作成し直す必要があります。実際、原点を変更するたびにパスを作成し直す必要が
生じます。パスの作成は負担の多い操作です。これに比べて、原点が(0, 0)の正方形を作成し、望み
の描画の原点に一致するようにCTMに変更を加える処理は少ない負担で済みます。

Core Graphicsフレームワークでは、CTMに変更を加える方法は2とおりあります。CTMは、CGContext
Referenceで定義されているCTM操作関数を使用して直接変更できます。CGAffineTransform構造体
を作成し、望みの変換を適用して、その変換をCTMに反映させることもできます。アフィン変換を
使用して変換をグループとしてひとまとめにし、それらの変換をCTMに一度に適用することができ

92 UIKitのグラフィックスシステム
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ます。アフィン変換を評価、反転し、その結果を用いて、コード内の点、サイズ、矩形の値を変更
することもできます。アフィン変換の使用の詳細については、『Quartz 2D Programming Guide』およ
び『CGAffineTransform Reference』を参照してください。

グラフィックスコンテキスト
カスタムのdrawRect:メソッドを呼び出す前に、ビューオブジェクトは自動的に描画環境を設定し、
コードがただちに描画を開始できるようにします。描画環境の設定の一環として、現在の描画環境
に対応するUIViewオブジェクトはグラフィックスコンテキスト(CGContextRef不透過型)を作成
します。このグラフィックスコンテキストには、描画システムがその後の描画コマンド実行に必要
とする情報が格納されます。グラフィックスコンテキストは、描画時に使用する色、クリッピング
領域、線の幅とスタイルの情報、フォント情報、合成オプションなど、基本的な描画属性を定義し
ます。

ビュー以外の場所に描画したい場合は、カスタムのグラフィックスコンテキストオブジェクトを作
成できます。Quartzでは、この作業は主に、一連の描画コマンドを取得して、画像やPDFファイルの
作成にこれらのコマンドを使用したい場合に行います。グラフィックスコンテキストを作成するに
は、CGBitmapContextCreate関数またはCGPDFContextCreate関数を使用します。グラフィックス
コンテキストを作成したら、それをコンテンツの作成に必要な描画関数に渡すことができます。

カスタムグラフィックスコンテキストを作成する場合、そのコンテキストの座標系は、iPhone OSが
使用するネイティブの座標系とは異なります。グラフィックスコンテキストの座標系の原点は、描
画サーフェスの左上隅ではなく、左下隅に存在し、軸は上と右に伸びていきます。描画コマンドで
指定する座標は、この点を考慮する必要があります。座標系の違いを考慮しない場合、結果として
画像やPDFファイルが正しくレンダリングされない可能性があります。

重要: ビットマップまたはPDFのコンテキストを描画するときに左下の原点を使用するため、作成
されたコンテンツをビューにレンダリングするときにその座標系を補正しなければなりません。言
い換えると、画像を作成しCGContextDrawImage関数を使用して描画すると、その画像はデフォル
トのままでは上下が逆になって表示されるということです。これを修正するには、CTMのY軸を反転
(Y軸の座標に-1を乗じる)し、ビューの左下隅から左上隅へと原点を移動する必要があります。
作成するCGImageRefをUIImageオブジェクトを使用してラップする場合、CTMを修正する必要はあ
りません。UIImageオブジェクトは、CGImageRef型の反転した座標系を自動的に補正します。

グラフィックスコンテキスト、グラフィックスの状態情報の修正、グラフィックスコンテキストを
使用したカスタムコンテンツの作成の詳細については、『Quartz 2D Programming Guide』を参照して
ください。グラフィックスコンテキストに関連して用いる関数の一覧については、『CGContext
Reference』、『CGBitmapContext Reference』、『CGPDFContext Reference』を参照してください。

点とピクセル
Quartz描画システムは、ベクトルベースの描画モデルを使用します。描画コマンドが個々のピクセ
ルを処理するラスタベースの描画モデルと比較して、Quartzの描画コマンドは、ユーザ座標空間と
呼ばれる、縮尺が固定の描画空間を使用して指定されます。そしてiPhone OSは、この描画空間の座
標を、デバイスの実際のピクセルに対応させます。この描画モデルの利点は、アフィン変換を使用
して拡大縮小したときに、ベクタコマンドを使用して描画したグラフィックスの見た目がよいとい
うことです。

UIKitのグラフィックスシステム 93
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ベクトルベースの描画システム本来の精度を維持するため、描画座標は、整数値ではなく、浮動小
数点値を使用して指定します。座標に浮動小数点値を使用することにより、プログラムのコンテン
ツ位置を非常に正確に指定することができます。ほとんどの場合、これらの値が最終的にデバイス
の画面にどう対応づけられているかは心配する必要はありません。

ユーザ座標空間が、すべての描画コマンドで使用する環境となります。ユーザ座標空間は、点を単
位として表されます。デバイス座標空間とは、デバイスにとってネイティブの座標空間で、ピクセ
ルを単位として表されます。デフォルトでは、ユーザ座標空間の1個の点が、デバイス空間の1ピク
セルに対応し、点1個が160分の1インチとなります。ただし、この1対1の比率が常に当てはまるわ
けではありません。

色および色空間
iPhone OSは、Quartzで利用可能な色空間全体をサポートしていますが、ほとんどのアプリケーショ
ンで必要となるのはRGB色空間だけです。iPhone OSは組み込みハードウェアで実行され、画面にグ
ラフィックスを表示するよう設計されているため、RGB色空間はもっとも使用に適しています。

UIColorオブジェクトは、RGB、HSB、グレイスケールの値を使用してカラー値を指定できる簡易メ
ソッドを備えています。この方法で色を作成する場合、色空間を指定する必要はありません。色空
間は、UIColorオブジェクトが自動的に指定してくれます。

Core Graphicsフレームワークでは、CGContextSetRGBStrokeColor関数および
CGContextSetRGBFillColor関数を使用して色を作成し、設定することもできます。Core Graphics
フレームワークでは、ほかの色空間を使用した色の作成およびカスタム色空間の作成がサポートさ
れていますが、描画コードでこれらの色を使用することは推奨されません。描画コードでは常にRGB
カラーを使用してください。

サポートされる画像形式
表 4-1に、iPhone OSが直接サポートする画像形式の一覧を示します。これらの形式のうち、PNG形
式はアプリケーションで使用する画像形式として最もお勧めです。

表 4-1 サポートされる画像形式

形式 ファイル名拡張子

Portable Network Graphic (PNG) .png

Tagged Image File Format (TIFF) .tiff, .tif

Joint Photographic Experts Group (JPEG) .jpeg, .jpg

Graphic Interchange Format (GIF) .gif

Windows Bitmap Format (DIB) .bmp, .BMPf

Windowsアイコン形式 .ico

Windowsカーソル .cur

XWindowビットマップ .xbm

94 UIKitのグラフィックスシステム
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

描画に関するヒント

以降の各セクションでは、エンドユーザから見たアプリケーションの外観を魅力的なものにしなが
ら、質の高い描画コードを作成するためのヒントを紹介します。

カスタム描画コードを使用する場面の判断
作成するアプリケーションのタイプに応じて、カスタム描画コードをほとんど、あるいはまったく
使用しないで済ませることができます。没入型のアプリケーションでは通常、カスタム描画コード
を惜しみなく使用しますが、ユーティリティ型アプリケーションや生産性型アプリケーションであ
れば、標準のビューやコントロールを使用してコンテンツを表示できることが少なくありません。

カスタム描画コードは、表示するコンテンツを動的に変化させる必要のある場合に限定するべきで
す。たとえば、描画アプリケーションであれば、カスタム描画コードを使用してユーザの描画コマ
ンドを追跡する必要がありますし、ゲームであれば、常に変化するゲームの状況を反映するため絶
えず画面を更新することになります。これらの状況では、適切な描画テクノロジーを選択し、カス
タムビュークラスを作成してイベントを処理し、表示を適切に更新する必要があります。

一方、アプリケーションのインターフェイスの大半が固定されている場合、あらかじめインター
フェイスを1つ以上の画像ファイルにレンダリングしておき、UIImageViewオブジェクトを使用し
て、それらの画像を実行時に表示することができます。インターフェイスを構築する際に、必要に
応じてほかのコンテンツとImage View群を重ねることができます。たとえば、UILabelオブジェク
トを使用して、設定変更可能なテキストを表示し、ボタンなどのコントロールを追加して対話機能
を提供できます。

描画パフォーマンスの改善
描画は、どのプラットフォームでも比較的負荷の高い処理です。描画コードを最適化することは、
開発プロセスにおいて常に重要です。表 4-2では、描画コードをできる限り最適化するためのヒン
トを紹介します。これらのヒントに加え、コードのテスト、ホットスポットや冗長部分の除去を行
うためのパフォーマンスツールを必ず使用してください。

表 4-2 描画パフォーマンス改善のヒント

ヒント アクション

描画を最小限にする 各更新サイクルの間は、ビューのなかで実際に変更された部分だけ
を更新します。UIViewのdrawRect:メソッドを使用して描画を実行
する場合、そのメソッドに渡される更新矩形を使用することで、描
画の範囲を限定します。OpenGLによる描画の場合、自ら更新を追跡
する必要があります。

不透過なビューは不透過と コンテンツが不透過なビューの合成は、部分的に透過的なビューを
してマークする 合成する場合よりもはるかに負担が少なくて済みます。ビューを不
透過にするためには、ビューコンテンツに透明効果が含まれないよ
うにし、ビューのopaqueプロパティをYESに設定します。

描画に関するヒント 95
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ヒント アクション

不透過なPNGファイルから PNG画像の各ピクセルが不透過な場合、アルファチャネルを削除す
アルファチャネルを削除す ることにより、その画像を含むレイヤのブレンドが不要となります。
る これにより、画像の合成が大幅に簡素化され、描画パフォーマンス
が改善します。

スクロール時に表のセルと スクロール時に新たなビューを作成することはいかなる場合でも避
ビューを再利用する けてください。新しいビューを作成するのに時間を費やすと、画面
の更新に使用できる時間が少なくなり、スクロール動作が滑らかで
なくなります。

スクロール時に、前のコン デフォルトでは、UIKitはビューの現在のコンテキストバッファをク
テンツのクリアを避ける リアしてからdrawRect:メソッドを呼び出して、その同じ領域を更
新します。ビュー内のスクロールイベントに応答する場合、スクロー
ルによる更新の間に繰り返しこの領域をクリアすると、負荷が大き
くなる可能性があります。この動作を無効にするには、
clearsContextBeforeDrawingプロパティの値をNOに変更します。

描画中のグラフィックス状 グラフィックス状態の変更は、ウインドウサーバに負担がかかりま
態の変更を最小限に抑える す。類似の状態情報を利用するコンテンツを描画する必要のある場
合、そうしたコンテンツをまとめて描画し、必要な状態変更の回数
を減らすことを試みてください。

画像品質の維持
ユーザインターフェイスに高品質の画像を提供することは、設計における優先事項です。画像は、
複雑なグラフィックスを表示するとても効率的な方法です。効果的な場面では積極的に使用するべ
きです。アプリケーション用の画像を作成するときは、次のガイドラインを念頭に置くようにして
ください。

■ PNG形式の画像を使用する。PNG形式は、高品質の画像コンテンツを提供する形式で、iPhone
OSにおける推奨画像形式です。さらに、iPhone OSには、PNG画像向けに最適化された、ほかの
形式より基本的に高効率な描画パスが組み込まれています。
■ リサイズが不要となるよう画像を作成する。ある特定サイズの画像を使用する予定のある場合
は、対応する画像リソースをそのサイズで作成するようにします。拡大縮小では必要なCPUサ
イクルが増え、補間処理が必要となるため、大きめの画像を作成してから適切なサイズに縮小
する方法はとらないようにしてください。可変サイズの画像を表示する必要のある場合は、そ
の画像を異なるサイズで複数作成しておき、対象のサイズに比較的近い画像を縮小するように
します。

QuartzとUIKitを使用した描画

Quartzとは、iPhone OSにおけるネイティブウインドウサーバと描画テクノロジーを表す総称です。
Core Graphicsフレームワークは、Quartzの核を構成し、コンテンツの描画に使用される主要インター
フェイスです。このフレームワークは、以下を操作するためのデータ型と関数を提供します。

■ グラフィックスコンテキスト

96 QuartzとUIKitを使用した描画
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

■ パス
■ 画像とビットマップ
■ 透明レイヤ
■ 色、パターン色、色空間
■ グラデーションと陰影
■ フォント
■ PDFコンテンツ

UIKitは、グラフィックス関連の操作に焦点を合わせた各種クラスを提供し、Quartzの基本機能に基
づいて構成されています。UIKitのグラフィックスクラスは、描画ツールの総合セットを意図したも
のではありません。その役割はCore Graphicsがすでに担っています。代わりに、UIKitグラフィック
スクラスは、ほかのUIKitクラスの描画をサポートします。UIKitのサポート機能には、次のクラスと
関数が含まれます。

■ UIImage。画像を表示する不変クラスを実装します。

■ UIColor。デバイスカラーの基本サポートを提供します。

■ UIFont。フォント情報を必要とするクラスにフォント情報を提供します。

■ UIScreen。画面に関する基本情報を提供します。

■ UIImageオブジェクトをJPEG形式またはPNG形式で生成する関数

■ 矩形を描画する関数および描画領域をクリッピングする関数
■ 現在のグラフィックスコンテキストを変更、取得する関数

UIKitを構成するクラスとメソッドの詳細については、『UIKit Framework Reference』を参照してくだ


さい。Core Graphicsフレームワークを構成する不透過型と関数に関する詳細については、『Core
Graphics Framework Reference』を参照してください。

グラフィックスコンテキストの設定
drawRect:メソッドが呼び出されるまでに、ビューに組み込まれている描画コードはすでに、デフォ
ルトのグラフィックスコンテキストの作成と設定を完了しています。このグラフィックスコンテキ
ストへのポインタは、UIGraphicsGetCurrentContext関数を呼び出して取得できます。この関数
は、CGContextRef型への参照を返します。この参照を、Core Graphics関数に渡して現在のグラフィッ
クス状態を変更します。表 4-3に、グラフィックス状態の変更に使用する主な関数を示します。す
べての関数の一覧については、『CGContext Reference』を参照してください。この表は、UIKitに代替
できるものがあれば、それも示しています。

表 4-3 グラフィックスの状態を変更するCore Graphics関数

グラフィックスの状態 Core Graphics関数 UIKitの代替

現在の変換行列(CTM) CGContextRotateCTM なし
CGContextScaleCTM
CGContextTranslateCTM
CGContextConcatCTM

QuartzとUIKitを使用した描画 97
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

グラフィックスの状態 Core Graphics関数 UIKitの代替

クリッピング領域 CGContextClipToRect なし

線:幅、結合、キャップ、ダッ CGContextSetLineWidth なし
シュ、マイター上限 CGContextSetLineJoin
CGContextSetLineCap
CGContextSetLineDash
CGContextSetMiterLimit

曲線推定(平坦度)の精度 CGContextSetFlatness なし

アンチエイリアスの設定 CGContextSetAllowsAntialiasing なし

色:塗りつぶしとストロークの設定 CGContextSetRGBFillColor UIColorクラス


CGContextSetRGBStrokeColor

アルファ値(透明度) CGContextSetAlpha なし

レンダリングインテント CGContextSetRenderingIntent なし

色空間:塗りつぶしとストロークの CGContextSetFillColorSpace なし
設定 CGContextSetStrokeColorSpace

テキスト:フォント、フォントサイ CGContextSetFont UIFontクラス


ズ、文字間のスペース、テキスト描 CGContextSetFontSize
画モード
CGContextSetCharacterSpacing

ブレンドモード CGContextSetBlendMode UIImageクラスと各種


描画関数を使用して、
使用するブレンドモー
ドを指定することがで
きます。

グラフィックスコンテキストには、保存されたグラフィックス状態のスタックがあります。Quartz
がグラフィックスコンテキストを作成する時点で、スタックは空です。CGContextSaveGState関数
を使用すると、現在のグラフィックス状態のコピーがスタックにプッシュされます。以後、グラ
フィックス状態に加えた変更はその後の描画操作に影響を与えますが、スタックに格納されたコ
ピーには影響しません。変更が完了した時点で、CGContextRestoreGState関数を使用して、保存
されている状態をスタックの一番上からポップすることにより、前のグラフィックス状態に戻るこ
とができます。このようにグラフィックス状態をプッシュしたり、ポップしたりする方法は、前の
状態にすばやく戻る方法であり、状態の変更を個別に取り消す必要をなくします。この方法は、状
態の特定の側面(クリッピングパスなど)を元の設定に復元するただ1つの方法でもあります。

グラフィックスコンテキストの概要およびグラフィックスコンテキストを使用した描画環境の設定
については、『Quartz 2D Programming Guide』の「Graphics Contexts」を参照してください。

98 QuartzとUIKitを使用した描画
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

画像の作成と描画
iPhone OSは、UIKitとCore Graphicsフレームワークの両方を使用した画像のロードと表示をサポート
します。画像の描画に使用するクラスと関数をどのように決めるかは、画像の使用目的によって異
なります。ただし、できる限り、コード内で画像を表示するときはUIKitのクラスを使用することを
お勧めします。表 4-4に、考えられるいくつかの画像使用のシナリオと、それぞれの場合に推奨さ
れる処理方法を示します。

表 4-4 画像使用のシナリオ

シナリオ 推奨される処理方法

画像をビューのコンテン UIImageViewクラスを使用して画像をロードし、表示します。この方
ツとして表示 法は、ビューのコンテンツが画像だけの場合に使用できます。画像の
ビューの上にさらにビューのレイヤを追加して、ほかのコントロール
やコンテンツを描画することもできます。

ビューの一部分に、装飾 UIImageクラスを使用して画像をロードし、表示します。
として画像を表示

ビットマップデータを画 UIGraphicsBeginImageContext関数を使用して、画像ベースの新しい
像オブジェクトに保存 グラフィックスコンテキストを作成します。グラフィックスコンテキ
ストを作成したら、それに画像コンテンツを描画し、
UIGraphicsGetImageFromCurrentImageContext関数を使用して描画
したコンテンツに基づく画像を生成します(必要であれば、追加の画
像の描画と生成を続けます)。画像の作成が完了したら、
UIGraphicsEndImageContext関数を使用してグラフィックスコンテキ
ストを閉じます。
Core Graphicsを使用する場合は、CGBitmapContextCreate関数を使用
して、ビットマップ用のグラフィックスコンテキストを作成し、それ
に画像コンテンツを描画します。描画が完了したら、
CGBitmapContextCreateImage関数を使用し、そのビットマップコン
テキストからCGImageRefを作成します。Core Graphicsの画像を直接描
画したり、この画像を使用してUIImageオブジェクトを初期化すること
ができます。

画像をJPEGファイルまた UIImageオブジェクトを元の画像データから作成します。UIImage-
はPNGファイルとして保 JPEGRepresentation関数またはUIImagePNGRepresentation関数を呼
存 び出してNSDataオブジェクトを取得し、取得したオブジェクトのメソッ
ドを使用してデータをファイルに保存します。

次の例は、アプリケーションバンドルから画像をロードする方法を示します。画像をロードした
後、この画像オブジェクトを使用してUIImageViewオブジェクトを初期化できます。また、この画
像を保存しておき、ビューのdrawRect:メソッドの中で明示的に描画できます。

NSString* imagePath = [[NSBundle mainBundle] pathForResource:@"myImage"


ofType:@"png"];
UIImage* myImageObj = [[UIImage alloc] initWithContentsOfFile:imagePath];

QuartzとUIKitを使用した描画 99
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ビューのdrawRect:メソッドで画像を明示的に描画するときは、UIImageで利用可能な任意の描画
メソッドを使用できます。これらのメソッドでは、ビューのどこに画像を描画するかを指定できる
ため、描画の前に別途変換を作成し、適用する必要がありません。anImageというメンバ変数に、
事前にロードした画像を保存したと仮定した場合、次の例ではその画像を、ビューの座標の(10, 10)
の位置に描画します。

- (void)drawRect:(CGRect)rect
{
// 描画する
[anImage drawAtPoint:CGPointMake(10, 10)];
}

重要: CGContextDrawImage関数を使用してビットマップ画像を直接描画する場合、デフォルトで
は、描画する画像データはY軸に沿って反転します。これは、Quartzの画像が、左下隅を原点とし、
正の座標軸が原点から上方向と右方向に伸びる座標系を前提としているためです。描画の前に変換
を適用することもできますが、それよりも簡単で推奨されるQuartz画像の描画方法は、Quartz画像
をUIImageオブジェクトでラップすることです。このオブジェクトでは、座標空間の違いが自動的
に補正されます。Core Graphicsを使用した画像の作成と描画の詳細については、『Quartz 2D
Programming Guide』を参照してください。

パスの作成と描画
パスとは、連続する直線とベジェ曲線を使用して表される2Dのジオメトリシーンを記述したもので
す。UIKitには、ビュー内に矩形などの単純なパスを作成、描画するためのUIRectFrame関数と
UIRectFill関数が含まれています。Core Graphicsにも、矩形や楕円といった単純なパスを作成する
ための簡易関数が含まれています。より複雑なパスの場合、Core Graphicsフレームワークの関数を
使用して自らパスを作成する必要があります。

パスを作成するには、CGContextBeginPath関数を使用して、パスコマンドを受け取るグラフィッ
クスコンテキストを設定します。この関数を呼び出した後、ほかのパス関連関数を使用して、パス
の開始点の設定、直線や曲線の描画、矩形と楕円の追加などを実行します。パスのジオメトリを指
定し終えたら、パスを直接ペイントしたり、CGPathRefデータ型またはCGMutablePathRefデータ
型を作成し、パスへの参照をそこに保存して後で利用したりできます。

ビューにパスを描画する際には、パスのストローク、パスの塗りつぶし、またはストロークと塗り
つぶしの両方を実行できます。CGContextStrokePathなどの関数を使用してパスをストロークする
と、現在のストローク色を使用して、パスを中心とした直線が作成されます。CGContextFillPath
関数によるパスの塗りつぶしでは、現在の塗りつぶし色または塗りつぶしパターンを使用して、パ
スの線分で囲まれている領域が塗りつぶされます。

複雑なパス要素を構成する点を指定する方法を含め、パスを描画する方法の詳細については、『Quartz
2D Programming Guide』の「Paths」を参照してください。パスの作成に使用する関数については、
『CGContext Reference』および『CGPath Reference』を参照してください。

パターン、グラデーション、陰影の作成
Core Graphicsフレームワークには、パターン、グラデーション、陰影を作成する関数も用意されて
います。これらはモノクロ以外の色の作成や、作成したパスの塗りつぶしに使用します。パターン
は画像やコンテンツの繰り返しを元に作成します。グラデーションと陰影はそれぞれ、色から色へ
の滑らかな移り変わりを生み出すことができます。

100 QuartzとUIKitを使用した描画
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

パターン、グラデーション、陰影の作成と使用の詳細については、『Quartz 2D Programming Guide』


を参照してください。

OpenGL ESを使用した描画

Open Graphics Library (OpenGL)は、C言語ベースのクロスプラットフォームインターフェイスで、


デスクトップシステムにおいて2Dおよび3Dのコンテンツを作成するために使用します。通常、ゲー
ムデベロッパや、高フレームレートで描画する必要のあるユーザに使用されています。OpenGLの関
数は、点、直線、多角形などの基本構造を指定したり、テクスチャや特殊効果をこれらの構造に適
用して外見に変化を付けるために使用します。呼び出したOpenGL関数は、レンダリングを行う、基
盤となるハードウェアにグラフィックスコマンドを送信します。レンダリングはほとんどがハード
ウェアで実行されるため、通常、OpenGLの描画は非常に高速です。

OpenGL for Embedded SystemsはOpenGLの機能を一部省略したバージョンで、モバイルデバイス向け


に、最新のグラフィックスハードウェアを生かすよう設計されています。iPhone OSベースのデバイ
ス、つまりiPhoneやiPod Touch向けにOpenGLコンテンツを作成する場合は、OpenGL ESを使用しま
す。iPhone OSに提供されているOpenGL ESフレームワーク(OpenGLES.framework)は、OpenGL ES v1.1
仕様に準拠しています。OpenGL ESの詳細については、「Polygons In Your Pocket: Introducing OpenGL
ES」を参照してください。

このセクションは、iPhone OSベースのデバイス向けにOpenGL ESアプリケーションを初めて作成す


る方を対象にしています。「レンダリングサーフェスのセットアップ」 (101 ページ)では、OpenGL
ESを使用して描画可能なサーフェスを作成する手順を詳しく説明します。ただし、アプリケーショ
ン内のOpenGL ESの部分を作成する前に、「実装の詳細」 (105 ページ)を読み、iPhone OSベース
デバイスの機能とiPhone OSにおけるOpenGL ES実装の詳細について確認しておいてください。「ベ
ストプラクティス」 (103 ページ)では、アプリケーション実行の最適化に役立つ、コード作成の
ガイドラインを示します。

レンダリングサーフェスのセットアップ
OpenGL ESによる描画のセットアップは簡単で、Macintoshコンピュータ上でサーフェスに描画する
ときと同じ種類の作業を行います。主な違いは、CGLやAGLといったAPIではなく、EAGL APIを使用し
てウインドウサーフェスをセットアップする点です。EAGL APIは、iPhoneアプリケーションのウイ
ンドウやビューと、OpenGL ESレンダラとの間のインターフェイスを提供します(『OpenGL ES
Framework Reference』参照)。

Xcodeプロジェクトをセットアップするときは、必ずOpenGLES.frameworkをリンクするようにして
ください。そして、次の手順に従ってレンダリングサーフェスをセットアップします。

1. UIViewをサブクラス化し、iPhoneアプリケーションのビューをセットアップします。

2. UIViewクラスのlayerClassメソッドをオーバーライドして、CALayerオブジェクトではなく、
CAEAGLLayerオブジェクトを返すようにします。

+ (Class) layerClass
{
return [CAEAGLLayer class];
}

3. UIViewのlayerメソッドを呼び出して、ビューに関連付けられているレイヤを取得します。

OpenGL ESを使用した描画 101


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

myEAGLLayer = (CAEAGLLayer*)self.layer;

4. レイヤのプロパティを設定します。

最善のパフォーマンスを得るために、CALayerクラスが提供するopaqueプロパティを設定して、
レイヤを不透過として指定することをお勧めします。「ベストプラクティス」 (103 ページ)
を参照してください。

5. 必要な場合は、値の新しいディクショナリをCAEAGLLayerオブジェクトのdrawableProperties
プロパティに割り当てて、レンダリングサーフェスのサーフェスプロパティを設定します。

EAGLフレームワークでは、カスタムのカラーフォーマットを指定したり、ネイティブサーフェ
スが表示後にコンテンツを保持するかどうかを指定したりすることができます。ディクショナ
リ内のこれらのプロパティは、kEAGLDrawablePropertyColorFormatキーおよび
kEAGLDrawablePropertyRetainedBackingキーを使用して識別します。これらのキーの値の一
覧については、EAGLDrawableプロトコルを参照してください。

6. 描画コンテキストを管理する、新規のEAGLContextオブジェクトを作成します。このオブジェ
クトは通常、次のようにして作成し、初期化します。

EAGLContext* myContext = [[EAGLContext alloc]


initWithAPI:kEAGLRenderingAPIOpenGLES1];

複数のコンテキスト間でオブジェクト(テクスチャオブジェクト、頂点バッファオブジェクト
など)を共有したい場合は、代わりにinitWithAPI:sharegroup:初期化メソッドを使用しま
す。オブジェクトのセットを共有するコンテキストごとに、同じEAGLSharegroupオブジェクト
をsharegroupパラメータに渡します。

7. setCurrentContext:クラスメソッドを使用して、EAGLContextオブジェクトを、現在のスレッ
ドのコンテキストにします。

スレッド1つにつき、現在のコンテキストを1個割り当てることができます。

8. 新しいレンダリングバッファを作成し、GL_RENDERBUFFER_OESターゲットにバインドします
(通常、glGenRenderbufferOES関数を使用して未使用の名前を割り当てて、
glBindRenderbufferOES関数群を使用してレンダリングバッファを作成してその名前にバイン
ドするという、2段階の手順を踏みます)。

9. EAGLContextオブジェクトのrenderBufferStorage:fromDrawable:メソッドを使用して、新
しく作成したレンダリングバッファターゲットをビューのレイヤオブジェクトにアタッチしま
す(このレイヤは、レンダリングバッファの基盤となるストレージを提供します)。たとえば、
コンテキストをあらかじめ作成しておき、次のコードを使用して、ビューのレイヤ(事前に取
得し、myEAGLLayer変数に格納したレイヤ)にバッファをバインドします。

[myContext renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:myEAGLLayer];

レンダリングバッファストレージの幅、高さ、フォーマットは、
renderbufferStorage:fromDrawable:メソッドを呼び出した時点のCAEAGLLayerオブジェク
トの境界とプロパティに由来します。後でレイヤの境界を変更すると、Core Animationはデフォ
ルトでコンテンツを拡大縮小します。拡大縮小を回避するには、
renderbufferStorage:fromDrawable:を呼び出してレンダリングバッファストレージを作成
し直さなければなりません。

10. 通常通りフレームバッファを設定し、レンダリングバッファをフレームバッファのアタッチポ
イントにバインドします。

102 OpenGL ESを使用した描画


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ベストプラクティス
最善のパフォーマンスを発揮するすぐれたOpenGL ESアプリケーションを作成するには、このセク
ションで紹介するガイドラインをできるだけ守ってください。GPUの特定の機能をコードの中で活
用する方法については、「実装の詳細」 (105 ページ)も参照してください。

全般に関するガイドライン

iPhone OSベースデバイス向けにOpenGL ESアプリケーションを開発するときは、以下の項目を守っ


てください。

■ 画面とサイズが同じEAGLサーフェスを使用します。画面サイズを取得するには、UIScreenクラ
スのboundsプロパティを読み取ります。
■ EAGLウインドウサーフェスを含むCAEAGLLayerオブジェクトにCore Animation変形を適用しない
ようにします。
■ CALayerクラスのopaqueプロパティを設定し、CAEAGLLayerオブジェクトを不透過として指定
します。
■ レンダリング先のCAEAGLLayerオブジェクトの前面に、ほかのCore AnimationレイヤやUIKitビュー
を配置しないようにします。
■ アプリケーションで横長のコンテンツを表示する必要のある場合、レイヤの変換は行わないよ
うにします。その代わり、Model/View/Projection変換を変更し、glViewport関数とglScissor
関数に対する幅と高さの引数を入れ換えることで、すべてを回転するようOpenGL ESの状態を設
定します。
■ OpenGL ESと、UIKitまたはCore Animationレンダリングとの間のやり取りを最低限にします。た
とえば、UIKitやCore Animationが提供する通知、メッセージ、またはその他のユーザインター
フェイスをレンダリングしている間、OpenGL ESによるレンダリングを実行しないようにしま
す。
■ メモリの消費量を抑えます。iPhone OSベースのデバイスは、共有メモリシステムを使用しま
す。アプリケーションのグラフィックスが使用している分のメモリをシステムが利用すること
はできません。たとえば、GLテクスチャをロードした後、ピクセルデータを使用する必要がな
い場合はそのデータを解放します(「メモリ」 (107 ページ)を参照)。
■ 透明効果を実装するには、アルファテストではなく、アルファブレンドを使用します。アルファ
テストは、アルファブレンドよりもはるかに負荷のかかる処理です。
■ 使用されない、不要な機能を無効にします。たとえば、照明やブレンドの効果が必要ない場合
はこれらを無効にしておきます。
■ シザーの状態の変更を最小限に抑えます。これらの変更は、OpenGL for Mac OS Xの場合よりも、
OpenGL ES for iPhone OSにおけるほうがはるかに負荷のかかる処理となります。
■ レンダリングフレームにおいて、EAGLContextクラスのsetCurrentContext:メソッドを呼び出
す回数を最小限に抑えます。OpenGL ES for iPhone OSにおいて現在のサーフェスを変更すること
は、OpenGL for Mac OS Xの場合よりもはるかに負荷のかかる処理です。複数のコンテキストを
使用するのではなく、複数のフレームバッファオブジェクトの使用を検討してください。
■ 直前のレンダリングコマンド(glTexSubImage、glCopyTexImage、glCopyTexSubImage、
glReadPixels、glFlush、glFinish、setCurrentContext:など)の実行が完了したかどうかに
左右される操作は、レンダリングフレームの中間で実行した場合、大きな負荷がかかる可能性
があります。これらの操作が必要な場合は、フレームの先頭または最後に実行します。

OpenGL ESを使用した描画 103


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

CPUの使用率

OpenGL ESの状態を指定し直すと、CPUが無駄な作業を実行する可能性があります。そこで、CPU使
用率を減らす手法を用います。たとえば、テクスチャアトラスを使用します。これにより、テクス
チャバインディングを変更せずに、追加の描画呼び出しを実行することが可能となります。さら
に、複数の描画呼び出しを1つにまとめることができれば、CPUの処理を増やさずにすみます。テク
スチャアトラスを作成する場合は、テクスチャのバインドし直しを回避するために、状態呼び出し
を整理する必要もあります。整理しない場合、パフォーマンス上のメリットは得られません。

頂点データ

ジオメトリを作成するときは、次を参考にしてください。

■ インデックス付き三角形ストリップを使用したり、ユーザから見える分だけディテールを表示
するなどして、ジオメトリ全体を減らします。
■ 頂点数を増やさずに描画における精細なディテールを得るには、DOT3ライティングやテクス
チャの使用を検討してください。
■ メモリのバンド幅が制限されているため、データの型として、許容可能な最小の型を使用しま
す。頂点の色は、4つの符号なしバイト値を使用して指定します。テクスチャの座標は、可能で
あれば浮動小数点値の代わりに、2つまたは4つの符号なしバイト値、またはshort値で指定しま
す。

テクスチャ

テクスチャについて最善のパフォーマンスを得るには、次を実行してください。

■ できるだけ1ピクセルあたりのサイズがもっとも小さいテクスチャを使用します。可能であれ
ば、8888の代わりに565のテクスチャを使用します。
■ PVRTC形式で保存された圧縮テクスチャを使用します。GL_IMG_texture_compression_pvrtc
拡張機能については仕様を参照してください。
■ LINEAR_MIPMAP_NEARESTオプションを指定してミップマップを使用します。

■ レンダリングの前にすべてのテクスチャを作成し、ロードします。フレームのレンダリング中
にテクスチャのアップロードや修正を行わないようにします。特に、フレームの中間で
glTexSubImage関数やglCopyTexSubImage関数を呼び出さないようにします。

■ 複数のパスでテクスチャを適用するのではなく、マルチテクスチャリングを使用します。

描画の順序

描画の順序は、タイルベースの遅延レンダリングを用いるハードウェアの場合は重要です(「レン
ダリングパス」 (107 ページ)参照)。

■ オブジェクトを前面から背面へと並べ替えるために無駄なCPU時間を費やさないようにします。
GPUが用いる、タイルベースの遅延レンダリングモデルでは並べ替えが不要です。
■ 不透過オブジェクトを先に描画し、アルファブレンドオブジェクトは最後に描画します。

104 OpenGL ESを使用した描画


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

ライティング

ライティングはできる限りシンプルなものにします。

■ ライティングの使用はできるだけ控え、アプリケーションにとって最もシンプルなタイプのラ
イティングを使用します。たとえば、パフォーマンス面で負担の大きいスポットライティング
の代わりに、指向性ライトの使用を検討します。
■ 可能であれば、事前にライティングの処理を実行しておきます。静的ライティングは、動的ラ
イティングよりもパフォーマンス面で有利です。ライティングは事前に演算処理を済ませ、そ
の結果を後から参照可能なテクスチャや色配列に保存することができます。

デバッグとチューニング

Instrumentsアプリケーションには、OpenGLコードの実行時の動作に関する情報収集に使用できる、
OpenGL ES instrumentが含まれています。そのほかに、GDBのopengl_error_breakシンボルにブレー
クポイントを設定し、OpenGLエラーがいつ生成されたかを確認することができます。

実装の詳細
ハードウェアの特徴やOpenGL ESの実装の詳細を理解することは、最良のパフォーマンスを発揮す
るコードの作成に役立ちます。OpenGL ESアプリケーションを設計するときは、「ベストプラクティ
ス」 (103 ページ)の内容と共に、このセクションの情報を活用してください。

OpenGL ESの実装

iPhone OSにおけるOpenGL ESの実装は、次の点でほかのOpenGL ESの実装と異なります。

■ 最大テクスチャサイズが1024×1024です。
■ 2Dテクスチャターゲットがサポートされています。ほかのテクスチャターゲットはサポートさ
れていません。
■ ステンシルバッファは利用できません。

ハードウェアの機能

OpenGLアプリケーションを開発する場合、アプリケーションが使用する機能の有無を確認し、使用
したい機能をハードウェアがサポートしていない場合の対策を考えておくことが重要です。これは
Macintoshコンピュータにもあてはまることですが、iPhone OSベースのデバイス向けにOpenGL ESア
プリケーションを作成するときはさらに重要です。アプリケーション作成対象の特定のハードウェ
アが備える機能を理解しておくことは非常に重要です。このことを踏まえると、Macintoshコンピュー
タでOpenGLを使用する場合と異なり、iPhone OSベースデバイス向けには、次善策としてのソフト
ウェアによるレンダリングという選択肢がありません。

iPhone OSベースデバイスのグラフィックスハードウェアには次の制約があります。

■ テクスチャ拡大縮小フィルタと(テクスチャレベルにおける)拡大縮小フィルタが一致してい
なければなりません。たとえば、次のようになります。

OpenGL ESを使用した描画 105


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

❏ サポート: GL_TEXTURE_MAG_FILTER =GL_LINEAR, GL_TEXTURE_MIN_FILTER =


GL_LINEAR_MIPMAP_LINEAR

❏ サポート: GL_TEXTURE_MAG_FILTER = GL_NEAREST, GL_TEXTURE_MIN_FILTER =


GL_LINEAR_MIPMAP_NEAREST

❏ サポートなし: GL_TEXTURE_MAG_FILTER = GL_NEAREST, GL_TEXTURE_MIN_FILTER =


GL_LINEAR_MIPMAP_LINEAR

使用されることがまれな、いくつかのテクスチャ環境操作が利用できません。

■ GL_COMBINE_RGBの値がGL_MODULATEの場合、2つのオペランドの一方のみがGL_ALPHAソースか
ら読み取ることができます。
■ GL_COMBINE_RGBの値がGL_INTERPOLATE、GL_DOT3_RGB、またはGL_DOT3_RGBAの場合、ソース
のGL_CONSTANT、GL_PRIMARY_COLORと、オペランドのGL_ALPHAとの組み合わせの一部が正常
に動作しません。
■ GL_COMBINE_RGBまたはGL_COMBINE_ALPHAの値がGL_SUBTRACTの場合、GL_SCALE_RGBまたは
GL_SCALE_ALPHAは1.0でなければなりません。

■ GL_COMBINE_ALPHAの値がGL_INTERPOLATEまたはGL_MODULATEの場合、2つのソースの一方のみ
がGL_CONSTANTとなることができます。
■ GL_TEXTURE_ENV_COLORの値は、すべてのテクスチャユニットで同一でなければなりません。

サポートされる拡張機能

iPhone OSベースデバイス向けにOpenGL ESアプリケーションを開発するときに使用できるOpenGL ES


拡張機能は次のとおりです。

■ GL_OES_blend_subtract
■ GL_OES_compressed_paletted_texture
■ GL_OES_depth24
■ GL_OES_draw_texture
■ GL_OES_framebuffer_object
■ GL_OES_mapbuffer
■ GL_OES_matrix_palette
■ GL_OES_point_size_array
■ GL_OES_point_sprite
■ GL_OES_read_format
■ GL_OES_rgb8_rgba8
■ GL_OES_texture_mirrored_repeat
■ GL_EXT_texture_filter_anisotropic
■ GL_EXT_texture_lod_bias
■ GL_IMG_read_format

■ GL_IMG_texture_compression_pvrtc

106 OpenGL ESを使用した描画


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

■ GL_IMG_texture_format_BGRA8888

メモリ

OpenGL ESアプリケーションにおいて、テクスチャとサーフェスの両方で、使用メモリが24MBを超
えないようにします。この24MBは、グラフィックス専用のメモリではなく、メインのシステムメモ
リの一部を使用しています。メインメモリはほかのiPhoneアプリケーションやシステムと共有され
るため、アプリケーションが使用するメモリは最小限にする必要があります。「ベストプラクティ
ス」 (103 ページ)では、メモリを効率的に使用するためのガイドラインを示しています。なかで
も、「全般に関するガイドライン」 (103 ページ)と「頂点データ」 (104 ページ)を参照してく
ださい。

レンダリングパス

iPhoneおよびiPod touchのGPUは、PowerVR MBX Liteです。このGPUはTBDR (Tile Based Deferred


Rendering:タイルベースの遅延レンダリング)と呼ばれる手法を用いています。レンダリングのた
めのOpenGL ESコマンドを送信すると、TBDRはストリーミングレンダラとは大きく異なる動作をし
ます。ストリーミングレンダラは単に、レンダリングコマンドを1つずつ順に実行するだけです。
一方、TBDRは、多数のレンダリングコマンドが蓄積されるまでレンダリングを遅らせて、蓄積され
たコマンドリストを1つのシーンとして処理します。フレームバッファはいくつかのタイルに分割
されており、シーンは1つのタイルにつき1回描画されます。描画の際には、タイル内で実際に見え
るコンテンツだけが描画されます。TBDRによる描画は、ストリーミングレンダラと比較して、メ
リットとデメリットがいくつか存在します。これらの違いを理解しておくと、パフォーマンスにす
ぐれたソフトウェアの作成に役立てることができます。

TBDRの利点で最も重要なことは、利用可能なメモリバンド幅を非常に効率よく使用できることで
す。レンダリングを1つのタイルに限定することにより、GPUはフレームバッファのキャッシュ処理
をより効果的に行い、デプステストブレンドの効率を高めることができます。1つのタイルに限定
しない場合、フレームバッファ操作で消費されるメモリバンド幅がパフォーマンス上の大きなボト
ルネックとなってしまうことが少なくありません。

遅延レンダリングを使用すると、操作によっては負荷が大きくなることがあります。たとえば、フ
レームの途中でglTexSubImage関数を呼び出すと、蓄積されたコマンドリストにはglTexSubImage
への呼び出しの前と後の両方のコマンドが含まれる可能性があります。このコマンドリストは、テ
クスチャ画像の旧バージョンと新バージョンを両方同時に参照する必要が生じるため、テクスチャ
のごく一部を更新するだけの場合であっても、テクスチャ全体が複製されます。重複により、
glTexSubImageなどの関数は、ストリーミングレンダラの場合より遅延レンダラの方がはるかに負
荷の高い処理となる可能性があります。

PowerVR GPUは、パフォーマンスの最適化をTBDRだけに依存しているわけではなく、フラグメント
処理の前に非表示サーフェイスを削除します。ピクセルが画面に表示されないとGPUが判断すると、
GPUはテクスチャサンプリングやフラグメントカラー計算を実行せずにそのピクセルを破棄します。
非表示ピクセルを削除することで、コンテンツの一部が隠れるようなシーンにおけるパフォーマン
スが大幅に向上する可能性があります。この機能の効果をできるだけ高めるためには、シーンので
きるだけ多くの部分を不透過なコンテンツで描画し、ブレンドとアルファテストの使用を最小限に
抑えるようにします。

これら機能の実装方法とアプリケーションにおける活用方法の詳細については、『PowerVR Technol-
ogy Overview』および『PowerVR MBX 3D Application Development Recommendations』を参照してく
ださい。

OpenGL ESを使用した描画 107


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

シミュレータの機能

iPhone Simulatorは、OpenGL ES 1.1の完全かつ仕様に準拠した実装を備えており、アプリケーション


開発に使用することができます。iPhone Simulatorにおける実装は、iPhone OSベースデバイスにおけ
る実装と異なる点があります。特に、iPhone Simulatorには、「ハードウェアの機能」 (105 ページ)
で取り上げた、テクスチャ拡大縮小フィルタやテクスチャ環境操作に関する制限がありません。そ
のほかに、iPhone Simulatorは、iPhone OSベースデバイスではサポートされていないアンチエイリア
ス化された線をサポートしています。

重要: iPhone SimulatorにおけるOpenGL ESのレンダリングのパフォーマンスは、実際のデバイスに


おけるOpenGL ESのパフォーマンスと関係ないという点は重要です。iPhone Simulatorは、Macintosh
コンピュータのベクトル処理機能を利用した、最適化されたソフトウェアラスタライザを備えてい
ます。その結果、OpenGL ESコードは、実際のデバイスよりもMac OS Xで実行するほうが高速な場合
も低速な場合もあり、実行するコンピュータや描画内容によって異なります。したがって、必ず実
デバイス上で描画コードのパフォーマンスをプロファイルし、最適化することが重要で、iPhone
Simulatorが実際のパフォーマンスを反映していると考えるべきではありません。

以降の各セクションでは、iPhone Simulatorで提供されるOpenGL ESサポートに関するその他の情報


を紹介します。

サポートされる拡張機能

iPhone Simulatorは、OpenGL ES 1.1のコア機能すべてをサポートし、iPhone OSベースのデバイスがサ


ポートする拡張機能のほとんどをサポートします。ただし、次に示す拡張機能はiPhone Simulatorで
はサポートされません。

■ GL_OES_draw_texture
■ GL_OES_matrix_palette
■ GL_EXT_texture_filter_anisotropic
■ GL_IMG_texture_compression_pvrtc

ハードウェアがサポートする拡張機能の一覧については、「サポートされる拡張機能」 (106 ペー
ジ)を参照してください。

メモリ

デバイス上では、OpenGL ESアプリケーションはテクスチャとサーフェスの両方で、24MBを超える
メモリを使用できません。iPhone Simulatorはこの制限を課しません。その結果、コンピュータのレ
ンダリングハードウェアがサポートするだけのメモリを、コードが割り当てることができてしまい
ます。開発中は使用メモリのサイズを常に確認するようにしてください。

レンダリングパス

デバイスで使用されるTBDRと比べ、iPhone Simulatorのソフトウェアラスタライザは、従来からある
OpenGL ESコマンド向けのストリーミングモデルを使用しています。オブジェクトは、指定に従っ
てただちに変換され、レンダリングされます。そのため、一部の操作のパフォーマンスが、実際の
デバイスの場合と大幅に異なる可能性があります。

108 OpenGL ESを使用した描画


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

OpenGL ESの2つの異なる実装について、iPhone Simulatorがレンダリングしたピクセルとデバイスが


レンダリングしたピクセルとの間で、わずかな違いの生じる可能性があります。たとえば、OpenGL
ESでは、色の補間やテクスチャミップマップフィルタリングなど、一部の計算を近似させることが
できます。一般に、両方の実装で同じような結果が得られても、ビット単位で同一であるわけでは
ありません。

詳細情報
iPhone OSベースデバイス向けのOpenGL ESアプリケーションの開発において、必要に応じ、次に示
すリソースを参照してください。

■ 『OpenGL ES 1.X Specification』はKhronos Groupが提供する、OpenGL ESの公式の定義です。この


Webサイトにはほかにも有用な情報が掲載されています。
■ 『PowerVR MBX OpenGL ES 1.x SDK page』には、PowerVR MBXグラフィックスハードウェアがサ
ポートするOpenGL ESの実装に固有の情報が掲載されています。
■ 『OpenGL ES 1.1 Reference Pages』は、OpenGL ES仕様に関する詳細なリファレンスが掲載されて
います。アルファベット順とテーマ別の索引も用意されています。
■ 『OpenGL ES Framework Reference』は、OpenGL ESとiPhoneユーザインターフェイスとの間のイン
ターフェイスを提供する関数と定数に関する解説です。

Core Animation効果の適用

Core AnimationはObjective-Cフレームワークで、なめらかなリアルタイムアニメーションをすばやく
簡単に作成する基盤を提供します。Core Animation自体は、形状や画像、その他のタイプのコンテン
ツを作成する基本ルーチンを提供するわけではないという点で、描画テクノロジーではありませ
ん。その代わり、別のテクノロジーを使用して作成したコンテンツを操作したり、表示したりする
ためのテクノロジーであるといえます。

ほとんどのアプリケーションは、iPhone OSにおいてなんらかの形でCore Animationを利用するメリッ


トがあります。アニメーションは、今起きていることをユーザに伝えるフィードバックの働きがあ
ります。たとえば、ユーザが「設定(Settings)」アプリケーションを操作するとき、ユーザが環境設
定の下位階層に進んだり、ルート階層に戻ったりするのに合わせて、画面が視野にすべり込んだ
り、視野からすべり出たりします。この種のフィードバックは重要で、ユーザに対して文脈情報を
提供します。アニメーションは、アプリケーションの見た目を充実させる働きもあります。

ほとんどの場合、ごくわずかな労力でCore Animationのメリットを享受することができます。たとえ
ば、UIViewクラスのいくつかのプロパティ(ビューのフレーム、中心、色、不透明度など)につい
て、値が変化するとアニメーションが開始するよう設定することができます。UIKitにこれらのアニ
メーションを実行するように伝えるために、一定の作業が必要となりますが、アニメーション自体
は自動的に作成され、実行されます。組み込みのビューアニメーションをトリガする方法について
は、「ビューのアニメーション化」 (70 ページ)を参照してください。

基本アニメーションからさらに充実させるには、Core Animationのクラスやメソッドを直接扱う必要
があります。以降の各セクションでは、Core Animationに関する情報を紹介し、iPhone OSにおいて、
Core Animaitonのクラスやメソッドを使用して典型的なアニメーションを作成する方法について説明
します。Core Animationの詳細と使用方法については、『Core Animation Programming Guide』を参照
してください。

Core Animation効果の適用 109


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第4章
グラフィックスと描画

レイヤについて
Core Animationにおける重要なテクノロジーがレイヤオブジェクトです。レイヤは、ビューに性質が
よく似た軽量オブジェクトですが、実際には、表示するコンテンツのジオメトリやタイミング、視
覚的プロパティをカプセル化する、モデルオブジェクトです。コンテンツは、次に示す3つのうち、
いずれかの方法で提供されます。

■ CGImageRefをレイヤオブジェクトのcontentsプロパティに割り当てることができます。

■ デリゲートをレイヤに割り当てて、デリゲートに描画を処理させることができます。
■ CALayerをサブクラス化し、表示メソッドの1つをオーバーライドすることができます。

レイヤオブジェクトのプロパティを操作すると、実際に操作されるのはモデルレベルのデータで、
このデータによって、関連付けられているコンテンツの表示方法が決まります。そのコンテンツの
実際のレンダリングはコードとは別に処理され、高速にレンダリングされるよう徹底して最適化さ
れます。デベロッパは、レイヤコンテンツとアニメーションプロパティを設定するだけでよく、あ
とはCore Animationが引き継いで処理してくれます。

レイヤに関する情報と使用方法については、『Core Animation Programming Guide』を参照してくださ


い。

アニメーションについて
レイヤのアニメーション化では、Core Animationは独立したアニメーションオブジェクトを使用して
アニメーションのタイミングと動作を制御します。CAAnimationクラスとそのサブクラスにより、
コード内で使用可能なさまざまな種類のアニメーション動作が提供されます。ある値から別の値へ
とプロパティを移行させるシンプルなアニメーションを作成することも、指定した値とタイミング
関数を通じてアニメーションを追跡する、複雑なキーフレームアニメーションを作成することもで
きます。

Core Animationでは、複数のアニメーションをトランザクションと呼ばれる単位にまとめることもで
きます。CATransactionオブジェクトは、アニメーションのグループを1つの単位として扱います。
このクラスのメソッドを使用して、アニメーションの再生時間を設定することもできます。

カスタムアニメーションの作成例については、『Animation Types and Timing Programming Guide』を


参照してください。

110 Core Animation効果の適用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章

テキストとWeb

iPhone OSのテキストシステムは、モバイルユーザのささやかなニーズを念頭において設計されまし
た。このテキストシステムは、電子メールやSMSのプログラムでよく使われる単一行および複数行
のテキスト入力を処理するために設計されました。また、このテキストシステムはUnicodeをサポー
トし、複数の異なる入力方式を備えています。このため、様々な言語でテキストを表示したり読ん
だりしやすくなっています。

テキストとWebのサポート

iPhone OSのテキストシステムは、非常に簡単に使えるにも関わらず、絶大な威力を発揮します。
UIKitフレームワークには、テキストの表示と入力を管理するための高度なクラスがいくつか含まれ
ています。また、このフレームワークには、HTMLやJavaScriptベースのコンテンツを表示するため
のより高度なクラスも含まれています。

以降の各セクションでは、iPhone OSでのテキストとWebの基本サポートについて説明します。この
セクションで取り上げた各クラスの詳細については、『UIKit Framework Reference』を参照してくだ
さい。

Text View
UIKitフレームワークには、テキストコンテンツを表示するために、次の3つの主要なクラスがありま
す。

■ UILabel:静的なテキスト文字列を表示する

■ UITextField:編集可能な単一行のテキストを表示する

■ UITextView:編集可能な複数行のテキストを表示する

これらのクラスは、任意の大きさのテキストの表示をサポートします。ただし、Label FieldやText
Fieldは、通常、比較的小さなテキストを表示するために使われます。ただし、iPhone OSベースのデ
バイスの小さな画面で表示されたテキストを読みやすくするために、これらのクラスでは、Mac OS
Xのようなデスクトップオペレーティングシステムに見られるような高度な書式化はサポートして
いません。この3つのクラスすべてにおいて、フォント情報(サイズ、スタイルオプションなど)
を指定できます。ただし、指定したフォント情報は、そのオブジェクトに関連付けられているテキ
ストすべてに適用されます。

図 5-1は、利用可能なテキストクラスの例を画面に表示した様子を示しています。この例は、UICatalog
サンプルアプリケーションから抜粋したものです。このサンプルアプリケーションは、UIKitで利用
可能なさまざまなビューやコントロールの使い方を示しています。左の画像は、さまざまなスタイ
ルのText Fieldを示しています。右の画像は、1つのText Viewを示しています。グレーの背景に表示さ

テキストとWebのサポート 111
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

れたコールアウトは、異なるビューを表示するために使われるテーブルセル内に埋め込まれたUILabel
オブジェクトそのものです。また、左の画面の下端には、「Left View」というテキストを含むUILabel
オブジェクトがあります。

図 5-1 UICatalogアプリケーションのテキスト関連クラス

編集可能なText Viewで作業をする場合は、常に、編集セッションを管理するデリゲートオブジェク
トを提供する必要があります。デリゲートに、編集の開始と終了を知らせたり、編集動作をオー
バーライドする機会を与えるために、Text Viewはさまざま通知をデリゲートに送信します。たとえ
ば、デリゲートは、現在のテキストに有効な値が含まれているかを判別し、有効な値でない場合は
編集セッションが終了するのを防止できます。最終的に編集が終わると、デリゲートは結果のテキ
スト値を取得し、アプリケーションのデータモデルを更新します。

Text Viewは、それぞれ意図した使い方が少し異なるので、各Text Viewのデリゲートメソッドも少し


異なります。UITextFieldクラスをサポートするデリゲートは、UITextFieldDelegateプロトコル
のメソッドを実装しています。同様に、UITextViewクラスをサポートするデリゲートは、
UITextViewDelegateプロトコルのメソッドを実装しています。どちらの場合も、プロトコルメソッ

112 テキストとWebのサポート
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

ドを実装する必要はありませんが、プロトコルメソッドを実装しないと、Text Fieldがあまり役に立
たない場合もあります。これら2つのプロトコルのメソッドの詳細については、『UITextFieldDelegate
Protocol Reference』および『UITextViewDelegate Protocol Reference』を参照してください。

Web View
UIWebViewクラスを利用すると、事実上、小型のWebブラウザをアプリケーションのユーザインター
フェイスに組み込むことができます。UIWebViewクラスは、HTML、CSS、およびJavaScriptコンテン
ツを完全にサポートする、iPhone OSの「Safari」を実装するために使われているのと同じWebテクノ
ロジーを完全に利用しています。また、このクラスは、「Safari」でユーザに親しまれている、たく
さんの組み込みジェスチャーもサポートしています。たとえば、ページをダブルクリックまたはピ
ンチすると拡大や縮小ができます。また、指をドラッグするとページをスクロールできます。

コンテンツを表示することのほかに、Web Viewオブジェクトを使用すると、Webフォームを使用し
てユーザからの入力を収集することもできます。UIKitのその他のテキストクラスと同様に、Webペー
ジ内のフォームに編集可能なText Fieldがある場合は、そのフィールドをタップすると、テキスト入
力用のキーボードが表示されます。これは、Web体験には不可欠な部分なので、キーボードの表示
と非表示はWeb Viewが自ら管理します。

図 5-2は、UiKitで利用可能なさまざまなビューとコントロールの使い方を示す、UICatalogサンプルア
プリケーションから抜粋したUIWebViewオブジェクトの例を示しています。HTMLコンテンツを表示
するだけなので、Webブラウザのようにユーザがページを移動できるようにするには、そのための
コントロールを追加する必要があります。たとえば、この図のWeb Viewは、ターゲットURLを含む
Text Fieldの下の領域を占有しており、このText Fieldそのものは含んでいません。

テキストとWebのサポート 113
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

図 5-2 Web View

UIWebView object

Web Viewは、それに関連付けられたデリゲートオブジェクトを通して、いつページがロードされた
かと、ロードエラーがあったかどうかについての情報を提供します。Webデリゲートは、1つ以上の
UIWebViewDelegateプロトコルメソッドを実装したオブジェクトです。デリゲートメソッドを実装
することによって、エラーに応答したり、Webページのロードに関連するその他のタスクを実行し
たりできます。UIWebViewDelegateプロトコルのメソッドの詳細については、『UIWebViewDelegate
Protocol Reference』を参照してください。

キーボードと入力方法
テキスト入力を受け付けることができるオブジェクト内でユーザがタップすると、そのオブジェク
トは、適切なキーボードを表示するようシステムに依頼します。プログラムのニーズとユーザが希
望する言語に応じて、システムは、複数の異なるキーボードの中の1つを表示します。アプリケー
ションでは、ユーザが希望する言語(およびキーボードの入力方法)を制御することはできません
が、ユーザが意図した使い方を示すキーボードの属性(特殊キーの設定とその動作など)を制御す
ることはできます。

114 テキストとWebのサポート
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

アプリケーションのテキストオブジェクトを利用して、キーボードの属性を直接設定します。
UITextFieldクラスとUITextViewクラスは共に、キーボード設定用のプロパティを定義する
UITextInputTraitsプロトコルに従います。プログラムやInterface BuilderのInspectorウインドウで
これらのプロパティを設定すると、システムは、指定されたタイプのキーボードを表示します。

注: UIWebViewクラスは、UITextInputTraitsプロトコルを直接的にはサポートしませんが、テ
キスト入力要素用にいくつかのキーボード属性を設定できます。特に、次の例のように入力要素の
定義にautocorrect属性とautocapitalization属性を含めると、キーボードの動作を指定できま
す。
<input type="text" size="30" autocorrect="off" autocapitalization="on">

入力要素にキーボードタイプを指定することはできません。Web Viewは、デフォルトのキーボード
を基に、要素間のナビゲーション用のコントロールを追加したカスタムキーボードを表示します。

デフォルトのキーボードは、一般的なテキスト入力用に設計されています。図 5-3は、異なるキー
ボード設定を持つデフォルトキーボードを示しています。デフォルトキーボードには、最初アル
ファベットキーボードが表示されますが、ユーザはそれを切り替えて、数字と記号を表示すること
もできます。その他のキーボードのほとんどは、デフォルトキーボードと同様の機能を提供します
が、特定のタスクに特化した追加ボタンを提供します。ただし、電話と数字のキーボードは、数字
入力がしやすいように大幅に異なるレイアウトになっています。

図 5-3 さまざまなキーボードタイプ

Default Email

URL Phone

さまざまなユーザの言語環境設定を容易にするために、iPhone OSは、さまざまな入力方式とさまざ
まな言語用のキーボードレイアウトをサポートしています。そのいくつかを図 5-4に示します。入
力方式とキーボードレイアウトは、ユーザの言語環境設定によって決まります。

テキストとWebのサポート 115
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

図 5-4 さまざまなキーボードと入力方式

English Russian Korean

Japanese - Romanji Japanese - Kana Chinese - Handwriting

キーボードの管理

多くのUIKitオブジェクトは、ユーザとの対話に応答して自動的にキーボードを表示しますが、キー
ボードを設定したり管理する責任の一部はアプリケーションにあります。以降の各セクションで
は、これらの責務について説明します。

キーボード通知を受信する
キーボードが表示または非表示になると、iPhone OSは、登録されているオブザーバに以下の通知を
送信します。

116 キーボードの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

■ UIKeyboardWillShowNotification

■ UIKeyboardDidShowNotification

■ UIKeyboardWillHideNotification

■ UIKeyboardDidHideNotification

キーボードが最初に表示されたとき、キーボードが消えたとき、キーボードの所有者が変わったと
き、またはアプリケーションの向きが変わったときに、システムはキーボード通知を送信します。
それぞれの状況で、システムは、これらのメッセージの適切なサブセットのみを送信します。たと
えば、キーボードの所有者が変わった場合、システムは現在の所有者に
UIKeyboardWillHideNotificationメッセージを送信しますが、UIKeyboardDidHideNotification
メッセージは送信しません。それは、この変更によってキーボードが非表示にならないからです。
UIKeyboardWillHideNotificationの送付は、キーボードフォーカスを失うおうとしている現在の
所有者に警告を与える単純な方法です。一方、キーボードの向きが変わると、willHideとdidHideの
両方の通知が送信されます。これは、それぞれの向きでキーボードが異なるので、新しいキーボー
ドを表示する前に元のキーボードを消去する必要があるからです。

各キーボード通知には、画面上のキーボードのサイズと位置についての情報が含まれています。
キーボードが特定のサイズ、または特定の場所にあると仮定するのではなく、これらの通知の情報
を常に使用すべきです。キーボードのサイズは、どの入力方式でも同じであるとは限りません。ま
た、iPhone OSのリリースの違いによって異なる場合もあります。さらに、同じ言語で同じシステム
リリースの場合ですら、アプリケーションの向きによってキーボードの寸法が変わる可能性があり
ます。たとえば、図 5-5は、縦長モードと横長モードの両方のURLキーボードのサイズの比較を示し
ています。キーボード通知内の情報を使用することによって、正しいサイズと位置の情報を確実に
取得できます。

図 5-5 縦長モードと横長モードのキーボードサイズの比較

162 pixels
216 pixels

480 pixels

320 pixels

キーボードの管理 117
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

注: 情報ディクショナリのUIKeyboardBoundsUserInfoKeyに含まれる矩形は、サイズ情報のため
だけに使用すべきです。キーボードはアニメーションによって配置されるので、キーボードの実際
の境界矩形は時間とともに変化します。したがって、キーボードの開始位置と終了位置は、情報
ディクショナリのUIKeyboardCenterBeginUserInfoKeyキーとUIKeyboardCenterEndUserInfoKey
キーの下に格納されます。

キーボード通知を使用する理由の1つは、キーボードが表示されたときに、キーボードによって隠
されるコンテンツを再配置できるからです。このシナリオの処理方法については、「キーボードの
下に隠れているコンテンツを移動する」 (119 ページ)を参照してください。

キーボードを表示する
ユーザがビューをタップすると、システムは自動的にそのビューをファーストレスポンダとして指
名します。編集可能なテキストを含むビューに対してこのイベントが発生すると、そのビューは対
象テキストの編集セッションを起動します。キーボードがまだ表示されていない場合は、編集セッ
ションの最初に、ビューはキーボードの表示をシステムに依頼します。キーボードが既に表示され
ている場合は、ファーストレスポンダ内の変更によって、キーボードからのテキスト入力は新たに
タップされたビューにリダイレクトされます。

ビューがファーストレスポンダになるとキーボードは自動的に表示されるので、通常は、キーボー
ドを表示するために何らかの処理を実行する必要はありません。ただし、編集可能なテキストビュー
のbecomeFirstResponderメソッドを呼び出すことによって、プログラムでキーボードを表示する
こともできます。このメソッドを呼び出すと、ターゲットビューがファーストレスポンダになり、
ユーザがビューをタップしたときとまったく同じように、編集プロセスが始まります。

アプリケーションが1つの画面上で複数のテキストベースビューを管理する場合は、後でキーボー
ドをしまうことができるように、現在どのビューがファーストレスポンダになっているかを追跡す
るのは、よい考えです。

キーボードをしまう
システムは、通常、キーボードを自動的に表示しますが、キーボードを自動的にはしまいません。
その代わり、適切なときにキーボードをしまうのはアプリケーションの責任です。通常は、ユーザ
のアクションに応答してキーボードをしまいます。たとえば、ユーザがキーボード上の「Return」
ボタンまたは「Done」ボタンをタップしたときや、アプリケーションのインターフェイス内のその
他のボタンをタップしたときに、キーボードをしまいます。キーボードの設定によっては、キー
ボードをしまいやすくするために、ユーザインターフェイスにその他のコントロールを追加する必
要があるかもしれません。

キーボードをしまうには、現在ファーストレスポンダになっているテキストベースビューの
resignFirstResponderメソッドを呼び出します。Text Viewがファーストレスポンダの状態でなく
なると、現在の編集セッションは終了し、そのことがデリゲートに通知されます。そして、キー
ボードが消えます。つまり、myTextFieldという変数が、現在ファーストレスポンダになっている
UITextFieldオブジェクトを指す場合、キーボードをしまうには以下のコードを実行するだけです。

[myTextField resignFirstResponder];

それ以降に発生したすべてのことは、このテキストオブジェクトによって自動的に処理されます。

118 キーボードの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

キーボードの下に隠れているコンテンツを移動する
システムは、キーボードの表示を要求されると、画面の下端からキーボードをスライドさせてアプ
リケーションのコンテンツの上に配置します。キーボードは、コンテンツの上に配置されるため、
キーボードが、編集対象のテキストオブジェクトの上に置かれる可能性があります。このような場
合は、編集対象のオブジェクトが見えるようにコンテンツを調整しなければなりません。

通常、コンテンツを調整するには、1つ以上のビューを一時的にサイズ変更したり、テキストオブ
ジェクトが見えるようにビューを配置する必要があります。テキストオブジェクトをキーボードと
一緒に管理する最も簡単な方法は、テキストオブジェクトをUIScrollViewオブジェクト(または、
そのサブクラス(UITableViewなど))内に埋め込むことです。キーボードが表示されたときに実
行しなければならないことは、Scroll Viewをサイズ変更して、対象のテキストオブジェクトを移動さ
せることです。したがって、UIKeyboardDidShowNotificationに応答して、処理メソッドでは以
下の処理を実行します。

1. キーボードのサイズを取得する。

2. Scroll Viewの高さからキーボードの高さを差し引く。

3. 編集対象のText Fieldが表示されるようにスクロールする。

図 5-6は、UIScrollViewオブジェクト内に複数のText Fieldが埋め込まれた単純なアプリケーション
で、上の手順を実行した様子を示しています。キーボードが表示されると、通知処理メソッドが
Scroll Viewのサイズを変更します。次に、UIScrollViewのscrollRectToVisible:animated:メソッ
ドを使用して、タップされたText Field(この場合は、「Email」フィールド)が見えるようにスク
ロールします。

図 5-6 キーボードに合わせてコンテンツを調整する

1. User taps email field 2. Scroll view resized to new height 3. Email field scrolled into view

キーボードの管理 119
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

注: 独自のScroll Viewをセットアップするときは、必ず、コンテンツビューに対する自動サイズ変
更規則を適切に設定してください。前の図では、Text Fieldが実際には汎用的なUIViewオブジェクト
に埋め込まれており、このオブジェクト自体がUIScrollViewオブジェクトに埋め込まれています。
汎用的なビューのUIViewAutoresizingFlexibleWidthとUIViewAutoresizingFlexibleHeightの
各自動サイズ変更オプションが設定されている場合、Scroll Viewのフレームサイズが変化すると、汎
用的なビューのフレームも変化します。これによって、望まない結果が生じることがあります。こ
れらのオプションを無効にすることによって、ビューのサイズが維持されて、コンテンツが正しく
スクロールされることが保証されます。

リスト 5-1は、キーボード通知を受信できるように登録するためのコードと、これらの通知用のハ
ンドラメソッドを示しています。このコードは、Scroll Viewを管理するView Controllerによって実装
されます。また、scrollView変数は、Scroll Viewオブジェクトを指す接続口です。各ハンドラメソッ
ドは、キーボード通知の情報ディクショナリからキーボードサイズを取得し、対応する分だけScroll
Viewの高さを調節します。さらに、keyboardWasShown:メソッドは、アクティブなText Fieldの矩形
をスクロールします。このText Fieldは、activeField変数に格納されており、
textFieldDidBeginEditing:デリゲートメソッドが呼び出されたときに設定されます(この例で
は、View Controllerは、それぞれのText Fieldのデリゲートとして役割も果たしています)。

リスト 5-1 キーボード通知の処理


- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self


selector:@selector(keyboardWasHidden:)
name:UIKeyboardDidHideNotification object:nil];
}

// UIKeyboardDidShowNotificationが送信されたときに呼び出される
- (void)keyboardWasShown:(NSNotification*)aNotification
{
if (keyboardShown)
return;

NSDictionary* info = [aNotification userInfo];

// キーボードのサイズを取得する
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;

// Scroll View(このウインドウのルートビュー)をサイズ変更する
CGRect viewFrame = [scrollView frame];
viewFrame.size.height -= keyboardSize.height;
scrollView.frame = viewFrame;

// アクティブなText Fieldが表示されるようにスクロールする
CGRect textFieldRect = [activeField frame];
[scrollView scrollRectToVisible:textFieldRect animated:YES];

keyboardShown = YES;
}

120 キーボードの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

// UIKeyboardDidHideNotificationが送信されたときに呼び出される
- (void)keyboardWasHidden:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];

// キーボードのサイズを取得する
NSValue* aValue = [info objectForKey:UIKeyboardBoundsUserInfoKey];
CGSize keyboardSize = [aValue CGRectValue].size;

// Scroll Viewの高さを元の値に戻す
CGRect viewFrame = [scrollView frame];
viewFrame.size.height += keyboardSize.height;
scrollView.frame = viewFrame;

keyboardShown = NO;
}

前のコードリストのkeyboardShown変数は、キーボードがすでに表示されているかどうかを追跡す
るために使用するブール値です。インターフェイスに複数のText Fieldが含まれている場合、ユーザ
は、各フィールド内の値を編集するために、これらのフィールドの間をタップすることができま
す。このような場合は、キーボードは消えませんが、システムは、新しいText Fieldで編集が始まる
たびにUIKeyboardDidShowNotification通知を生成します。キーボードが実際に消えたかどうか
を追跡することによって、このコードでは、Scroll Viewのサイズが2回以上小さくなることを防止し
ています。

テキストの描画

テキストを表示したり編集したりするUIKitクラスのほかに、iPhone OSには、画面に直接テキストを
描画するための方法がいくつかあります。単純な文字列を描画するための最も簡単で効率的な方法
は、NSStringクラスのUIKit拡張を使用することです。これらの拡張には、さまざまな属性を使用し
て画面上の望みの場所に文字列を描画するメソッドが含まれています。また、実際に文字列を描画
する前に、レンダリングされた文字列のサイズを計算するメソッドもあります。これは、アプリ
ケーションのコンテンツを正確にレイアウトするために役立ちます。

重要: パフォーマンスに影響するので、テキストを直接描画するのはできるだけ避けてください。
静的なテキストは、1つ以上のUILabelオブジェクトを使用すると、独自の描画ルーチンを使用する
よりもはるかに効率的に描画できます。同様に、UITextFieldクラスには、編集可能なテキスト領
域をコンテンツに組み込みやすくする、さまざまなスタイルが含まれています。

インターフェイスにカスタムテキスト文字列を描画する必要のある場合は、NSStringのメソッドを
使用します。UIKitには、基本のNSStringクラスの拡張機能が含まれており、それを利用してビュー
に文字列を描画できます。それらのメソッドを使用することで、レンダリングされるテキストの位
置を細かく調節したり、ビューコンテンツの残りの部分と合成したりできます。このクラスのメ
ソッドを利用して、望みのフォントとスタイル属性に基づいて、テキストの境界矩形をあらかじめ
計算することもできます。詳細については、『NSString UIKit Additions Reference』を参照してくださ
い。

テキストの描画 121
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第5章
テキストとWeb

描画中に使用するフォントをきめ細かく制御する必要がある場合は、Core Graphicsフレームワーク
の関数を使用して描画します。Core Graphicsフレームワークは、図やテキストの正確な描画と配置
のためのメソッドを提供します。これらの関数とその使用法の詳細については、『Quartz 2D
Programming Guide』および『Core Graphics Framework Reference』を参照してください。

122 テキストの描画
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章

ファイルとネットワーク

iPhone OSで実行中のアプリケーションは、ローカルのファイルシステムとネットワークにアクセス
できます。それには、Core OSフレームワークとCore Servicesフレームワークの両方を使用します。
ローカルのファイルシステム上のファイルを読み書きできることによって、ユーザデータとアプリ
ケーションの状態を次回使用するときのために保存できます。ネットワークアクセスを利用する
と、リモート操作の実行とデータの送受信のためにネットワークサーバと通信できます。

ファイルとデータの管理

iPhone OSのファイルは、フラッシュメモリの領域を、ユーザのメディアおよび個人ファイルと共有
しています。セキュリティのために、アプリケーションは、そのアプリケーション専用のディレク
トリに配置され、そのディレクトリ内のファイルしか読み書きできないように制限されます。以降
の各セクションでは、アプリケーションのローカルファイルシステムの構造と、ファイルを読み書
きするためのいくつかの手法について説明します。

よく使われるディレクトリ
セキュリティ目的のため、アプリケーションにはデータと環境設定を書き込むことのできる場所は
数か所だけです。アプリケーションがデバイス上にインストールされると、アプリケーション用の
ホームディレクトリが作成されます。表 6-1は、アプリケーションからアクセスする可能性のある、
ホームディレクトリ内の重要なサブディレクトリのリストです。この表には、各ディレクトリの用
途とアクセス制限、およびディレクトリの内容がiTunesによってバックアップされるかどうかが記
述されています。バックアッププロセスと復元プロセスの詳細については、「バックアップと復
元」 (125 ページ)を参照してください。アプリケーションのホームディレクトリの詳細について
は、「アプリケーションサンドボックス」 (22 ページ)を参照してください。

表 6-1 iPhoneアプリケーションのディレクトリ

ディレクトリ 説明

<Application_Home>/AppName.app これはアプリケーション自体を含む、バンドルの
ディレクトリです。アプリケーションは署名されて
いる必要があるため、実行時にこのディレクトリの
内容を変更してはなりません。変更を加えると、後
でアプリケーションを起動できなくなります。
iPhone OS 2.1以降では、このディレクトリの内容が
iTunesによってバックアップされません。ただし、
App Storeから購入したアプリケーションの最初の同
期はiTunesによって実行されます。

ファイルとデータの管理 123
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

ディレクトリ 説明

<Application_Home>/Documents/ アプリケーション固有のすべてのデータファイルを
書き込むために使用するディレクトリです。ユーザ
データや、定期的にバックアップする必要があるそ
の他のデータを保存するために、このディレクトリ
を使用します。このディレクトリのパスの取得方法
の詳細については、「アプリケーションディレクト
リへのパスの取得」 (125 ページ)を参照してくだ
さい。
このディレクトリの内容はiTunesによってバックアッ
プされます。

<Application_Home>/Library/Preferences このディレクトリには、アプリケーション固有の環
境設定ファイルを保存します。環境設定ファイルを
直接作成しないでください。その代わりに、
NSUserDefaultsクラスまたはCFPreferencesAPIを使用
して、アプリケーションの環境設定を取得したり設
定したりします(「Settingsバンドルの追
加」 (167 ページ)を参照)。
このディレクトリの内容はiTunesによってバックアッ
プされます。

<Application_Home>/Library/Caches アプリケーションが終了しても次の起動まで保持し
ておきたいアプリケーション固有のサポートファイ
ルを書き込むために、このディレクトリを使用しま
す。一般に、これらのファイルの追加と削除はアプ
リケーション側で処理します。ただし、iTunesは、
デバイスの完全復元中にこれらのファイルを削除す
るので、必要に応じて再作成する必要があります。
このディレクトリにアクセスするには、「アプリ
ケーションディレクトリへのパスの取得」 (125 ペー
ジ)で説明するインターフェイスを使用して、ディ
レクトリへのパスを取得します。
iPhone OS 2.2以降では、このディレクトリの内容が
iTunesによってバックアップされません。

<Application_Home>/tmp/ アプリケーションが終了しても次の起動まで保持し
ておきたい一時ファイルを書き込むために、この
ディレクトリを使用します。アプリケーションは、
これらのファイルが不要になったと判断したら、こ
のディレクトリから削除する必要があります(アプ
リケーションが実行されていないときに、システム
が古いファイルをこのディレクトリから削除する場
合もあります)。このディレクトリのパスの取得方
法の詳細については、「アプリケーションディレク
トリへのパスの取得」 (125 ページ)を参照してく
ださい。
iPhone OS 2.1以降では、このディレクトリの内容が
iTunesによってバックアップされません。

124 ファイルとデータの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

バックアップと復元
アプリケーションで、バックアップ操作や復元操作に備える必要はありません。iPhone OS 2.2以降
では、デバイスがコンピュータに接続されて同期されると、iTunesがすべてのファイルの段階的な
バックアップを実行します。ただし、以下のディレクトリ内のファイルは除きます。

■ <Application_Home>/AppName.app
■ <Application_Home>/Library/Caches
■ <Application_Home>/tmp

iTunesは、アプリケーションバンドルをバックアップしますが、同期操作のたびにそれが実行され
るわけではありません。App Storeから購入したデバイス上のアプリケーションは、そのデバイスが
次回iTunesと同期したときにバックアップされます。アプリケーションバンドルに変更がない場合
は(たとえば、アプリケーションが更新されていない場合)、次回の同期操作中にアプリケーショ
ンはバックアップされません。

同期処理に長期間かかるのを防ぐには、アプリケーションのホームディレクトリ内のファイルの置
き場所を選択しておく必要があります。<Application_Home>/Documentsディレクトリは、ユーザデー
タファイルや、アプリケーションで簡単に再作成できるファイルを保存するために使用します。一
時的なデータを保存するために使用するファイルは、ApplicationHome/tmpディレクトリ内に置きま
す。そして、不要になったらアプリケーション側が削除します。次回起動するときに使用するデー
タファイルを作成する場合は、それらのファイルをApplication Home/Library/Cachesに置きます。

注: 大きなデータファイルや、頻繁に変更されるファイルを作成する場合は、それらを
<Application_Home>/Documentsディレクトリではなく、Application Home/Library/Cachesディレク
トリに保存することを検討してください。大きなデータファイルをバックアップすると、バック
アップ処理が大幅に遅くなる可能性があります。定期的に変更される(したがって、頻繁にバック
アップしなければならない)ファイルの場合も同様です。これらのファイルをCachesディレクトリ
に置くと、同期操作のたびにバックアップされるのを防止できます(iPhone OS 2.2以降の場合)。

アプリケーションでのディレクトリの使い方に関するその他のガイダンスについては、表
6-1 (123 ページ)を参照してください。

アプリケーションディレクトリへのパスの取得
システムのさまざまなレベルにおいて、アプリケーションサンドボックスのディレクトリに対する
ファイルシステムパスを、プログラムによって取得する方法が存在します。ただし、これらのパス
を取得する推奨される方法は、Cocoaプログラミングのインターフェイスを使用する方法です。
FoundationフレームワークのNSHomeDirectory関数は、最上位のホームディレクトリ、つまり、ア
プリケーション、Documents、Library、およびtmpの各ディレクトリを含んでいるディレクトリへ
のパスを返します。この関数のほかに、NSSearchPathForDirectoriesInDomains関数および
NSTemporaryDirectory関数を使って、Documents、Caches、およびtmpの各ディレクトリへのパ
スを取得することもできます。

NSHomeDirectory関数とNSTemporaryDirectory関数はどちらも、正しい形式のパス情報をNSString
オブジェクトとして返します。NSStringのパス関連メソッドを使用して、パス情報に変更を加えた
り、新しいパス文字列を作成したりできます。たとえば、一時ディレクトリのパスを取得して、
ファイル名を追加し、結果として得られた文字列を使って一時ディレクトリ内に指定した名前の
ファイルを作成することができます。

ファイルとデータの管理 125
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

注: ANSI Cのプログラムインターフェイス(パスを受け取るインターフェイスを含む)でフレーム
ワークを使用している場合、NSStringオブジェクトは、Core Foundation版の同等のオブジェクトと
「toll-free bridging」(犠牲を伴わない橋渡し)であることを思い出してください。つまり、NSString
オブジェクト(前述の関数のいずれかの戻り値など)は、以下の例に示すように、CFStringRef型
にキャストできるということです。
CFStringRef homeDir = (CFStringRef)NSHomeDirectory();

「toll-free bridge」の詳細については、『Carbon-Cocoa Integration Guide』を参照してください。

FoundationフレームワークのNSSearchPathForDirectoriesInDomains関数を使うと、アプリケー
ション関連のディレクトリへのフルパスを取得できます。iPhone OSでこの関数を使用するには、第
1パラメータに適切な検索パス定数、第2パラメータにNSUserDomainMaskを指定します。表 6-2は、
最もよく使われる定数と、その定数が返すディレクトリのリストです。

表 6-2 よく使われる検索パス定数

定数 ディレクトリ

NSDocumentDirectory <Application_Home>/Documents

NSCachesDirectory <Application_Home>/Library/Caches

NSApplicationSupportDirectory <Application_Home>/Library/Application Support

NSSearchPathForDirectoriesInDomains関数は、もともと、このようなディレクトリが複数存在
するMac OS X用に設計されているため、1つのパスではなくパスの配列を返します。iPhone OSでは、
その結果の配列に、要求したディレクトリへのパスが1つ含まれています。リスト 6-1は、この関数
の一般的な使用方法を示します。

リスト 6-1 アプリケーションのDocuments/ディレクトリへのファイルシステムパスの取得


NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSUserDomainMask以外のドメインマスクパラメータや、表 6-2 (126 ページ)に示した定数以外の


ディレクトリ定数を使用して、NSSearchPathForDirectoriesInDomainsを呼び出すこともできま
すが、アプリケーションは、その戻り値として返されたディレクトリに書き込むことはできませ
ん。たとえば、ディレクトリパラメータとしてNSApplicationDirectoryを、ドメインマスクパラ
メータとしてNSSystemDomainMaskを指定すると、(デバイス上では)/Applicationsというパス
が戻り値として得られます。しかし、アプリケーションからこの場所へのファイルの書き込みはで
きません。

その他の注意点としては、プラットフォーム間のディレクトリの場所における違いです。
NSSearchPathForDirectoriesInDomains、NSHomeDirectory、NSTemporaryDirectory、および
類似の関数から返されるパスは、アプリケーションを実行しているのがデバイス上かシミュレータ
上かにより異なります。たとえば、リスト 6-1 (126 ページ)に示した関数呼び出しを見てみます。
デバイス上では、返されるパス(documentsDirectory)は以下のようになります。

/var/mobile/Applications/30B51836-D2DD-43AA-BCB4-9D4DADFED6A2/Documents

一方、iPhone Simulatorでは、返されるパスは次の形式をとります。

126 ファイルとデータの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

/Volumes/Stuff/Users/johnDoe/Library/Application Support/iPhone
Simulator/User/Applications/118086A0-FAAF-4CD4-9A0F-CD5E8D287270/Documents

ユーザの環境設定を読み書きするには、NSUserDefaultsクラスまたはCFPreferences APIを使用し
ます。これらのインターフェイスにより、Library/Preferences/ディレクトリへのパスを作成し
たり、環境設定ファイルのディレクトリへ読み書きしたりする必要がなくなります。これらのイン
ターフェイスの使用の詳細については、「Settingsバンドルの追加」 (167 ページ)を参照してくだ
さい。

アプリケーションバンドルにサウンド、画像、またはその他のリソースが含まれている場合には、
NSBundleクラスまたはCFBundle不透過型を使用してこれらのリソースをロードする必要がありま
す。バンドルは、アプリケーション内のリソースの格納場所についてもともと情報を備えていま
す。加えて、バンドルはユーザの言語に関する環境設定を認識し、デフォルトのリソースの代わり
にローカライズ済みのリソースを自動的に優先して選択することができます。バンドルの詳細につ
いては、「アプリケーションバンドル」 (23 ページ)を参照してください。

ファイルデータの読み取りおよび書き込み
iPhone OSはファイルの読み取り、書き込み、および管理の方法をいくつか提供します。

■ Foundationフレームワーク:
❏ アプリケーションのデータをプロパティリストとして表現できる場合、
NSPropertyListSerialization APIを使用して、プロパティリストをNSDataオブジェクト
に変換します。その後、NSDataクラスのメソッドを使用して、データオブジェクトをディ
スクに書き込むことができます。
❏ アプリケーションのモデルオブジェクトでNSCodingプロトコルを採用する場合、
NSKeyedArchiverクラス、特にこのクラスのarchivedDataWithRootObject:メソッドを使
用してこれらのモデルオブジェクトのグラフをアーカイブできます。
❏ FoundationフレームワークのNSFileHandleクラスを使用すれば、ファイルの内容へのラン
ダムアクセスが可能です。
❏ FoundationフレームワークのNSFileManagerクラスは、ファイルシステム内のファイルの作
成、および操作のメソッドを提供します。

■ Core OS呼び出し:
❏ fopen、fread、およびfwriteなどの呼び出しを使用しても、順次アクセスまたはランダム
アクセスを行ってファイルデータを読み書きできます。
❏ mmapおよびmunmap呼び出しは、大きなファイルをメモリにロードし、その内容にアクセス
するための効率的な方法を提供します。

注: Core OS呼び出しの前述のリストは、一般的によく使われている呼び出しの一例に過ぎません。
利用できる関数の詳細なリストについては、『iPhoneOSManualPages』のセクション3の関数の一覧
を参照してください。

以降の各セクションでは、ファイルの読み書きを行うための高レベルの手法のいくつかについて、
その使用法の例を示します。Foundationフレームワークのファイル関連クラスの詳細情報について
は、『Foundation Framework Reference』を参照してください。

ファイルとデータの管理 127
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

プロパティリストデータの読み取りおよび書き込み

プロパティリストとは、いくつかのFoundation(およびCore Foundation)データ型(辞書、配列、
文字列、日付、バイナリデータ、および数値とブール値を含む)をカプセル化する、データ表現の
形式です。プロパティリストは、一般的に構造化された設定データを格納するために使用します。
たとえば、CocoaアプリケーションおよびiPhoneアプリケーションのそれぞれにあるInfo.plistファイ
ルは、アプリケーション自体の設定情報を格納するプロパティリストです。プロパティリストを使
用して、アプリケーションの終了時の状態など、追加の情報を格納できます。

通常、コードでは、辞書または配列をコンテナオブジェクトとして使うところから始めてプロパ
ティリストを構成します。その後、(場合によっては)ほかの辞書や配列を含んだその他のプロパ
ティリストオブジェクトを追加します。辞書のキーは文字列オブジェクトでなければなりません。
これらのキーの値は、NSDictionary、NSArray、NSString、NSDate、およびNSNumberのインスタ
ンスです。

データがプロパティリストオブジェクト(NSDictionaryオブジェクトなど)によって表現され得る
アプリケーションの場合、リスト 6-2に示すメソッドを使って、プロパティリストをディスクに書
き込めます。このメソッドは、プロパティリストオブジェクトをNSDataオブジェクトへとシリアラ
イズし、writeApplicationData:toFile:メソッド(リスト 6-4 (130 ページ)に示す実装)を呼び
出して、このデータをディスクに書き込みます。

リスト 6-2 NSDataオブジェクトへのプロパティリストオブジェクトの変換とストレージへの書


き込み
- (BOOL)writeApplicationPlist:(id)plist toFile:(NSString *)fileName {
NSString *error;
NSData *pData = [NSPropertyListSerialization dataFromPropertyList:plist
format:NSPropertyListBinaryFormat_v1_0 errorDescription:&error];
if (!pData) {
NSLog(@"%@", error);
return NO;
}
return ([self writeApplicationData:pData toFile:(NSString *)fileName]);
}

iPhone OSでプロパティリストファイルを書き込む場合、ファイルをバイナリ形式で格納することが
重要です。これを行うには、dataFromPropertyList:format:errorDescription:メソッドのformat
パラメータにNSPropertyListBinaryFormat_v1_0キーを指定します。バイナリ形式のプロパティ
リストは、テキストベースのその他の形式に比べればかなりコンパクトです。このコンパクトさに
よって、ユーザのデバイス上で占有する領域が減るだけでなく、プロパティリストの読み書きに費
やす時間も減ります。

リスト 6-3に、ディスクからプロパティリストファイルをロードし、そのプロパティリスト内のオ
ブジェクトを再構成するコードを示します。

リスト 6-3 アプリケーションのDocumentsディレクトリからのプロパティリストオブジェクトの


読み取り
- (id)applicationPlistFromFile:(NSString *)fileName {
NSData *retData;
NSString *error;
id retPlist;
NSPropertyListFormat format;

retData = [self applicationDataFromFile:fileName];

128 ファイルとデータの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

if (!retData) {
NSLog(@"Data file not returned.");
return nil;
}
retPlist = [NSPropertyListSerialization propertyListFromData:retData
mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error];
if (!retPlist){
NSLog(@"Plist not returned, error:%@", error);
}
return retPlist;
}

プロパティリストおよびNSPropertyListSerializationクラスの詳細については、『Property List
Programming Guide』を参照してください。

アーカイバを使ったデータの読み取りおよび書き込み

アーカイバは、任意のオブジェクトコレクションをバイトストリームに変換します。
NSPropertyListSerializationクラスで採用しているプロセスに似ているように感じるかもしれ
ませんが、重要な違いが1つあります。つまり、プロパティリストのシリアライザが変換できるの
は、限られたデータ型(ほとんどはスカラー)だけであるということです。アーカイバは、任意の
Objective-Cオブジェクト、スカラー型、配列、構造体、文字列などを変換できます。

アーカイブプロセスの鍵は、対象オブジェクト自身の中にあります。アーカイバが操作するオブ
ジェクトは、オブジェクトの状態を読み書きするインターフェイスを定義している、NSCodingプロ
トコルに準拠する必要があります。アーカイバは、オブジェクトの集合をエンコードするとき、そ
れぞれのオブジェクトに対してencodeWithCoder:メッセージを送ります。オブジェクトは、これ
に基づいて、対応するアーカイブに重要な状態情報を書き出します。展開プロセスは、情報の流れ
を逆転します。展開する間、各オブジェクトは、initWithCoder:メッセージを受け取ります。オ
ブジェクトは、このメッセージを使用して、アーカイブ内の現在の状況情報で自身を初期化しま
す。展開プロセスが完了すると、バイトストリームは、以前にアーカイブに書き込んだものと同じ
状態を持った新しいオブジェクトの集合として再構築されます。

Foundationフレームワークは、シーケンシャルとキー付きの二種類のアーカイブをサポートしてい
ます。キー付きアーカイバはより柔軟性が高く、アプリケーションで使用することをお勧めしま
す。次の例では、キー付きアーカイバを使ってオブジェクトのグラフをアーカイブする方法を示し
ます。_myDataSourceオブジェクトのrepresentationメソッドは、アーカイブに含めるすべての
オブジェクトを指す単一のオブジェクト(配列または辞書)を返します。その後、データオブジェ
クトは、myFilePath変数に指定されているパスのファイルに書き込まれます。

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[_myDataSource


representation]];
[data writeToFile:myFilePath atomically:YES];

注: archiveRootObject:toFile:メッセージをNSKeyedArchiverオブジェクトに送信すると、1
ステップで、アーカイブを作成し、そのアーカイブをストレージに書き込めます。

ディスクからアーカイブの内容をロードするには、単にプロセスを逆転させます。ディスクから
データをロードしたら、NSKeyedUnarchiverクラスおよびそのunarchiveObjectWithData:クラス
メソッドを使用して、モデルオブジェクトグラフを復元します。たとえば、前述の例からデータを
展開するには、以下のコードを使用できます。

NSData* data = [NSData dataWithContentsOfFile:myFilePath];


id rootObject = [NSKeyedUnarchiver unarchiveObjectWithData:data];

ファイルとデータの管理 129
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

アーカイバの使用方法およびオブジェクトでNSCodingプロトコルをサポートする方法の詳細につい
ては、『Archives and Serializations Programming Guide for Cocoa』を参照してください。

Documentsディレクトリへのデータの書き込み

アプリケーションデータを(アーカイブまたはシリアライズされたプロパティリストとして)カプ
セル化したNSDataオブジェクトを作成したら、リスト 6-4に示すメソッドを呼び出して、このデー
タをアプリケーションのDocumentsディレクトリに書き込めます。

リスト 6-4 アプリケーションのDocumentsディレクトリへのデータの書き込み


- (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
if (!documentsDirectory) {
NSLog(@"Documents directory not found!");
return NO;
}
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
return ([data writeToFile:appFile atomically:YES]);
}

Documentsディレクトリからのデータの読み取り

アプリケーションのDocumentsディレクトリからファイルを読み取るには、ファイル名のパスを作
成し、望みのメソッドを使用してメモリにファイルの内容を読み込みます。比較的小さなファイ
ル、つまり、メモリページが数ページ分のサイズもないファイルについては、リスト 6-5に示すコー
ドを使用してファイルの内容のデータオブジェクトを取得できます。この例では、Documentsディ
レクトリ内のファイルへのフルパスを構成し、そこからデータオブジェクトを作成してそのオブ
ジェクトを返します。

リスト 6-5 アプリケーションのDocumentsディレクトリからのデータの読み取り


- (NSData *)applicationDataFromFile:(NSString *)fileName {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *appFile = [documentsDirectory
stringByAppendingPathComponent:fileName];
NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile]
autorelease];
return myData;
}

メモリに保持するために複数のメモリページを必要するファイルについては、ファイル全体を一度
にロードしないようにします。これは、ファイルの一部のみを使用する場合、特に重要です。より
大きなファイルについては、mmap関数、またはNSDataのinitWithContentsOfMappedFile:メソッ
ドを使用して、メモリにファイルをマップすることを検討すべきです。

ファイルをマップするか、直接ロードするかの判断はデベロッパに任されています。必要なメモリ
ページがごくわずか(3~4ページ)の場合、ファイル全体をメモリにロードしても比較的安全で
す。しかし、数十ページ、または数百ページを必要とするファイルの場合、おそらくファイルをメ

130 ファイルとデータの管理
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

モリにマップする方が効率的です。ただし、ほかの同様の決断をする場合のように、デベロッパは
アプリケーションのパフォーマンスを測定し、ファイルのロードおよび必要なメモリの割り当てに
要する時間を調べるべきです。

ファイルアクセスガイドライン
ファイルを作成したりファイルにデータを書き込む際には、以下のガイドラインを念頭に置いてく
ださい。

■ ディスクに書き込むデータ量を最小限にする。ファイル操作は、比較的低速であり、寿命が限
られているフラッシュディスクへの書き込みを伴います。ファイル関連操作を最小限にするた
めの具体的なヒントを、以下に示します。
❏ ファイルの変更部分だけを書き込み、変更はできるだけまとめる。わずか数バイトの変更
のために、ファイル全体を書き込むようなことは避けるようにします。
❏ ファイル形式を定義する際には、毎回ディスクに書き込む必要があるブロック数が最少に
なるように、頻繁に更新されるコンテンツをグループにまとめる。
❏ ランダムにアクセスされる構造化されたコンテンツで構成されるデータは、SQLiteデータ
ベースに保存する。この点は、操作するデータの量が数メガバイトを越える可能性がある
場合、特に重要です。

■ ディスクへのキャッシュファイルの書き込みを避ける。この規則の唯一の例外は、アプリケー
ションを終了する際、次の起動時に同じ状態へアプリケーションを戻すために使用する、状態
情報を書き込む必要がある時です。

状態情報を保存する
ユーザがホーム(Home)ボタンを押すと、iPhone OSはアプリケーションを終了して、ホーム(Home)画
面に戻ります。同様に、アプリケーションが、別のアプリケーションによって処理されるスキーム
のURIを開くと、iPhone OSは現在のアプリケーションを終了して、他方のアプリケーションでその
URIを開きます。つまり、Mac OS Xでは、アプリケーションを一時停止したりバックグラウンドにす
るようなアクションが、iPhone OSではアプリケーションを終了させることになります。モバイルデ
バイスでは、このようなアクションがよく発生するので、アプリケーションは、揮発性のデータや
アプリケーションの状態を管理する方法を変更しなければなりません。

ほとんどのデスクトップアプリケーションでは、いつファイルをディスクに保存するかをユーザが
手動で選択します。これとは異なり、iPhoneアプリケーションでは、そのワークフローの中の重要
な時点で、変更を自動的に保存する必要があります。いつデータを保存するかはデベロッパに任さ
れていますが、考えられる選択肢は2つあります。1つは、ユーザが変更を行ったらすぐにその変更
を保存することです。もう1つは、同じページでの変更をまとめておいて、そのページを閉じると
き、新しいページを開くとき、またはアプリケーションが終了するときに変更を保存することで
す。どのような場合にも、前のページのデータを保存せずに新しいページのコンテンツにユーザが
進めるようにすべきではありません。

アプリケーションが終了する場合は、アプリケーションの現在の状態を一時キャッシュファイル、
または環境設定データベースに保存します。次回ユーザがアプリケーションを起動したときには、
その情報を使用して、アプリケーションを以前の状態に復元します。保存する状態情報は、できる
限り最小にする必要があります。ただし、アプリケーションを適切な状態に正確に復元できるよう
にしなければなりません。ユーザが以前操作していたものとまったく同じ画面を復元しても意味が

ファイルとデータの管理 131
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

ない場合は、そこまでする必要はありません。たとえば、ユーザが連絡先情報を編集した後に「電
話(Phone)」アプリケーションを離れた場合、戻ったときに、「電話(Phone)」アプリケーションは、
その連絡先情報の編集画面ではなく、連絡先情報のトップレベルのリストを表示します。

大文字小文字の区別
iPhone OSベースのファイルシステムは、大文字小文字を区別します。ファイル名を扱う場合は、大
文字小文字まで正確に一致させる必要があります。さもなければ、コードからファイルを開けな
かったり、ファイルにアクセスしたりできない場合があります。

ネットワーク

iPhone OSのネットワークスタックには、iPhoneおよびiPod touchデバイスの無線ハードウェアをカ


バーするインターフェイスがいくつか含まれています。主たるプログラミングインターフェイスは
CFNetworkフレームワークです。これは、Core FoundationフレームワークのBSDソケットと不透過型
の最上位に構築されており、ネットワークエンティティと通信します。また、Foundationフレーム
ワークのNSStreamクラスや、システムのCore OSレイヤにある低レベルのBSDソケットを使用するこ
ともできます。

以降の各セクションでは、アプリケーションにネットワーク機能を組み込む必要があるデベロッパ
向けに、iPhone固有のヒントを示します。ネットワーク通信にCFNetworkフレームワークを使用する
方法の詳細については、『CFNetwork Programming Guide』および『CFNetwork Framework Reference』
を参照してください。NSStreamクラスの使用方法については、『Foundation Framework Reference』
を参照してください。

効率的なネットワーク処理のためのヒント
ネットワーク経由で送受信を行うコードを実装する場合、その送受信がデバイス上で最も電力を集
中的に使う操作の1つであると覚えておいてください。送受信にかける時間を最小限にすることが
バッテリー持続時間の向上に寄与します。そのためには、ネットワーク関連コードの作成時には、
以下のヒントを考慮してください。

■ デベロッパのコントロール下にあるプロトコルについては、可能な限りコンパクトなデータ形
式を定義する。
■ やりとりを頻繁に行うプロトコルを使用した通信を避ける。
■ 可能な場合はデータをバースト転送する。

携帯電話無線機能およびWi-Fi無線機能は、アクティブでないときには電源がオフになるように設計
されています。しかし、無線の状態によりますが、これには数秒間かかる場合があります。アプリ
ケーションが数秒ごとに少量データのバースト転送を行う場合、実際には何もしていなくても無線
機能の電源がオフにならずに、電力を消費し続ける可能性があります。頻繁に少量のデータを転送
するよりも、多量のデータを一度に転送するか、比較的長い間隔で転送するほうが良いでしょう。

ネットワーク経由で通信する場合、パケットはいつでも失われる可能性があると覚えておくことも
重要です。ネットワークのコードを作成する際には、エラー処理に関してできる限り強固なコード
にすべきです。ネットワーク状態の変化に対応するハンドラを実装することは理にかなっています
が、これらのハンドラが一貫性を持って呼び出されなくても驚かないでください。たとえば、Bonjour

132 ネットワーク
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

ネットワーキングのコールバックは、ネットワークサービスが失われても、必ずしもすぐに呼び出
されるわけではありません。Bonjourシステムサービスは、サービスが失われたという通知を受け取
るとブラウズコールバックをすぐに呼び出しますが、ネットワークサービスは通知なく失われる場
合もあります。たとえば、ネットワークサービスを提供しているデバイスが予期しないときにネッ
トワーク接続を失ったり、通知が転送中に失われたりする可能性があります。

Wi-Fiの使用
Wi-Fi無線を使用してネットワークアクセスをする場合は、そのことをシステムに通知する必要があ
ります。それには、アプリケーションのInfo.plistファイルにUIRequiresPersistentWiFiキーを
含めます。このキーを含めると、アクティブなWi-Fiホットスポットを検出したら、ネットワーク選
択パネルにそれを表示する必要があることをシステムに知らせることができます。また、アプリ
ケーションの実行中はWi-Fiハードウェアを停止させてはならないことをシステムに知らせることも
できます。

Wi-Fiハードウェアが電力を消費し過ぎるのを防ぐために、iPhone OSにはタイマーが組み込みこまれ
ており、UIRequiresPersistentWiFiキーを通してWi-Fiハードウェアを利用するアプリケーション
がない場合は、30分経過したらこのハードウェアが完全にオフになります。ユーザがこのキーを含
むアプリケーションを起動すると、iPhone OSは、アプリケーションが実行している間は、事実上こ
のタイマーを無効にします。ただし、アプリケーションが終了したらすぐに、システムはタイマー
を有効にし直します。

UIRequiresPersistentWiFiキーおよびInfo.plistファイルのキーの詳細については、「情報プロ
パティリスト」 (26 ページ)を参照してください。

ネットワーク 133
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第6章
ファイルとネットワーク

134 ネットワーク
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章

マルチメディアサポート

iPhone OSでは、Core AudioフレームワークおよびOpenALフレームワークを通じてアプリケーション


のオーディオ機能をサポートし、Media Playerフレームワークを使用してビデオ再生をサポートしま
す。Core Audioでは、サウンドの再生、録音、操作のほか、ストリーミングオーディオの解析のた
めに高度なインターフェイスを提供します。ゲームデベロッパの場合、OpenALを利用したコードを
すでに持っていれば、そのコードをiPhone OSで使用できます。

iPhone OSでのサウンドの使用

Core Audioは、アプリケーションでサウンドを扱うための豊富なツールセットを提供します。これ
らのツールは、次の4つのフレームワークにまとめられています。

■ Audio Toolboxフレームワーク。オーディオの録音と再生、オーディオストリームの解析、およ
びオーディオフォーマットの変換のために使用します。
■ Audio Unitフレームワーク。オーディオ処理プラグインを使うために使用します。
■ AV Foundationフレームワーク。単純なObjective-Cインターフェイスを使用してオーディオを再
生するために使用します。
■ Core Audioフレームワーク(アンブレラフレームワークではない)。すべてのCore Audioサービ
スで使われるデータ型を提供します。

Core Audioのほかに、iPhone OSではOpenALフレームワークを使用して、ポジショニングを伴うオー


ディオ再生ができます。iPhone OSでサポートされているOpenAL 1.1は、Core Audioの上に構築され
ています。

アプリケーションのニーズに応じて、さまざまなiPhoneオーディオAPIを選択できます。以下のリス
トは、使用するオーディオ技術についての参照先を示しています。

■ 警告やユーザインタフェースのサウンドエフェクトを再生したり、デバイス上でバイブレーショ
ンを起こすには、System Sound Servicesを使用します。「System Sound Servicesを使用して短い
サウンドを再生したり、バイブレーションを起動する」 (140 ページ)を参照してください。
■ 最小のコード行でサウンドを再生するには、AVAudioPlayerクラスを使用します。「AVAudioPlayer
クラスを利用して簡単にサウンドを再生する」 (141 ページ)を参照してください。
■ ステレオポジション、音量制御、同時再生などのフル装備のオーディオ再生を提供するには、
OpenALを使用します。「OpenALを使用したポジショニングを伴うサウンドの再生」 (146 ペー
ジ)を参照してください。
■ 遅延が最小のオーディオを提供するには(特に、VOIPアプリケーションなどのために入力と出
力を同時に行う場合)、I/Oオーディオユニットを使用します。「iPhone OSでのオーディオユ
ニットのサポート」 (148 ページ)を参照してください。
■ 最高レベルの制御でサウンドを再生するには(同期のサポートも含む)、Audio Queue Services
を使用します。「Audio Queue Servicesを使用した制御を伴うサウンドの再生」 (143 ページ)
を参照してください。

iPhone OSでのサウンドの使用 135


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

■ オーディオを録音するには、Audio Queue Servicesを使用します。「オーディオの録音」 (146 ペー


ジ)を参照してください。
■ ネットワーク接続からのオーディオストリームを解析するには、Audio File Stream Servicesを使
用します。「ストリーミングされたオーディオの解析」 (147 ページ)を参照してください。

iPhone OSベースのデバイス上でオーディオがどのように動作するかについての重要な情報が書かれ
ているので、次のセクション「基礎:ハードウェアコーデック、オーディオフォーマット、オー
ディオセッション」 (136 ページ)は必ずお読みください。また、「iPhoneオーディオのベストプ
ラクティス」 (148 ページ)もお読みください。ここでは、最高のパフォーマンスと最高のユーザ
体験を実現するためのガイドラインを提供し、使用すべきオーディオフォーマットおよびファイル
形式のリストを示します。

さらに深く学びたい場合は、iPhone Dev Centerで提供されているガイド、リファレンスブック、サ


ンプルコード、その他を参照してください。一般的なオーディオタスクの実行方法についてのヒン
トは、『Audio & Video Coding How-To's』を参照してください。iPhone OSでのオーディオ開発につい
ての詳しい説明は、『Core Audio Overview』、『Audio Queue Services Programming Guide』、および
『Audio Session Programming Guide』を参照してください。

基礎:ハードウェアコーデック、オーディオフォーマット、
オーディオセッション
iPhoneオーディオの開発を始めるには、iPhone OSベースのデバイスのハードウェアおよびソフト
ウェアのアーキテクチャについて少し理解しておくと役立ちます。

iPhoneオーディオのハードウェアコーデック

iPhone OSアプリケーションでは、次のセクションで説明するような幅広いオーディオデータフォー
マットを使用できます。これらのフォーマットのなかには、ソフトウェアベースのエンコードとデ
コードを使用するものあります。これらのフォーマットの複数のサウンドを同時に再生することも
できます。さらに、アプリケーションとバックグラウンドアプリケーション(有名なものとして
は、iPodアプリケーション)で、これらのフォーマットのサウンドを同時に再生することもできま
す。

iPhone OSのその他のオーディオフォーマットは、再生にハードウェアコーデックを使用します。
以下のフォーマットがあります。

■ AAC
■ ALAC (Apple Lossless)
■ MP3

一度に再生できるのは、これらのいずれかのフォーマットの1つのインスタンスのみです。たとえ
ば、ステレオMP3サウンドを再生しているときに、同時に別のMP3サウンドを再生することはでき
ません。また、AACサウンドやALACサウンドを同時に再生することもできません。 iPodアプリケー
ションがバックグラウンドでMP3サウンドを再生している場合、アプリケーションはAAC、ALAC、
またはMP3のサウンドを再生することはできません。

複数の高品質サウンドを再生したり、iPodを再生中にバックグラウンドでサウンドを再生するには、
リニアPCM(圧縮なし)またはIMA4(圧縮あり)のオーディオを使用します。

136 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

オーディオの再生フォーマットと録音フォーマット

以下は、iPhone OSでサポートされているオーディオ再生フォーマットです。

■ AAC
■ AMR(Adaptive Multi-Rate。音声用のフォーマット)
■ ALAC (Apple Lossless)
■ iLBC(internet Low Bitrate Codec。音声向けのもう1つのフォーマット)
■ IMA4 (IMA/ADPCM)
■ リニアPCM(圧縮なし)
■ µ-lawおよびa-law
■ MP3 (MPEG-1 audio layer 3)

以下は、iPhone OSでサポートされているオーディオ録音フォーマットです。

■ ALAC (Apple Lossless)


■ iLBC(internet Low Bitrate Codec。音声向け)
■ IMA/ADPCM (IMA4)
■ リニアPCM
■ µ-lawおよびa-law

以下のリストは、iPhone OSが、個別再生または複数再生のためにサポートしているオーディオフォー
マットの要約です。

■ リニアPCMおよびIMA4 (IMA/ADPCM)。リニアPCMフォーマットとIMA4フォーマットのサウンド
は、iPhone OSでCPUリソースを気にせずに複数同時に再生できます。これは、音声品質のAMR
フォーマットとiLBCフォーマット、およびµ-lawおよびa-lawの各圧縮フォーマットについても同
様です。
■ AAC、MP3、ALAC (Apple Lossless)。AAC、MP3、およびALACのサウンドの再生には、iPhone OS
ベースのデバイス上の効率的なハードウェアベースのデコードが使われます。ただし、これら
のコーデックはすべて1つのハードウェアパスを共有します。一度に再生できるのは、これらの
いずれかのフォーマットの1つのインスタンスのみです。

AAC、MP3、およびALACのオーディオに1つのハードウェアパスということは、仮想ピアノなどの
「次々と再生する」スタイルのアプリケーション向けである言えます。ユーザがiPodアプリケーショ
ンでこの3つのフォーマットのいずれか1つのサウンドを再生している場合、そのオーディオと同時
に再生するには、アプリケーションは、ソフトウェアデコードフォーマット(リニアPCM、IMA4、
AMR、iLBC、µ-law、またはa-law)の1つを使用しなければなりません。

オーディオセッション

Core Audioのオーディオセッションインターフェイス(AudioToolbox/AudioServices.hで宣言さ
れている)を利用すると、アプリケーションは専用のオーディオコンテキストを定義して、そのア
プリケーションが実行されているデバイスの大きい方のオーディオコンテキスト内でうまく動作さ
せることができます。

iPhone OSでのサウンドの使用 137


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

このコンテキストには、着信/サイレントスイッチによってオーディオを鳴らなくするかどうか、
オーディオを開始したときにiPodオーディオの再生を継続するかどうかなどの設定が含まれます。
大きい方のオーディオコンテキストには、ユーザによる変更(ヘッドセットを接続しているかどう
かなど)が含まれます。また、電話の着信などのイベントも含まれます。

すべてのiPhone OSアプリケーションは、シングルトンのオーディオセッションオブジェクト(通
常、オーディオセッションと呼ばれる)を取得します。このオブジェクトは、すぐに開発に使用で
きるデフォルトの動作をいくつか備えています。ただし、このデフォルト動作は、例外的な場合を
除いて製品版のアプリケーションには適しません。このオーディオセッションを設定して使用すれ
ば、オーディオの意図を表現し、OSレベルのオーディオ判断に対応できます。

Audio Session Servicesには、表 7-1に示す3つのプログラム機能があります。

表 7-1 オーディオセッションインターフェイスによって提供される機能

オーディオセッション 説明
の機能

カテゴリ カテゴリは、アプリケーションの一連のオーディオ動作を識別するキー
です。カテゴリを設定することによって、オーディオの意図(たとえ
ば、画面がロックされたときにオーディオの再生を続けるかどうかな
ど)をiPhone OSに伝えます。

割り込み、および出力 オーディオ割り込みの発生時、終了時、およびハードウェアのオーディ
先の変更 オ出力先が変更されたときに、オーディオセッションから通知を送りま
す。これらの通知によって、大きい方のオーディオ環境での変更(電話
の着信による割り込みなど)に、うまく応答できるようになります。

ハードウェアの特性 オーディオセッションに問い合わせて、アプリケーションが実行されて
いるデバイスの特性(ハードウェアのサンプルレート、ハードウェアの
チャネル数、オーディオ入力を使用できるかどうかなど)を調べること
ができます。

デフォルトのオーディオセッションを使用すると、Auto-Lock期間がタイムアウトしたり画面がロッ
クしたときに、アプリケーションのオーディオが停止します。画面がロックされても確実に再生を
続けたい場合は、以下の手順を実行します。

1. アプリケーションの初期化コードで、リスト 7-1に示すように、オーディオセッションを初期化
します。オーディオセッションは、カテゴリを割り当てる前に初期化する必要があります。カ
テゴリの割り当ては次のステップで実行します。

リスト 7-1 オーディオセッションの初期化

AudioSessionInitialize (
NULL, // デフォルトの実行ループを使用する
NULL, // デフォルトの実行ループモードを使用する
interruptionCallback, // コールバック関数(NULLに設定することも可能)
userData // コールバックに渡したいデータ
);

138 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

(この関数は、interruptionCallbackパラメータを使用して割り込みリスナコールバック関
数を登録します。(オプションで)オーディオ割り込みが開始または終了したときのアプリケー
ションの動作を指定するコールバックを提供することもできます。そのコールバックは、オー
ディオセッションのカテゴリ設定には関係しないので、画面がロックしたときの動作には影響
しません。)

2. 再生を開始する前に、リスト 7-2に示すように、オーディオセッションのカテゴリを
kAudioSessionCategory_MediaPlaybackに設定します。ほかのカテゴリの中で、このカテゴ
リは、画面のロック時や着信/サイレントスイッチがサイレントに設定されたときに、オーディ
オを継続することを表します。

リスト 7-2 オーディオセッションカテゴリの設定

UInt32 sessionCategory = kAudioSessionCategory_MediaPlayback;

AudioSessionSetProperty (
kAudioSessionProperty_AudioCategory,
sizeof (sessionCategory),
&sessionCategory
);

カテゴリの詳細については、『Audio Session Programming Guide』の「Audio Session Categories」


を参照してください。

電話の着信による割り込みを処理する方法は、アプリケーションで使用しているオーディオテクノ
ロジーによって異なります。それを表 7-2に示します。

表 7-2 オーディオ割り込みの処理方法

オーディオテクノロ 割り込み時の動作
ジー

System Sound Services 割り込みが開始されると、システムサウンドと警告音は鳴らなくなります。


割り込みが終了した場合(ユーザが着信した電話に出ないことを選択した
場合)、これらのサウンドは自動的に使用可能な状態に戻ります。このテ
クノロジーを使うサウンドについて、割り込み時の動作をアプリケーショ
ンが変更することはできません。

Audio Queue 最大限に柔軟な処理が可能であり、割り込み時の動作を制御できます。こ


Services、OpenAL、 れらのテクノロジーを使う場合は、アプリケーションのコード内に割り込
I/Oオーディオユニッ みリスナーコールバック関数を作成します。『Audio Session Programming
ト Guide』の「Responding to Audio Interruptions」の説明を参照してください。

AVAudioPlayerクラ AVAudioPlayerクラスは、割り込みの開始と終了に関するデリゲートメソッ
ス ドを備えています。必要に応じてaudioPlayerBeginInterruption:メソッ
ドを実装することで、ユーザインターフェイスの更新処理ができます。再
生の一時停止と状態の保存は、オーディオプレーヤーオブジェクトによっ
て自動処理されます。audioPlayerEndInterruption:メソッドを実装す
ることで、再生の再開処理と、必要に応じてユーザインターフェイスの更
新処理ができます。オーディオセッションの再アクティブ化は、オーディ
オプレーヤーオブジェクトによって自動処理されます。

iPhone OSでのサウンドの使用 139


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

すべてのiPhone OSアプリケーションは、(稀に例外はありますが)Audio Session Servicesを採用す


るべきです。その方法については、『Audio Session Programming Guide』を参照してください。

オーディオの再生
このセクションでは、System Sound Services、Audio Queue Services、AVAudioPlayerクラス、および
OpenALを使用した、iPhone OSでのサウンドの再生について紹介します。

System Sound Servicesを使用して短いサウンドを再生したり、バイブレーションを


起動する

ユーザインターフェイスのサウンドエフェクト(ボタンのクリック音など)や警告音を再生した
り、デバイス上でバイブレーションを起動するには、System Sound Servicesを使用します。このコン
パクトなインターフェイスについては、『System Sound Services Reference』で説明されています。
iPhone Dev CenterのSysSoundサンプルにサンプルコードがあります。

注: System Sound Servicesを使用して再生されたサウンドは、オーディオセッションを使用した設


定を前提としていません。その結果、System Sound Servicesオーディオの動作を、アプリケーション
のほかのオーディオ動作と同じように管理することはできません。このため、System Sound Services
の本来の目的と異なるオーディオにはSystem Sound Servicesを使わないでください。

AudioServicesPlaySystemSound関数を利用すると、非常に簡単に短いサウンドファイルを再生で
きます。単純化されているために、この関数にはいくつかの制限があります。サウンドファイル
は、以下の条件を満たす必要があります。

■ 長さが30秒未満である
■ リニアPCMフォーマットまたはIMA4 (IMA/ADPCM)フォーマットである
■ .cafファイル、.aifファイル、または.wavファイルになっている

さらに、AudioServicesPlaySystemSound関数を使用する場合は、以下の制限があります。

■ サウンドは現在のシステムオーディオレベルで再生され、レベルの制御はできない
■ すぐに再生される
■ ループおよびステレオポジショニングは利用できない

類似のAudioServicesPlayAlertSound関数は、短いサウンドを警告として再生します。ユーザが
着信設定(Ring Settings)でデバイスをバイブレーションに設定すると、この関数を呼び出すことに
よって、サウンドファイルを再生すると同時にバイブレーションを起動します。

注: システムが提供する警告音と、システムが提供するユーザインターフェイスのサウンドエフェ
クトは、アプリケーションでは利用できません。たとえば、kSystemSoundID_UserPreferredAlert
定数をパラメータとしてAudioServicesPlayAlertSound関数に渡しても、何も再生されません。

AudioServicesPlaySystemSound関数やAudioServicesPlayAlertSound関数でサウンドを再生す
るには、リスト 7-3に示すように、最初にサウンドIDオブジェクトを作成します。

140 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

リスト 7-3 サウンドIDオブジェクトの作成


// アプリケーションのメインバンドルを取得する
CFBundleRef mainBundle = CFBundleGetMainBundle ();

// 再生対象のサウンドファイルのURLを取得する。この場合のファイルは
// "tap.aiff"。
soundFileURLRef = CFBundleCopyResourceURL (
mainBundle,
CFSTR ("tap"),
CFSTR ("aif"),
NULL
);

// このサウンドファイルを表すシステムサウンドオブジェクトを作成する
AudioServicesCreateSystemSoundID (
soundFileURLRef,
&soundFileObject
);

次に、リスト 7-4に示すようにしてサウンドを再生できます。

リスト 7-4 システムサウンドの再生


- (IBAction) playSystemSound {
AudioServicesPlaySystemSound (self.soundFileObject);
}

たびたび、または繰り返し再生するなどの典型的な使いかたでは、アプリケーションが終了するま
でサウンドIDオブジェクトを保持します。起動時のサウンドなど、一度しかサウンドを使用しない
ことがわかっている場合は、サウンドを再生したらすぐにサウンドIDオブジェクトを破棄してメモ
リを解放します。

iPhone OSベースのデバイス上で実行される、バイブレーションをサポートするアプリケーション
は、System Sound Servicesを使用してバイブレーションを起動します。バイブレーションオプション
はkSystemSoundID_Vibrate識別子で指定します。バイブレーションを起動するには、リスト 7-5に
示すように、AudioServicesPlaySystemSound関数を使います。

リスト 7-5 バイブレーションの起動


#import <AudioToolbox/AudioToolbox.h>
#import <UIKit/UIKit.h>
- (void) vibratePhone {
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}

iPod touchでアプリケーションを実行している場合は、このコードでは何も起こりません。

AVAudioPlayerクラスを利用して簡単にサウンドを再生する

AVAudioPlayerクラスは、サウンドを再生するためのObjective-C簡易インターフェイスを提供しま
す。アプリケーションでステレオポジショニングや正確な同期を必要とせず、ネットワークスト
リームからキャプチャしたオーディオを再生しない場合は、このクラスを再生に使用することをお
勧めします。

オーディオプレーヤーを使用すると、次を実行できます。

iPhone OSでのサウンドの使用 141


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

■ 任意の所要時間のサウンドの再生
■ ファイルまたはメモリバッファからのサウンドの再生
■ サウンドのループ再生
■ 複数のサウンドの同時再生
■ 再生中の各サウンドの相対的な再生レベルの制御
■ サウンドファイル内での特定の位置へのシーク(早送りや巻き戻しなどのアプリケーション機
能をサポートします)
■ オーディオレベル測定機能に使用できるオーディオパワーデータの取得

AVAudioPlayerクラスを利用すると、iPhone OSで利用可能な任意のオーディオフォーマット(「オー
ディオの再生フォーマットと録音フォーマット」 (137 ページ)を参照)のサウンドを再生できま
す。このクラスのインターフェイスの詳細については、『AVAudioPlayer Class Reference』を参照して
ください。

オーディオプレーヤーを再生用に設定するには、サウンドファイルを割り当てて、再生の準備を行
い、デリゲートオブジェクトを指定します。リスト 7-6に示すコードの場合、通常は、アプリケー
ションのコントローラクラスの初期化メソッドに移動します。

リスト 7-6 AVAudioPlayerオブジェクトの設定


NSString *soundFilePath =
[[NSBundle mainBundle] pathForResource:@"sound"
ofType:@"wav"];

NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:soundFilePath];

AVAudioPlayer *newPlayer =
[[AVAudioPlayer alloc] initWithContentsOfURL:fileURL
error:nil];
[fileURL release];

self.player = newPlayer;
[newPlayer release];

[self.player prepareToPlay];
[self.player setDelegate:self];

サウンドの再生が完了したときに、デリゲートオブジェクト(コントローラオブジェクトを割り当
てることもできる)を使用して割り込みを処理し、ユーザインターフェイスを更新します。
AVAudioPlayerクラスのデリゲートメソッドについては、『AVAudioPlayerDelegate Protocol Reference』
を参照してください。リスト 7-7は、1つのデリゲートメソッドを簡単に実装したものです。この
コードは、サウンドの再生が完了したときに、「再生/一時停止(Play/Pause)」トグルボタンのタイ
トルを更新します。

リスト 7-7 AVAudioPlayerのデリゲートメソッドの実装


- (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player
successfully:(BOOL) flag {
if (flag == YES) {
[self.button setTitle:@"Play" forState:UIControlStateNormal];
}
}

142 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

AVAudioPlayerオブジェクトを再生、一時停止、または停止するには、そのいずれかの再生制御メ
ソッドを呼び出します。再生が実行中かどうかを調べるには、playingプロパティを使用します。
リスト 7-8は、再生を制御し、UIButtonオブジェクトのタイトルを更新する、基本的な再生/一時
停止切り替えメソッドを示しています。

リスト 7-8 AVAudioPlayerオブジェクトの制御


- (IBAction) playOrPause:(id) sender {

// すでに再生中の場合は一時停止する
if (self.player.playing) {
[self.button setTitle: @"Play" forState: UIControlStateHighlighted];
[self.button setTitle: @"Play" forState: UIControlStateNormal];
[self.player pause];

// 停止または一時停止状態の場合は、再生を開始する
} else {
[self.button setTitle: @"Pause" forState: UIControlStateHighlighted];
[self.button setTitle: @"Pause" forState: UIControlStateNormal];
[self.player play];
}
}

AVAudioPlayerクラスでは、サウンドに関する情報(サウンドのタイムライン内の再生ポイントな
ど)を管理し、再生オプション(音量やループ再生など)にアクセスするために、Objective-Cで宣
言されたプロパティ機能を使用します。たとえば、オーディオプレーヤーの再生音量を設定するに
は次のようにします。

[self.player setVolume: 1.0]; // 使用可能な範囲は0.0~1.0

AVAudioPlayerクラスの詳細については、『AVAudioPlayer Class Reference』を参照してください。

Audio Queue Servicesを使用した制御を伴うサウンドの再生

Audio Queue Servicesは、AVAudioPlayerで利用可能な再生機能に、さらにいくつかの再生機能を追


加します。再生にAudio Queue Servicesを使用すると、以下のことができます。

■ サウンドの再生を正確にスケジューリングし、同期を可能にする
■ 音量を正確に制御する(バッファ単位で)
■ Audio File Stream Servicesを使用してストリームからキャプチャしたオーディオを再生する

Audio Queue Servicesを利用すると、iPhone OSで利用可能な任意のオーディオフォーマット(「オー


ディオの再生フォーマットと録音フォーマット」 (137 ページ)を参照)のサウンドを再生できま
す。「オーディオの録音」 (146 ページ)で説明するように、録音にもこのテクノロジーを使用し
ます。

このテクノロジーの使用の詳細については、『Audio Queue Services Programming Guide』および『Audio


Queue Services Reference』を参照してください。サンプルコードについては、iPhone Dev Centerの
SpeakHereを参照してください(Mac OS Xでの実装については、Core Audio SDKで入手できる
AudioQueueToolsプロジェクトを参照してください。Mac OS XにXcodeツールをインストールした場
合は、AudioQueueToolsプロジェクト
は/Developer/Examples/CoreAudio/SimpleSDK/AudioQueueToolsから利用できます)。

iPhone OSでのサウンドの使用 143


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

オーディオキューオブジェクトの作成

再生のためのオーディオキューオブジェクトを作成するには、次の3つの手順を実行します。

1. 再生するデータのオーディオフォーマットなど、オーディオキューで必要な情報を管理するデー
タ構造を作成します。

2. オーディオキューバッファを管理するコールバック関数を定義します。このコールバック関数
は、Audio File Servicesを使用して再生するファイルを読み込みます(iPhone OS 2.1以降では、
Extended Audio File Servicesを使用してファイルを読み込むこともできます)。

3. AudioQueueNewOutput関数を使用して、再生オーディオキューをインスタンス化します。

リスト 7-9に、ANSI Cを使用した場合のこれらの手順を示します。SpeakHereサンプルプロジェクト


は、Objective-Cプログラムのコンテキストでの同じ手順を示しています。

リスト 7-9 オーディオキューオブジェクトの作成


static const int kNumberBuffers = 3;
// オーディオキューで必要な情報を管理するためのデータ構造を作成する
struct myAQStruct {
AudioFileID mAudioFile;
CAStreamBasicDescription mDataFormat;
AudioQueueRef mQueue;
AudioQueueBufferRef mBuffers[kNumberBuffers];
SInt64 mCurrentPacket;
UInt32 mNumPacketsToRead;
AudioStreamPacketDescription *mPacketDescs;
bool mDone;
};
// 再生オーディオキューのコールバック関数を定義する
static void AQTestBufferCallback(
void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inCompleteAQBuffer
) {
myAQStruct *myInfo = (myAQStruct *)inUserData;
if (myInfo->mDone) return;
UInt32 numBytes;
UInt32 nPackets = myInfo->mNumPacketsToRead;

AudioFileReadPackets (
myInfo->mAudioFile,
false,
&numBytes,
myInfo->mPacketDescs,
myInfo->mCurrentPacket,
&nPackets,
inCompleteAQBuffer->mAudioData
);
if (nPackets > 0) {
inCompleteAQBuffer->mAudioDataByteSize = numBytes;
AudioQueueEnqueueBuffer (
inAQ,
inCompleteAQBuffer,
(myInfo->mPacketDescs ? nPackets : 0),

144 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

myInfo->mPacketDescs
);
myInfo->mCurrentPacket += nPackets;
} else {
AudioQueueStop (
myInfo->mQueue,
false
);
myInfo->mDone = true;
}
}
// オーディオキューオブジェクトをインスタンス化する
AudioQueueNewOutput (
&myInfo.mDataFormat,
AQTestBufferCallback,
&myInfo,
CFRunLoopGetCurrent(),
kCFRunLoopCommonModes,
0,
&myInfo.mQueue
);

再生レベルの制御

オーディオキューオブジェクトには、再生レベルを制御するための方法が2つあります。

再生レベルを直接設定するには、AudioQueueSetParameter関数にkAudioQueueParam_Volumeパラ
メータを渡します。その例をリスト 7-10に示します。レベルの変更はすぐに有効になります。

リスト 7-10 再生レベルの直接設定


Float32 volume = 1; // リニアスケール、範囲は0.0から1.0
AudioQueueSetParameter (
myAQstruct.audioQueueObject,
kAudioQueueParam_Volume,
volume
);

AudioQueueEnqueueBufferWithParameters関数を使用して、オーディオキューバッファの再生レ
ベルを設定することもできます。これを利用すると、実際にオーディオキューバッファが保持する
オーディオキューの設定を、エンキュー時に割り当てることができます。このような変更は、オー
ディオキューバッファが再生を開始するときに有効になります。

どちらの場合も、オーディオキューのレベル変更は、再びそれを変更するまで有効です。

再生レベルの表示

現在の再生レベルは、以下の手順を実行してオーディオキューオブジェクトから取得できます。

1. kAudioQueueProperty_EnableLevelMeteringプロパティをtrueに設定して、オーディオキュー
オブジェクトの測定を有効にする

2. オーディオキューオブジェクトのkAudioQueueProperty_CurrentLevelMeterプロパティを問
い合わせる

iPhone OSでのサウンドの使用 145


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

このプロパティの値はAudioQueueLevelMeterState構造体の配列であり、チャネルごとに1つあり
ます。リスト 7-11に、この構造体を示します。

リスト 7-11 AudioQueueLevelMeterState構造体

typedef struct AudioQueueLevelMeterState {


Float32 mAveragePower;
Float32 mPeakPower;
}; AudioQueueLevelMeterState;

複数のサウンドの同時再生

複数のサウンドを同時に再生するには、サウンドごとに再生オーディオキューオブジェクトを1つ
ずつ作成します。各オーディオキューに対して、AudioQueueEnqueueBufferWithParameters関数
を使用して、オーディオの最初のバッファが同時に開始するように指定します。

iPhone OSベースのデバイスで複数のサウンドを同時に再生する場合、オーディオフォーマットが非
常に重要になります。複数のサウンドを同時に再生するには、リニアPCM(圧縮なし)オーディオ
フォーマット、または特定の圧縮ありのオーディオフォーマット(「オーディオの再生フォーマッ
トと録音フォーマット」 (137 ページ)を参照)を使用します。

OpenALを使用したポジショニングを伴うサウンドの再生

iPhone OSのOpenALフレームワークで利用可能な、オープンソースのOpenALオーディオAPIは、再生
中にステレオ領域でのサウンドのポジショニングを行うために最適化されたインターフェイスを提
供します。OpenALを使用すると、サウンドの再生、ポジショニング、および移動は、ほかのプラッ
トフォームで実行する場合と同様に簡単です。OpenALを使用すると、サウンドのミキシングもでき
ます。OpenALは、再生にCore AudioのI/Oを使用するため、遅延が最小になります。

これらの理由から、iPhone OSベースのデバイス上のゲームアプリケーションでサウンドエフェクト
を再生する場合は、OpenALが最適な選択肢といえます。また、OpenALは一般的なiPhone OSアプリ
ケーションのオーディオ再生ニーズにも適しています。

iPhone OSでサポートされているOpenAL 1.1は、Core Audioの上に構築されています。詳細について


は、『OpenAL FAQ for iPhone OS』を参照してください。OpenALのドキュメントについては、OpenAL
のWebサイト(http://openal.org)を参照してください。OpenALオーディオの再生方法のサンプルコー
ドは、oalTouchを参照してください。

オーディオの録音
Core Audioは、iPhone OSでのAudio Queue Servicesを使用したオーディオの録音をサポートします。
このインターフェイスは、オーディオハードウェアへの接続、メモリの管理、および必要に応じた
コーデックの適用を行います。「iPhone OSの推奨オーディオフォーマット」 (149 ページ)に示し
た任意のフォーマットでオーディオを録音できます。

オーディオを録音するには、アプリケーションでオーディオセッションを設定して、録音用のオー
ディオキューオブジェクトをインスタンス化し、コールバック関数を用意します。このコールバッ
クではオーディオデータを、すぐに使用できるようにメモリに格納したり、長期保存するために
ファイルに書き込んだりします。

146 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

iPhone OSでは、録音はシステムで定義されたレベルで行われます。システムは、ユーザが選択した
オーディオソース、すなわち内蔵マイク、または(接続されている場合は)ヘッドセットのマイ
ク、その他の入力ソースから録音します。

再生の場合と同様に、現在の録音レベルは、オーディオキューオブジェクトの
kAudioQueueProperty_CurrentLevelMeterプロパティを問い合わせて取得できます(「再生レベ
ルの表示」 (145 ページ)を参照)。

Audio Queue Servicesを使用してオーディオを録音する方法の詳細な例については、『Audio Queue


Services Programming Guide』の「Recording Audio」を参照してください。サンプルコードについて
は、iPhone Dev CenterのSpeakHereを参照してください

ストリーミングされたオーディオの解析
ネットワーク接続からなど、ストリーミングされたオーディオコンテンツを再生するには、Audio
Queue Servicesと一緒にAudio File Stream Servicesを使用します。Audio File Stream Servicesは、ネット
ワークのビットストリームの一般的なオーディオファイルコンテナフォーマットからのオーディオ
パケットとメタデータを解析します。ディスク上のファイルのパケットとメタデータを解析するこ
ともできます。

iPhone OSでは、Mac OS Xと同様に、次のオーディオファイルフォーマットとビットストリームフォー


マットを解析できます。

■ MPEG-1 Audio Layer 3。.mp3ファイルに使用する


■ MPEG-2 ADTS。.aacオーディオデータフォーマットに使用する
■ AIFC
■ AIFF
■ CAF
■ MPEG-4。.m4a、.mp4、および.3gpファイルに使用する
■ NeXT
■ WAVE

オーディオパケットを取得したら、iPhone OSでサポートされている任意のフォーマット(「オー
ディオの再生フォーマットと録音フォーマット」 (137 ページ)を参照)で再生できます。

最善のパフォーマンスを実現するには、ネットワークストリーミングアプリケーションではWi-Fi接
続からのデータのみを使用するべきです。iPhone OSでは、System Configurationフレームワークと
SCNetworkReachability.hのインターフェイスを利用して、どのネットワークが到達可能で利用可
能かどうかを判断できます。サンプルコードについては、iPhone Dev CenterのReachabilityを参照し
てください

ネットワークストリームに接続するには、CFHTTPMesaageインターフェイス(『CFHTTPMessage
Reference』を参照)などの、iPhone OSのCore Foundationのインターフェイスを使用できます。Audio
File Stream Servicesを使用して、ネットワークパケットを解析し、オーディオパケットを復元しま
す。次に、そのオーディオパケットをバッファリングして、再生オーディオキューオブジェクトに
送ります。

iPhone OSでのサウンドの使用 147


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

Audio File Stream Servicesは、AudioFramePacketTranslation構造体、AudioFilePacketTableInfo


構造体などのAudio File Servicesのインターフェイスに依存します。これらについては、『Audio File
Services Reference』を参照してください。

ストリームの使用の詳細については、『Audio File Stream Services Reference』を参照してください。サ


ンプルコードについては、<Xcode> /Examples/CoreAudio/Services/ディレクトリにある
AudioFileStreamサンプルプロジェクトを参照してください。<Xcode>は、デベロッパツールディレク
トリへのパスです。

iPhone OSでのオーディオユニットのサポート
iPhone OSは、任意のアプリケーションで使用可能なオーディオプラグインセット(オーディオユ
ニットと呼ばれる)を提供しています。Audio Unitフレームワークのインターフェイスを利用する
と、これらのオーディオユニットをオープン、接続、使用することができます。カスタムオーディ
オユニットを定義して、それをアプリケーション内で使用することもできます。カスタムのオー
ディオユニットコードはアプリケーションに静的にリンクする必要があります。そのため、自分で
作成したオーディオユニットをiPhone OSのほかのアプリケーションで使用することはできません。

表 7-3に、iPhone OSで提供されているオーディオユニットを示します。

表 7-3 サポートされているオーディオユニット

オーディオユニット 説明

3D Mixerユニット kAudioUnitSubType_AU3DMixerEmbedded型の3D Mixerユニットを利用


すると、複数のオーディオストリームをミキシングしたり、ステレオ出
力パンを指定したり、サンプルレートを操作できます。

Multichannel Mixerユ kAudioUnitSubType_MultiChannelMixer型のMultichannel Mixerユニッ


ニット トを利用すると、複数のオーディオストリームをミキシングできます。

Converterユニット kAudioUnitSubType_AUConverter型のConverterユニットを利用する
と、オーディオデータのフォーマットを変換できます。

I/Oユニット kAudioUnitSubType_RemoteIO型のIOユニットを利用すると、オーディ
オの入出力ハードウェアに接続でき、リアルタイムI/Oをサポートしま
す。このオーディオユニットの使用方法のサンプルコードは、aurioTouch
を参照してください。

iPod EQユニット kAudioUnitSubType_AUiPodEQ型のiPod EQユニットは、アプリケーショ


ンで使用できる簡単な、プリセットベースのイコライザを提供します。

iPhoneオーディオのベストプラクティス

オーディオ操作のヒント

表 7-4に、iPhone OSでオーディオコンテンツを操作する際に覚えておくと役立つ基本的なヒントを
示します。

148 iPhone OSでのサウンドの使用


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

表 7-4 オーディオのヒント

ヒント アクション

圧縮オーディオは適切に AAC、MP3、およびALAC (Apple Lossless)のオーディオは、ハードウェア


使用する でデコードされるため効率的ですが、一度に再生できるオーディオス
トリームは1つに制限されます。複数のサウンドを同時に再生する必要
がある場合は、IMA4フォーマット(圧縮あり)またはリニアPCMフォー
マット(圧縮なし)を使用してサウンドを保存します。

必要なデータフォーマッ Mac OS Xのafconvertツールを利用すると、幅広いオーディオデータ


トおよびファイル形式に フォーマットおよびファイル形式に変換できます。「iPhone OSの推奨
変換する オーディオフォーマット」 (149 ページ)およびafconvertのmanペー
ジを参照してください。

オーディオメモリの問題 Audio Queue Servicesを使用してサウンドを再生している場合は、短い


を評価する セグメントのオーディオデータをオーディオキューバッファに送信す
るコールバックを記述します。ディスクアクセスを最小にできるため、
サウンドファイル全体をメモリにロードして再生するのが最適な場合
もあります。また、バッファが一杯になる分だけのデータをロードす
るのが最適な場合もあります。アプリケーションにとってどちらの方
法が最適か、テストして評価してください。

サンプルレートとビット サンプルレートと、サンプルごとのビット数は、圧縮されていないオー
深度を制限して、オー ディオのサイズに直接影響します。このようなサウンドをたくさん再
ディオファイルのサイズ 生する必要がある場合は、これらの値を下げて、オーディオデータの
を小さくする メモリ占有量を削減することを検討します。たとえば、サウンドエフェ
クトに44.1 kHzのサンプリングレートではなく、32 kHz(または、それ
以下)のサンプリングレートを使用しても、妥当な品質が得られます。

適切なテクノロジーを採 警告やユーザインターフェイスのサウンドエフェクトを再生するには、
用する Core AudioのSystem Sound Servicesを使用します。ステレオ領域でサウ
ンドをポジショニングするために便利で高度なインターフェイスがほ
しい場合や、遅延の少ない再生が必要な場合は、OpenALを使用します。
ファイルやネットワークストリームからのオーディオパケットを解析
するには、Audio File Stream Servicesを使用します。1つ以上のサウンド
を簡単に再生するには、AVAudioPlayerクラスを使用します。その他
のオーディオアプリケーション(ストリームオーディオの再生、オー
ディオの録音を含む)には、Audio Queue Servicesを使用します。

遅延の少ないコードにす 再生時の遅延を最小にするには、OpenALを使用するか、IOユニットを
る 直接使用します。

iPhone OSの推奨オーディオフォーマット

圧縮されていない(高品質の)オーディオには、CAFファイルにパッケージされる16ビット、リト
ルエンディアン、リニアPCMオーディオデータを使用します。Mac OS Xでafconvertコマンドライ
ンツールを次のように使用すると、オーディオファイルをこのフォーマットに変換できます。

/usr/bin/afconvert -f caff -d LEI16 {INPUT} {OUTPUT}

iPhone OSでのサウンドの使用 149


2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

afconvertツールを利用すると、幅広いオーディオデータフォーマットおよびファイル形式に変換
できます。詳細については、afconvertのmanページを参照するか、シェルプロンプトでafconvert
-hと入力してください。

圧縮されたオーディオを一度に1つ再生する場合、およびiPodアプリケーションと同時にオーディオ
を再生する必要がない場合は、CAFファイルまたはm4aファイルにパッケージされるAACフォーマッ
トを使用します。

複数のサウンドを同時に再生するときのメモリ使用を少なくするには、IMA4 (IMA/ADPCM)圧縮を使
用します。これによってファイルサイズは削減されますが、展開中はわずかにCPU負荷がかかりま
す。リニアPCMデータと同様に、IMA4データはCAFファイルにパッケージします。

ビデオファイルの再生

iPhoneでは、Media Playerフレームワーク(MediaPlayer.framework)を使用して、アプリケーション
から直接ビデオファイルを再生する機能をサポートしています。ビデオの再生は、フルスクリーン
モードでのみサポートされ、ゲームデベロッパがカットシーンアニメーションを再生したり、その
他のデベロッパがメディアファイルを再生したりするために利用できます。アプリケーションから
ビデオを開始すると、メディアプレーヤーインターフェイスが処理を引き継ぎ、画面を徐々に暗く
した後に、ビデオコンテンツを徐々に表示します。再生を調整するためのユーザコントロール付き
のビデオ再生や、コントロールなしの再生ができます。(図 7-1に示すように)コントロールの一
部または全部を有効にすると、ユーザは音量を変更したり、再生ポイントを変更したり、ビデオを
開始したり停止したりすることができます。これらのコントロールをすべて無効にすると、ビデオ
は最後まで再生されます。

図 7-1 転送コントロール付きのメディアプレーヤーインターフェイス

ビデオの再生を開始するには、再生するファイルのURLを知っている必要があります。アプリケー
ションが提供するファイルの場合は、通常、これはアプリケーションバンドル内のファイルへのポ
インタです。ただし、リモートサーバ上のファイルへのポインタでもかまいません。このURLを使
用して、MPMoviePlayerControllerクラスの新しいインスタンスをインスタンス化します。このク
ラスは、ビデオファイルの再生を統轄し、(転送コントロールが表示されている場合は)転送コン
トロールでのユーザタップなどのユーザとのやり取りを管理します。再生を開始するには、単純に
このコントローラのplayメソッドを呼び出します。

リスト 7-12に、指定したURLのビデオを再生するメソッドの例を示します。この再生メソッドは、
ムービーの再生中に呼び出し側に制御を戻す非同期呼び出しです。ムービーコントローラは、フル
スクリーンビューにムービーをロードし、アプリケーションの既存のコンテンツの前面でムービー
を再生します。再生が終了すると、ムービーコントローラはオブジェクトに通知を送ります。通知
を受け取ったオブジェクトは、不要になったムービーコントローラを解放します。

150 ビデオファイルの再生
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

リスト 7-12 フルスクリーンムービーの再生


-(void)playMovieAtURL:(NSURL*)theURL
{
MPMoviePlayerController* theMovie = [[MPMoviePlayerController alloc]
initWithContentURL:theURL];

theMovie.scalingMode = MPMovieScalingModeAspectFill;
theMovie.movieControlMode = MPMovieControlModeHidden;

// 再生終了通知のための登録
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(myMovieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];

// ムービーの再生は非同期なので、このメソッドはすぐに戻る
[theMovie play];
}

// ムービーが終了したら、コントローラを解放する
-(void)myMovieFinishedCallback:(NSNotification*)aNotification
{
MPMoviePlayerController* theMovie = [aNotification object];

[[NSNotificationCenter defaultCenter] removeObserver:self


name:MPMoviePlayerPlaybackDidFinishNotification
object:theMovie];

// playMovieAtURLで作成されたムービーインスタンスを解放する
[theMovie release];
}

Media Playerフレームワークのクラスの詳細については、『Media Player Framework Reference』を参照


してください。サポートされているビデオフォーマットのリストは、『iPhoneOSTechnologyOverview』
を参照してください。

ビデオファイルの再生 151
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第7章
マルチメディアサポート

152 ビデオファイルの再生
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章

デバイスサポート

iPhone OSは、モバイルコンピューティング体験を魅力的にするさまざまな機能をサポートしていま
す。iPhone OSを通じて、アプリケーションは、加速度センサーやカメラなどのハードウェア機能
や、ユーザのフォトライブラリなどのソフトウェア機能にアクセスできます。以降の各セクション
では、これらの機能について説明しそれらをアプリケーションに組み込む方法を示します。

加速度センサーイベントへのアクセス

加速度センサーは、特定の線形パスに沿って速度の変化を時系列に測定します。iPhoneおよびiPod
touchには、デバイスの主軸に沿って1つずつ、計3つの加速度センサーがあります。この加速度セン
サーを組み合わせることによって、任意の方向へのデバイスの動きを検出できます。このデータを
使用して、デバイスの瞬間的な動きと、重力に対するデバイスの現在の向きの両方を追跡できま
す。

どのアプリケーションも、加速度データを受け取れるUIAccelerometerオブジェクトを1つ持って
います。このクラスのインスタンスを取得するには、UIAccelerometerクラスの
sharedAccelerometerメソッドを使用します。このオブジェクトを使用して、報告の間隔や、加速
度イベントを受け取るカスタムデリゲートを設定します。報告の間隔は、最短で10ミリ秒(100Hz
の更新レートに相当)に設定できます。ただし、ほとんどのアプリケーションはもっと長い間隔で
十分に動作します。デリゲートオブジェクトを割り当てるとすぐに、加速度センサーはそのオブ
ジェクトにデータを送り始めます。その後、デリゲートオブジェクトは指定の更新間隔でデータを
受け取ります。

リスト 8-1に、加速度センサーを設定するための基本的な手順を示します。この例では、更新頻度
は50Hzです。これは、更新間隔20ミリ秒に相当します。myDelegateObjectはカスタムオブジェク
トです。このオブジェクトは、加速度データを受け取る方法を定義するUIAccelerometerDelegate
プロトコルをサポートする必要があります。

リスト 8-1 加速度センサーの設定


#define kAccelerometerFrequency 50 //Hz
-(void)configureAccelerometer
{
UIAccelerometer* theAccelerometer = [UIAccelerometer sharedAccelerometer];
theAccelerometer.updateInterval = 1 / kAccelerometerFrequency;

theAccelerometer.delegate = self;
// デリゲートイベントがすぐに開始する
}

共有の加速度センサーは、一定の間隔でイベントデータをデリゲートの
accelerometer:didAccelerate:メソッドに送付します。その様子をリスト 8-2に示します。この
メソッドを使用して、任意の方法で加速度データを処理できます。一般的には、何らかのフィルタ
を使用して、関心のあるデータ成分を分離する処理をお勧めします。

加速度センサーイベントへのアクセス 153
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

リスト 8-2 加速度センサーイベントの受け取り


- (void)accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration
{
UIAccelerationValue x, y, z;
x = acceleration.x;
y = acceleration.y;
z = acceleration.z;

// 受け取った値を使って何か処理をする
}

加速度イベントの送付を停止するには、UIAccelerometer共有オブジェクトのデリゲートにnilを設
定します。デリゲートオブジェクトにnilを設定すると、システムに、必要に応じて加速度センサー
ハードウェアをオフにしてバッテリー持続時間を節約できることを知らせます。

デリゲートメソッドで受け取る加速度データは、加速度センサーハードウェアによって報告される
瞬間的な値を表します。デバイスがたとえ静止していても、ハードウェアから報告されるこの値は
わずかに変動する可能性があります。これらの値を使用する場合、時間の経過とともに値を平均化
したり、受け取ったデータを補正したりして、必ずこの変動を計算に入れる必要があります。たと
えば、Bubble Levelサンプルアプリケーションでは、既知の表面に対して現在の角度を補正するコン
トロールを提供しています。補正後の計測では、補正後の角度に対する相対角度が報告されます。
自分のコードで同じレベルの精度が必要な場合、そのユーザインターフェイスにも何らかの補正手
段を含めるべきです。

適切な更新間隔の選択
加速度イベントの更新間隔を設定するとき、アプリケーションのニーズを満たしながら、送付され
るイベントの数を最小限に抑える間隔を選択するのが最善です。1秒間に100回も加速度イベントの
送付を必要とするアプリケーションはほとんどありません。低い頻度を採用することでアプリケー
ションが頻繁に動作せずに済むため、バッテリー持続時間を向上させることができます。表 8-1に、
一般的な更新頻度とその頻度で生成された加速度データを使って何ができるかを示します。

表 8-1 加速度イベントの一般的な更新間隔

イベント頻度(Hz) 使用法

10–20 デバイスの現在の向きを表すベクトルを判断するのに適しています。

30–60 ゲーム、またはリアルタイムユーザ入力用に加速度センサーを使用するその他
のアプリケーションに適しています。

70–100 高い頻度でモーションを検出する必要があるアプリケーションに適していま
す。たとえば、この間隔を使って、ユーザがデバイスをたたいたり高速でゆ
すったりすることを検出する場合が考えられます。

154 加速度センサーイベントへのアクセス
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

加速度データからの重力成分の分離
加速度センサーのデータを使用してデバイスの現在の向きを検出する場合は、デバイスの動きによ
る加速度データ成分から、重力による加速度データ成分を取り除く必要があります。それには、
ローパスフィルタを使用して、加速度センサーのデータに対する瞬間的な変化の影響を減らすこと
ができます。フィルタを適用した結果得られた値は、より安定した重力の影響を反映しています。

リスト 8-3に、簡単なローパスフィルタを示します。この例では、低い値のフィルタ係数を使用し
て、フィルタリングされていない加速度データの10%と、直前にフィルタリングした値の90%を使
用した値を生成します。直前の値は、このクラスのメンバ変数であるaccelX、accelY、および
accelZに格納されています。加速度データは規則的になるので、これらの値はすぐに安定し、瞬間
的な動きの変化に対する反応は鈍くなります。

リスト 8-3 加速度センサーのデータからの重力の影響の分離


#define kFilteringFactor 0.1

- (void)accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration {
// 基本的なローパスフィルタを使用して、各軸の重力成分だけを保持する
accelX = (acceleration.x * kFilteringFactor) + (accelX * (1.0 -
kFilteringFactor));
accelY = (acceleration.y * kFilteringFactor) + (accelY * (1.0 -
kFilteringFactor));
accelZ = (acceleration.z * kFilteringFactor) + (accelZ * (1.0 -
kFilteringFactor));

// この加速度データを使用する
}

加速度データからの瞬間的な動きの分離
加速度センサーのデータを使用してデバイスの瞬間的な動きだけを検出する場合は、一定である重
力の影響から瞬間的な動きの変化を分離する必要があります。それには、ハイパスフィルタを使用
します。

リスト 8-4に、簡単なハイパスフィルタの計算を示します。直前のイベントの加速度値は、このク
ラスのメンバ変数であるaccelX、accelY、およびaccelZに格納されています。この例では、瞬間
的な動きの成分だけを取り出すために、ローパスフィルタの値を計算してそれを現在の値から引い
ています。

リスト 8-4 加速度センサーのデータからの瞬間的な動きの取得


#define kFilteringFactor 0.1

- (void)accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration {
// ローパス値を現在の値から引いて、簡単なハイパスフィルタを取得する
accelX = acceleration.x - ( (acceleration.x * kFilteringFactor) + (accelX
* (1.0 - kFilteringFactor)) );
accelY = acceleration.y - ( (acceleration.y * kFilteringFactor) + (accelY
* (1.0 - kFilteringFactor)) );
accelZ = acceleration.z - ( (acceleration.z * kFilteringFactor) + (accelZ
* (1.0 - kFilteringFactor)) );

加速度センサーイベントへのアクセス 155
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

// この加速度データを使用する
}

現在のデバイスの向きの取得
向きの正確なベクトルではなく、単にデバイスの大まかな向きを知る必要がある場合、UIDeviceク
ラスのメソッドを使用してその情報を取得します。UIDeviceインターフェイスを使うのがより簡単
で、デベロッパ自身が向きのベクトルを計算する必要がありません。

現在の向きを取得する前に、beginGeneratingDeviceOrientationNotificationsメソッドを呼び
出すことによって、デバイス向きの通知の生成を開始するようにUIDeviceクラスに指示する必要が
あります。これを行うことで、加速度センサーハードウェアがオンになります。そうでなければ、
節電のためにオフになっている可能性があります。

向きの通知を有効にしたらすぐ、UIDevice共有オブジェクトのorientationプロパティから現在の
向きを取得できます。また、大まかな向きの変化が生じたるたびに送信される、
UIDeviceOrientationDidChangeNotification通知の受け取りを登録することもできます。デバ
イスの向きは、デバイスが横長モードか縦長モードか、デバイスの表面が上に向いているか下に向
いているかを示す、UIDeviceOrientationの定数を使って報告されます。これらの定数は、デバイ
スの物理的な向きを示し、アプリケーションのユーザインターフェイスの向きに対応する必要はあ
りません。

デバイスの向きを知る必要がなくなったら、必ずUIDeviceの
endGeneratingDeviceOrientationNotificationsメソッドを呼び出して、向きの通知を無効にす
るようにします。これを行うことで、システムはほかで加速度センサーハードウェアを使用してい
なければ、加速度センサーハードウェアを無効にできます。

ユーザの現在位置の取得

Core Locationフレームワークを使用すると、デバイスの現在位置を検出してその情報をアプリケー
ションで使用できます。このフレームワークは、デバイスの組み込みハードウェアを利用して、利
用可能な信号情報から三角法によって位置を特定します。次に、その位置をコードに報告し、新規
または更新された信号を受信するとその位置情報を更新します。

Core Locationフレームワークを使用する場合、使用を控えめにするとともに、ロケーションサービ
スを適切に設定してください。位置データを収集するためには、内蔵無線の電源をオンにし、利用
可能な携帯電話の基地局、Wi-Fiホットスポット、またはGPS衛星を照会する必要があります。これ
には数秒かかる場合があります。さらに、より正確な位置データを必要とする場合は、長い時間無
線をオンにしたままにしなければならない可能性もあります。このハードウェアを長時間オンにし
たままにするとデバイスのバッテリーが消費されます。位置情報はそれほど頻繁に変化しないこと
を考慮すると、最初の位置を検出した後は、定期的に更新情報を取得すれば十分です。定期的な位
置の更新が必要な場合に、サービスに最小距離のしきい値を設定することによって、コードで処理
しなければならない位置更新の回数を最小にもできます。

ユーザの現在位置を取得するには、CLLocationManagerクラスのインスタンスを作成して、それに
望みの精度としきい値パラメータを設定します。位置通知の受け取りを開始するには、そのオブ
ジェクトにデリゲートを割り当て、startUpdatingLocationメソッドを呼び出して、ユーザの現在
位置の検出を開始します。新しい位置データが利用可能になると、Location Managerはその割り当て

156 ユーザの現在位置の取得
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

られたデリゲートオブジェクトに通知します。位置の更新がすでに送付されている場合は、次のイ
ベントの送付を待たずに、最新の位置データをCLLocationManagerオブジェクトから直接取得する
こともできます。

リスト 8-5に、startUpdatesカスタムメソッドと、
locationManager:didUpdateToLocation:fromLocation:デリゲートメソッドの実装を示します。
startUpdatesメソッドは、新しいLocation Managerオブジェクトを作成し(まだ作成されていない
場合)、それを使用して位置更新の生成を開始します(この例では、locationManager変数は、
MyLocationGetterクラスで宣言されているメンバ変数です。この変数は、
CLLocationManagerDelegateプロトコルに従います)。このハンドラメソッドは、イベントのタ
イムスタンプを使用してイベントがどの程度新しいかを判断します。古いイベントの場合は、ハン
ドラはそれを無視して、より新しいイベントを待ちます。新しいイベントのときは、ロケーション
サービスを無効にします。

リスト 8-5 位置更新の初期化と処理


#import <CoreLocation/CoreLocation.h>

@implementation MyLocationGetter
- (void)startUpdates
{
// このオブジェクトがまだLocation Managerを持っていない場合は、
// Location Managerを作成する
if (nil == locationManager)
locationManager = [[CLLocationManager alloc] init];

locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;

// 新しいイベント用に、移動のしきい値を設定する
locationManager.distanceFilter = 500;

[locationManager startUpdatingLocation];
}

// CLLocationManagerDelegateプロトコルのデリゲートメソッド
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// 比較的新しいイベントの場合は、節電のために更新をオフする
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 5.0)
{
[manager stopUpdatingLocation];

printf("latitude %+.6f, longitude %+.6f\n",


newLocation.coordinate.latitude,
newLocation.coordinate.longitude);
}
// それ以外の場合は、このイベントをスキップして次のイベントを処理する
}
@end

ユーザの現在位置の取得 157
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

ロケーションサービスは、しばしば最後にキャッシュした位置イベントを即座に返すので、イベン
トのタイムスタンプをチェックすることをお勧めします。おおまかな位置を取得するまで数秒を要
する場合があります。したがって、古いデータは、最後に取得した位置を表す手段としてのみ役立
ちます。イベントを受け取るか判断する手段として精度を使用することもできます。ロケーション
サービスは、より正確なデータを受け取ると、それに応じた修正を反映した精度の値を含む追加イ
ベントを返します。

注: Core Locationフレームワークは、ロケーションクエリが戻るときではなく、それぞれのクエリ
の初めにタイムスタンプの値を記録します。Core Locationは異なる複数の手法を使って測位を取得
するため、クエリは、タイムスタンプが示す時間と異なる順番で戻る場合もあり得ます。結果とし
て、場合によっては新しいイベントが、前のイベントよりわずかに古いタイムスタンプになってい
ても問題ありません。フレームワークは、タイムスタンプの値に関係なく、送付する新しいイベン
トごとに位置データの精度を向上することに重点を置いています。

Core Locationフレームワークのオブジェクトおよびメソッドの詳細については、『Core Location


Framework Reference』を参照してください。

カメラによる写真の撮影

UIKitは、UIImagePickerControllerクラスを通してデバイスのカメラへのアクセスを提供します。
このクラスは、利用可能なカメラを使用して写真を撮影するための標準システムインターフェイス
を提供します。また、写真を撮影した後で、画像のサイズを変更したり画像を切り抜いたりするた
めのオプションのコントロールもサポートします。またこのクラスは、ユーザのフォトライブラリ
から写真を選択するためにも使用できます。

カメラインターフェイスを表すビューは、UIImagePickerControllerクラスによって管理される
モーダルビューです。このビューにはコードから直接アクセスしてはいけません。このビューを表
示するには、現在アクティブなView ControllerのpresentModalViewController:animated:メソッ
ドを呼び出して、UIImagePickerControllerオブジェクトを新しいView Controllerとして渡す必要
があります。インストールされると、このPicker Controllerは自動的にカメラインターフェイスをス
ライドして配置します。カメラインターフェイスは、ユーザが写真を承認するか操作をキャンセル
するまでアクティブなままになります。ユーザが承認またはキャンセルすると、このPicker Controller
は、ユーザの選択をデリゲートに通知します。

UIImagePickerControllerクラスによって管理されるインターフェイスは、一部のデバイスで利用
できない場合があります。カメラインターフェイスを表示する前に、UIImagePickerControllerク
ラスのisSourceTypeAvailable:メソッドを呼び出して、そのインターフェイスが利用可能かどう
かを必ず確認する必要があります。このメソッドの戻り値を、常に尊重してください。このメソッ
ドがNOを返した場合は、現在のデバイスがカメラを搭載していないか、何らかの理由でカメラが現
在利用できない状態にあることを意味します。このメソッドがYESを返した場合は、以下の手順を
実行してカメラインターフェイスを表示します。

1. UIImagePickerControllerの新規オブジェクトを作成します。

2. Picker Controllerにデリゲートオブジェクトを割り当てます。

ほとんどの場合、現在のView Controllerがピッカーに対するデリゲートとしての役割を果たしま
す。ただし、必要であればまったく別のオブジェクトを使用することもできます。このデリゲー
トオブジェクトは、UIImagePickerControllerDelegateプロトコルに従わなければなりませ
ん。

158 カメラによる写真の撮影
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

3. ピッカーのタイプをUIImagePickerControllerSourceTypeCameraに設定します。

4. 必要に応じて、allowsImageEditingプロパティに適切な値を割り当てて、写真編集コントロー
ルを有効または無効にします。

5. 現在のView ControllerのpresentModalViewController:animated:メソッドを呼び出して、こ
のピッカーを表示します。

リスト 8-6に、前述の手順を表すコードを示します。presentModalViewController:animatedメ
ソッドを呼び出すとすぐに、Picker Controllerが処理を引き継ぎ、カメラインターフェイスを表示し、
そのインターフェイスが閉じられるまですべてのユーザ操作に対応します。ユーザのフォトライブ
ラリから既存の写真を選択するには、ピッカーのsourceTypeプロパティの値を
UIImagePickerControllerSourceTypePhotoLibraryに変更するだけです。

リスト 8-6 写真撮影用のインターフェイスの表示


-(BOOL)startCameraPickerFromViewController:(UIViewController*)controller
usingDelegate:(id<UIImagePickerControllerDelegate>)delegateObject
{
if ( (![UIImagePickerController
isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
|| (delegateObject == nil) || (controller == nil))
return NO;

UIImagePickerController* picker = [[UIImagePickerController alloc] init];


picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = delegateObject;
picker.allowsImageEditing = YES;

// ピッカーは非同期に表示される
[controller presentModalViewController:picker animated:YES];
return YES;
}

ユーザがカメラインターフェイスを閉じるために適切なボタンをタップした場合、
UIImagePickerControllerはユーザの選択をデリゲートに通知しますが、インターフェイスを閉じ
ません。ピッカーインターフェイスを閉じるのはデリゲートです(アプリケーションもまた、作業
が終了したらピッカーを解放する責任があります。これは、デリゲートメソッドで行えます)。デ
リゲートが、そもそもピッカーを表示したView Controllerオブジェクトであるのは、このような理由
からです。デリゲートメッセージを受け取ると、View Controllerは、
dismissModalViewControllerAnimated:メソッドを呼び出して、カメラインターフェイスを閉じ
ます。

リスト 8-7は、リスト 8-6 (159 ページ)で表示したカメラインターフェイスを閉じるデリゲートメ


ソッドを示します。これらのメソッドは、MyViewControllerカスタムクラスで実装されています。
この例では、このクラスはUIViewControllerのサブクラスであるため、ピッカーを最初に表示し
たオブジェクトと同じとみなされています。useImage:メソッドは、このクラスの自分独自のバー
ジョンで実行する作業のための空のプレースフォルダです。このメソッドは、カスタムコードで置
き換える必要があります。

リスト 8-7 画像ピッカー用のデリゲートメソッド


@implementation MyViewController (ImagePickerDelegateMethods)

- (void)imagePickerController:(UIImagePickerController *)picker

カメラによる写真の撮影 159
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第8章
デバイスサポート

didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
[self useImage:image];

// ピッカーインターフェイスを削除し、ピッカーオブジェクトを解放する
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}

- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
[picker release];
}

// 自分のコードでこのメソッドを実装して、画像を処理する
- (void)useImage:(UIImage*)theImage
{
}
@end

画像の編集が有効になっている場合、ユーザが1つの画像を選択すると、
imagePickerController:didFinishPickingImage:editingInfo:メソッドのimageパラメータに
編集対象の画像が入ります。この画像は選択された画像として扱う必要があります。ただし、元の
画像を保存しておきたい場合は、editingInfoパラメータの辞書から(クロップ矩形とともに)元
の画像を取得できます。

フォトライブラリからの写真の選択

UIKitは、UIImagePickerControllerクラスを通してユーザのフォトライブラリへのアクセスを提供
します。このコントローラは、写真ピッカーインターフェイスを表示します。このインターフェイ
スは、ユーザのフォトライブラリ内を移動したり、1つの画像を選択してアプリケーションに返す
ためのコントロールを提供します。また、ユーザ編集用のコントロールを有効にするオプションも
あります。これを利用して、ユーザは返された画像をパンしたりクロップしたりできます。このク
ラスは、カメラインターフェイスを表示するためにも使用できます。

UIImagePickerControllerクラスは、カメラとユーザのフォトライブラリの両方のインターフェイ
スを表示するために使用されるので、このクラスを使用する手順はどちらの場合もほとんど同じで
す。唯一の違いは、ピッカーオブジェクトのsourceTypeプロパティに、
UIImagePickerControllerSourceTypePhotoLibraryの値を割り当てる点です。カメラのピッカー
を表示する手順は、「カメラによる写真の撮影」 (158 ページ)で説明しています。

注: カメラピッカーの場合と同様に、必ずUIImagePickerControllerクラスの
isSourceTypeAvailable:クラスメソッドを呼び出し、メソッドから返された値を尊重する必要が
あります。対象デバイスにフォトライブラリが存在することを前提にしてはなりません。たとえ、
デバイスにライブラリが存在しても、そのライブラリが現在利用できなければ、このメソッドはNO
を返します。

160 フォトライブラリからの写真の選択
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章

アプリケーション環境設定

従来のデスクトップアプリケーションでは、環境設定はアプリケーションの動作や外観を設定する
のに使われるアプリケーション固有の設定です。iPhone OSでも、アプリケーションに必須の部分と
してではありませんが、アプリケーション環境設定をサポートしています。ただし、カスタムの
ユーザインターフェイスを使ってアプリケーションごとに環境設定を表示するのではなく、すべて
のアプリケーションレベルの環境設定が、システムの提供する「設定(Settings)」アプリケーション
を使って表示されます。

カスタムのアプリケーション環境設定を「設定(Settings)」アプリケーションに組み込むには、アプ
リケーションバンドルの最上位ディレクトリに専用の書式をもつSettingsバンドルを含める必要があ
ります。このSettingsバンドルは、「設定(Settings)」アプリケーションにアプリケーションの環境設
定に関する情報を提供します。「設定(Settings)」アプリケーションは、それらの環境設定を表示し、
ユーザが指定する値で環境設定データベースを更新します。実行時には、アプリケーションが環境
設定取得用の標準APIを使ってこれらの環境設定を取得します。以降の各セクションでは、Settings
バンドルの書式と環境設定の値を取得するのに使用するAPIの両方について説明します。

環境設定のためのガイドライン

アプリケーションの環境設定を「設定(Settings)」アプリケーションに追加するのに最も適している
のは、生産性型アプリケーションであり、一度設定した環境設定の値がほとんど変更されないよう
な場合です。たとえば、「メール(Mail)」アプリケーションでは、これらの環境設定を使用してユー
ザのアカウント情報とメッセージチェックの設定を格納します。「設定(Settings)」アプリケーショ
ンでは環境設定を階層的に表示できるため、環境設定が数多くある場合にも、「設定(Settings)」ア
プリケーションから環境設定を操作するのがより適しています。アプリケーションでそのような一
連の環境設定を用意すると、必要となる画面が多すぎて、ユーザを混乱させてしまう可能性があり
ます。

アプリケーションがごく少数のオプションを備えている場合や、ユーザが頻繁に変更するオプショ
ンを備えている場合、「設定(Settings)」アプリケーションにそれらを置くのが妥当なのかを慎重に
検討する必要があります。たとえば、ユーティリティ型アプリケーションは、メインビューの裏面
でカスタムの設定オプションを提供します。ビュー上にある専用のコントロールを使ってビューを
反転してオプションを表示し、別のコントロールを使ってビューを元に戻せます。簡単なアプリ
ケーションでは、こうした動作によってアプリケーションのオプションへすばやくアクセスするこ
とができるため、「設定(Settings)」に移動するよりもユーザにとってははるかに便利です。

ゲームやその他のフルスクリーンのアプリケーションでは、「設定(Settings)」アプリケーションを
使用したり、環境設定のためのカスタムスクリーンを独自に実装できます。多くの場合、カスタム
スクリーンはゲームに適しています。ゲーム設定の一部として扱われるためです。ゲームの流れに
とって妥当と考えられる場合は、環境設定に「設定(Settings)」アプリケーションを使用することも
できます。

環境設定のためのガイドライン 161
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

注: 「設定(Settings)」アプリケーションとアプリケーションのカスタムスクリーンにまたがって環
境設定を分散させるべきではありません。たとえば、メインビューの裏側に環境設定をもったユー
ティリティ型アプリケーションは、「設定(Settings)」アプリケーションに設定可能な環境設定をも
つべきではありません。環境設定がある場合には、いずれかの方法を採用してそれだけを使用する
ようにします。

環境設定インターフェイス

「設定(Settings)」アプリケーションは、アプリケーションの環境設定を行き来するための一連のペー
ジを階層構造として実装しています。「設定(Setting)」アプリケーションのメインページには、環
境設定をカスタマイズできるシステムおよびサードバーティ製アプリケーションが表示されます。
サードパーティ製アプリケーションを選択すると、そのアプリケーションの環境設定へ移動しま
す。

各アプリケーションには、メインページと呼ばれる環境設定のページが少なくとも1ページありま
す。アプリケーションの環境設定がごく少数の場合、必要なページはメインページのみという場合
もあります。一方、環境設定の数が多く、メインページに収まらない場合はページを追加できま
す。これらの追加ページはメインページの子ページになります。ユーザが子ページにアクセスする
には、新しいページにリンクしている特別なタイプの環境設定をタップします。

表示するそれぞれの環境設定は、特定のタイプである必要があります。環境設定のタイプによっ
て、その環境設定が「設定(Settings)」アプリケーションにどのように表示されるかが決まります。
ほとんどの環境設定のタイプは、環境設定の値を設定するために使用される特定のコントロールの
タイプを示します。一方、環境設定を編成するための方法を提供するタイプもあります。表 9-1に、
「設定(Settings)」アプリケーションでサポートされているさまざまな要素のタイプと、環境設定ペー
ジを独自に実装するためにそれぞれのタイプを使用する方法を示します。

表 9-1 環境設定の要素のタイプ

要素のタイ 説明

Text Field Text Fieldタイプは、省略可能なタイトルと編集可能なテキストフィールドを表示し


ます。このタイプは、カスタムの文字列値をユーザが指定する必要のある環境設定
に使用します。
このタイプのキーはPSTextFieldSpecifierです。

Title Titleタイプは、読み取り専用の文字列の値を表示します。このタイプは、読み取り
専用の環境設定の値を表示するために使用できます(環境設定に分かりにくい値や
直感的に把握できない値がある場合、このタイプを使用して候補となる値をカスタ
ム文字列にマッピングできます)。
このタイプのキーはPSTitleValueSpecifierです。

Toggle Toggle Switchタイプは、オン/オフ(ON/OFF)のトグルボタンを表示します。こ


Switch のタイプを使って、二者択一型の環境設定を設定できます。一般的に、このタイプ
を使用してブール値を含む環境変数を表せますが、ブール値以外の値を含む環境変
数にも使うことができます。
このタイプのキーはPSToggleSwitchSpecifierです。

162 環境設定インターフェイス
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

要素のタイ 説明

Slider Sliderタイプは、スライダコントロールを表示します。このタイプは、特定の範囲の
値をもつ環境変数に使用できます。このタイプの値は実数で、その最小値と最大値
はデベロッパが指定します。
このタイプのキーはPSSliderSpecifierです。

Multi Value Multi Valueタイプは、候補値の一覧から1つの値をユーザに選択させます。このタイ


プは、相互に排他的な値をサポートする環境設定に使用できます。任意の型の値を
設定できます。
このタイプのキーはPSMultiValueSpecifierです。

Group Groupタイプは、1つのページに環境設定の複数のグループを編成するのに使用しま
す。Groupタイプは、設定可能な環境設定ではありません。設定可能な1つ以上の環
境設定の直前に表示するタイトル文字列が含まれているだけです。
このタイプのキーはPSGroupSpecifierです。

Child Pane Child Paneタイプは、環境設定の新しいページにユーザを移動させます。このタイプ


を使用して階層型の環境設定を実装できます。この環境設定タイプの設定方法、お
よび使用方法の詳細については、「階層型環境設定」 (165 ページ)を参照してく
ださい。このタイプのキーはPSChildPaneSpecifierです。

それぞれの環境設定タイプの形式の詳細については、『Settings Application Schema Reference』を参照


してください。「設定(Setting)」ページのファイルの作成と編集の方法を学習するには、「Settings
バンドルの追加と変更」 (167 ページ)を参照してください。

Settingsバンドル

iPhone OSでは、専用のSettingsバンドルを使用してアプリケーションの環境設定を指定します。こ
のバンドルはSettings.bundleという名前で、アプリケーションバンドルの最上位ディレクトリに
置かれます。バンドルには、1つ以上のSettings Pageファイルが含まれており、このファイルがアプ
リケーションの環境設定に関する詳細情報を提供します。バンドルには、画像やローカライズされ
た文字列など、環境設定の表示に必要なその他のサポートファイルも含まれます。表 9-2に、標準
的なSettingsバンドルの内容を示します。

表 9-2 Settings.bundleディレクトリの内容

項目名 説明

Root.plist ルートページの環境設定を含むSettings Pageファイル。このファイルの内


容の詳細については、「Settings Pageのファイル形式」 (164 ページ)で説
明しています。

その他の.plistファ Child Paneタイプを使用した階層型環境設定のセットを構築すると、それ


イル ぞれの子ペインの内容は別々のSettings Pageファイルに保存されます。こ
れらのファイル名の指定と、正しい子ペインにこれらのファイルを関連付
ける責任はデベロッパにあります。

Settingsバンドル 163
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

項目名 説明

1つ以上の.lprojディ これらのディレクトリには、Settings Pageファイルのローカライズされた


レクトリ 文字列リソースが格納されます。それぞれのディレクトリには1つの文字
列ファイルが含まれ、そのタイトルはSettings Pageで指定されます。文字
列ファイルは、それぞれの環境設定をユーザに対して表示するためのロー
カライズされた内容を提供します。

その他の画像 スライダコントロールを使用する場合、スライダの画像をバンドルの最上
位のディレクトリに保存できます。

アプリケーションバンドルには、Settingsバンドルに加えて、アプリケーション設定用のカスタムア
イコンを含めることができます。Icon-Settings.pngという名前のファイルがアプリケーションバ
ンドルのディレクトリの最上位にあれば、そのアイコンが「設定(Settings)」アプリケーションにお
いて、アプリケーションの環境設定を示すのに使用されます。そのような画像ファイルがない場
合、「設定(Settings)」アプリケーションは代わりにアプリケーションのアイコンファイル(デフォ
ルトでは、Icon.png)を使用し、必要に応じて拡大縮小します。Icon-Settings.pngファイルは、
29×29ピクセルの画像にします。

「設定(Settings)」アプリケーションは起動すると、各カスタムアプリケーションを確認してSettings
バンドルがあるかどうかをチェックします。カスタムバンドルを見つけると、そのバンドルをロー
ドし、対応するアプリケーション名とアイコンを「設定(Settings)」のメインページに表示します。
ユーザがアプリケーションに対応する行をタップすると、「設定(Settings)」は該当するSettingsバン
ドルのRoot.plist Settings Pageファイルをロードし、そのファイルを使用してアプリケーションの
環境設定のメインページを表示します。

バンドルのRoot.plist Settings Pageファイルをロードするほかに、「設定(Settings)」アプリケー


ションでは必要に応じてそのファイルの言語固有のリソースもロードします。各Settings Pageファ
イルには、ユーザに表示する文字列をローカライズした値を含んだ.stringsファイルを関連付ける
ことができます。「設定(Settings)」アプリケーションは、表示する環境設定を用意する際に、ユー
ザの優先言語に対応する文字列リソースを探し、環境設定のページでそれらを置き換えてから表示
します。

Settings Pageのファイル形式
SettingsバンドルのそれぞれのSettings Pageファイルは、構造化されたファイル形式であるiPhone
Settingsプロパティリストファイル形式で保存されます。Settings Pagesファイルを編集する最も簡単
な方法は、Xcodeに組み込みのエディタ機能を使用することです。「編集用のSettings Pageの準
備」 (167 ページ)を参照してください。Xcodeツールに付属のProperty List Editorアプリケーション
を使って、プロパティリストファイルを編集することもできます。

注: アプリケーションをビルドするとき、Xcodeはプロジェクト内のすべてのXMLベースのプロパ
ティファイルを自動的にバイナリ形式に変換します。この変換によりスペースが節約されます。こ
れはビルド時に自動的に行われます。

各Settings Pageファイルのルート要素には、表 9-3に示すキーが含まれます。実際に必要なキーは1


つだけですが、両者を含めることをお勧めします。

164 Settingsバンドル
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

表 9-3 環境設定のSettings Pageファイルのルートレベルキー

キー 型 値

PreferenceSpecifiers 配列 このキーの値は辞書配列です。それぞれの辞書には1つの環境
(必須) 設定要素が含まれます。要素タイプの一覧については、表
9-1 (162 ページ)を参照してください。それぞれの要素のタイ
プに対応するキーの説明については、『Settings Application
Schema Reference』を参照してください。

StringsTable 文字列 このファイルに関連付けられた文字列ファイルの名前です。こ


のファイルのコピー(適切にローカライズされた文字列を含
む)は、それぞれのバンドルの言語固有のプロジェクトディレ
クトリに配置する必要があります。このキーを含めない場合、
このファイルの文字列はローカライズされません。これらの文
字列がどのように使用されるかについては、「ローカライズさ
れたリソース」 (166 ページ)を参照してください。

階層型環境設定
環境設定を階層構造にする場合は、定義する各ページがそれぞれ独立の.plistファイルを持つ必要
があります。各.plistファイルには、そのページにのみ表示される環境設定一式を含めます。アプ
リケーションの環境設定のメインページは、必ずRoot.plistファイルに格納します。追加のページ
には任意の名前をつけられます。

親ページと子ページとの間のリンクを指定するには、Child Pane要素を親ページ内に含めます。子ペ
インの要素は1つの行を作成します。この行をタップすると、新しい設定ページが表示されます。
子ペイン要素のFileキーは、子ページのコンテンツを定義した.plistファイルの名前を表します。
Titleキーは、子ページのタイトルを表します。このタイトルは、子ページを表示するためにユー
ザがタップする行のテキストとしても使われます。「設定(Settings)」アプリケーションは、ユーザ
が親ページに戻るためのナビゲーションコントロールを子ページ上に自動的に表示します。

図 9-1に、一連の階層型ページの仕組みを示します。図の左側は.plistファイルを表し、右側は対
応する各ページの関係を示します。

Settingsバンドル 165
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

図 9-1 子ペインを使った環境設定の編成

Sounds
Group 1
New Voicemail
New Email
Settings
Sent Mail
Group 1
Usage Group 2
Ringtones
Group 2
Sounds
Brightness
Sounds.plist Wallpaper
Sounds page
Group 3
General General
Root.plist Group 1
Root page
Date & Time
Network
Keyboard
General.plist

General page

子ペインの要素とそれに関連するキーの詳細については、『Settings Application Schema Reference』を


参照してください。

ローカライズされたリソース
環境設定にはユーザに表示する文字列が含まれるため、Settingsバンドルにこれらの文字列をローカ
ライズしたものを含めて提供する必要があります。それぞれの環境設定のページには、バンドルで
サポートするローカライズごとに、.stringsファイルを関連付けることができます。「設定
(Settings)」アプリケーションは、ローカライズ可能なキーを検出すると、適切なローカライ
ズ.stringsファイルに、一致するキーがあるか確認します。該当するキーが見つかれば、そのキー
に対応する値を表示します。

.stringsファイルなどのローカライズされたリソースを探す場合、「設定(Settings)」アプリケー
ションはMac OS Xアプリケーションと同じ規則に従います。まず、ユーザが選択した言語設定に一
致するリソースのローカライズされたバージョンを探します。ユーザが選択した言語のリソースが
存在しない場合、適切な代替言語が選択されます。

文字列ファイルの形式、言語固有のプロジェクトディレクトリ、および言語固有のリソースをバン
ドルから取得する方法の詳細については、『Internationalization Programming Topics』を参照してくだ
さい。

166 Settingsバンドル
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

Settingsバンドルの追加と変更

Xcodeでは、現在のプロジェクトにSettingsバンドルを追加するためのテンプレートを提供していま
す。デフォルトのSettingsバンドルには、Root.plistファイルと、任意のローカライズされたリソー
スを格納するためのデフォルトの言語ディレクトリが含まれています。デベロッパは、このバンド
ルを拡張して、Settingsバンドルで必要な追加のプロパティリストファイルやリソースを含めること
ができます。

Settingsバンドルの追加
XcodeプロジェクトにSettingsバンドルを追加するには、次の手順を実行します。

1. 「ファイル(File)」>「新規ファイル(New File)」を選びます。

2. 「iPhone OS」>「Settings」>「Settings Bundle」テンプレートを選択します。

3. ファイルにSettings.bundleと名前を付けます。

Xcodeは、プロジェクトに新規Settingsバンドルを追加するほかに、アプリケーションのターゲット
のCopy Bundle Resourcesビルドフェーズにそのバンドルを自動的に追加します。つまり、デベロッ
パが行う必要があるのは、Settingsバンドルのプロパティリストファイルを修正し、必要なリソース
を追加することだけです。

新しく追加されたSettings.bundleバンドルの構造は、以下のとおりです。

Settings.bundle/
Root.plist
en.lproj/
Root.strings

編集用のSettings Pageの準備
Settings Bundleテンプレートを使用してSettingsバンドルを作成したら、スキーマファイルの内容を
書式化して編集しやすくできます。以下の手順は、SettingsバンドルのRoot.plistファイルに対し
てこれを実行する方法を示していますが、ほかのスキーマファイルの場合も手順は同じです。

1. SettingsバンドルのRoot.plistファイルの内容を表示します。

a. 「グループとファイル(Groups & Files)」リストで、Settings.bundleを開き、内容を表示し


ます。

b. Root.plistファイルを選択します。詳細ビューにその内容が表示されます。

2. 詳細ビューで、Root.plistファイルのRootキーを選択します。

3. 「表示(View)」>「プロパティリストタイプ(Property List Type)」>「iPhone Settings plist」を選


択します。

Settingsバンドルの追加と変更 167
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

このコマンドは、詳細ビュー内のプロパティリストの内容を書式化します。プロパティリスト
のキー名と値を表示する代わりに、Xcodeは、そのファイルの内容を理解したり編集しやすくす
るために、わかりやすい文字列に置き換えます(図 9-2を参照)。

図 9-2 書式化されたRoot.plistファイルの内容

Settings Pageの設定:チュートリアル
このセクションには、Settingsページを設定して、必要なコントロールを表示する方法を示したチュー
トリアルが含まれています。このチュートリアルの目的は、図 9-2に示すようなページを作成する
ことです。プロジェクト用のSettingsバンドルをまだ作成していない場合は、この手順に進む前に、
「編集用のSettings Pageの準備」 (167 ページ)で説明した手順を実行してください。

168 Settingsバンドルの追加と変更
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

図 9-3 ルートのSettingsページ

1. Settings Page Titleキーの値を、アプリケーションの名前に変更します。

YOUR_PROJECT_NAMEテキストをダブルクリックし、そのテキストをMyAppに変更します。

2. Preference Itemsキーを展開し、テンプレートに含まれているデフォルトのアイテムを表示しま
す。

3. Item 1のタイトルをSoundに変更します。

■ Preference ItemsのItem 1を開きます。

■ Titleキーの値をGroupからSoundに変更します。

■ TypeキーはGroupに設定されたままにします。

4. 新たに名前変更したSoundグループに、第1のトグルスイッチを作成します。

■ Preference ItemsのItem 3を選択し、「編集(Edit)」>「カット(Cut)」を選びます。

■ Item 1を選択し、「編集(Edit)」>「ペースト(Paste)」を選びます(これによって、Text Field


Itemの前にToggle Switch Itemが移動します)。
■ Toggle Switch Itemを開き、設定用のキーを表示します。
■ Titleキーの値をPlay Soundsに変更します。

■ Identifierキーの値をplay_sounds_preferenceに変更します。これで、このアイテムは
次の図に示すように設定されます。

Settingsバンドルの追加と変更 169
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

5. Soundグループに第2のToggle Switchを作成します。

■ Item 2 (Play Sounds Toggle Switch)を選択します。

■ 「編集(Edit)」>「コピー(Copy)」を選択します。
■ 「編集(Edit)」>「ペースト(Paste)」を選択します。これで、このToggle Switchは第1のスイッ
チのすぐ後に配置されます。
■ この新しいToggle Switch Itemを展開し、設定用のキーを表示します。
■ Titleキーの値を3D Soundに変更します。

■ Identifierキーの値を3D_sound_preferenceに変更します。

この時点で、設定の第1グループは完成し、User Infoグループを作成する準備ができました。

6. Item 4をGroup要素に変更し、その名前をUser Infoにします。

■ Preferences ItemsのItem 4をクリックします。アイテムタイプリストのドロップダウン


メニューが表示されます。
■ このドロップダウンメニューから、Groupを選択し、この要素のタイプを変更します。

170 Settingsバンドルの追加と変更
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

■ Item 4の内容を展開します。

■ Titleキーの値をUser Infoに設定します。

7. Nameフィールドを作成します。

■ Preferences ItemのItem 5を選択します。


■ ドロップダウンメニューを使用して、タイプをText Fieldに変更します。
■ Titleキーの値をUser Infoに設定します。

■ Identifierキーの値をuser_nameに設定します。

■ このアイテムの展開ボタンを切り替えて、内容を非表示にします。

8. Experience Levelの設定を作成します。

■ Item 5を選択し、プラス記号(+)ボタンをクリックして(または、Returnキーを押して)、
新しいアイテムを作成します。
■ 新しいアイテムをクリックし、タイプをMulti Valueに設定します。
■ アイテムの内容を展開し、TitleをExperience Levelに設定します。また、Identifierを
experience_preferenceに、Default Valueを0に設定します。

■ Default Valueキーが選択されている状態で、プラス記号ボタンをクリックし、Titles配列を
追加します。

Settingsバンドルの追加と変更 171
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

■ Titles配列の展開ボタンを開き、テーブルの右端にあるアイテムボタンをクリックします。
このボタンをクリックすると新しいサブアイテムをTitlesに追加します。
■ この新しいサブアイテムを選択し、プラス記号ボタンをもう2回クリックし、合計3個のサ
ブアイテムを作成します。
■ これらのサブアイテムの値を、Beginner、Expert、およびMasterに設定します。
■ Titlesキーを再度選択し、展開ボタンをクリックしてサブアイテムを非表示にします。

■ プラス記号ボタンをクリックし、Values配列を作成します。
■ 3つのサブアイテムをValues配列に追加し、その値を0、1、2に設定します。
■ Item 6の展開ボタンをクリックし、その内容を非表示にします。

9. 最後のグループをSettingsページに追加します。

■ 新しいアイテムを作成し、TypeをGroupに設定します。また、TitleをGravityに設定します。
■ 新しいアイテムをもう1つ作成し、TypeをSliderに設定します。また、Identifierを
gravity_preferenceに、Default Valueを1に、Maximum Valueを2に設定します。

追加のSettings Pageファイルの作成
Settings BundleテンプレートにはRoot.plistファイルが含まれています。このファイルは、アプリ
ケーションの最上位のSettingsページを定義します。追加のSettingsページを定義するには、Settings
バンドルにプロパティリストファイルを追加する必要があります。この操作は、FinderまたはXcode
から実行できます。

XcodeでSettingsバンドルにプロパティファイルを追加するには、次の手順を実行します。

1. 「グループとファイル(Groups & Files)」ペインで、Settingsバンドルを開き、Root.plistファイ


ルを選択します。

2. 「ファイル(File)」>「新規ファイル(New)」を選びます。

3. 「Other」>「Property List」を選びます。

4. 新しいファイルを選択して、「表示(View)」>「プロパティリストタイプ(Property List Type)」>


「iPhone Settings plist」を選び、それをSettingsファイルとして設定します。

新しいSettingsページをSettingsバンドルに追加したら、「Settings Pageの設定:チュートリア
ル」 (168 ページ)での説明にあるように、そのページの内容を編集できます。このページの設定
を表示するには、「階層型環境設定」 (165 ページ)で説明したように、Child Pane要素から参照す
る必要があります。

172 Settingsバンドルの追加と変更
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

環境設定へのアクセス

iPhoneアプリケーションでは、FoundationフレームワークおよびCore Foundationフレームワークの
いずれかを使用して環境設定の値を取得したり設定したりします。Foundationフレームワークでは、
NSUserDefaultsクラスを使用して環境設定の値の取得と設定を行います。Core Foundationフレーム
ワークでは、環境設定に関連するいかくつかの関数を使用して値の取得と設定を行います。

リスト 9-1に、アプリケーションから環境設定の値を読み取る方法の簡単な例を示します。この例
では、NSUserDefaultsクラスを使用して環境設定からブール値を読み取り、それをアプリケーショ
ン固有のインスタンス変数に代入しています。

リスト 9-1 アプリケーションの環境設定の値へのアクセス


- (void)applicationDidFinishLaunching:(UIApplication *)application
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[self setMyAppBoolProperty:[defaults boolForKey:MY_BOOL_PREF_KEY]];

// アプリケーションの初期化を終了
}

環境設定の読み取りと書き込みに使用するNSUserDefaultsメソッドの詳細については、
『NSUserDefaults Class Reference』を参照してください。環境設定の読み取りと書き込みに使用する
Core Foundation関数の詳細については、『Preferences Utilities Reference』を参照してください。

シミュレートしたアプリケーションの環境設定のデバッグ

iPhone Simulatorでアプリケーションを実行すると、アプリケーションの環境設定の値はすべて~/ラ
イブラリ/Application Support/iPhone
Simulator/User/Applications/<APP_ID>/Library/Preferencesに保存されます。<APP_ID>は、
iPhone OSがアプリケーションを識別するために使用するディレクトリ名で、プログラムによって生
成されます。

アプリケーションをインストールするたびに、iPhone OSはクリーンインストールを実行してそれま
での環境設定を削除します。つまり、Xcodeからアプリケーションをビルドしたり実行したりする
と、常に新しいバージョンがインストールされ、古いコンテンツはすべて置き換えられるというこ
とです。実行を重ねる間の環境設定の変更をテストするには、Xcodeからではなくシミュレータイ
ンターフェイスから直接アプリケーションを実行する必要があります。

環境設定へのアクセス 173
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
第9章
アプリケーション環境設定

174 シミュレートしたアプリケーションの環境設定のデバッグ
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
改訂履歴

書類の改訂履歴

この表は「iPhoneアプリケーションプログラミングガイド」の改訂履歴です。

日付 メモ

2009-01-06 誤字をいくつか訂正し、「設定(Settings)」アプリケーションの子ページ
作成プロセスを分かりやすくしました。

2008-11-12 浮動小数点演算の考慮事項についてガイダンスを追加しました。

iTunesでのバックアップに関連する情報を更新しました。

2008-10-15 文書の内容を編成しなおしました。

『iPhone OS Technology Overview』に、iPhone OSの高度な情報を移動しま


した。

『Apple URL Scheme Reference』に、標準システムのURLスキームについて


の情報を移動しました。

『iPhone Development Guide』に、開発ツール、およびデバイスの設定方


法についての情報を移動しました。

アプリケーションアーキテクチャを紹介し、iPhoneアプリケーション作
成についての多くのガイダンスを取り上げている「コアアプリケーショ
ン」の章を作成しました。

TextクラスとWebクラスの使用および画面上のキーボード操作について取
り上げた「テキストとWeb」の章を追加しました。

「ファイルとネットワーク」の章を作成し、外部の情報をここに移動し
ました。

『iPhone OS Programming Guide』からドキュメント名を変更しました。

2008-07-08 iPhone OSおよびiPhone OSアプリケーションの開発プロセスについて説明


する新規文書。

175
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.
改訂履歴
書類の改訂履歴

176
2009-01-06 | © 2009 Apple Inc. All Rights Reserved.

You might also like