70
102-0072 東京都千代田区飯田橋 4-7-1 ロックビレイビル 8F TEL 03-4577-4520 FAX 03-6843-0961 Delphi Prism XE による iPhoneiPod touchiPad 向け開発 Brian Long Consultancy & Training Services Ltd 2011 2

iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

〒102-0072 東京都千代田区飯田橋 4-7-1 ロックビレイビル 8F TEL 03-4577-4520 FAX 03-6843-0961

Delphi Prism XE による

iPhone、iPod touch、iPad 向け開発 Brian Long Consultancy & Training Services Ltd 2011 年 2 月

Page 2: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 1

概要

iPhone® がスマートフォン市場において成功を収め、開発者に iPhone 向けアプリケーション開発という新

しい分野を切り開いたことは疑うまでもありません。当初、iPhone アプリケーションは、Apple の

CocoaTouch フレームワークを直接用いる Objective-C プログラマのみを対象としていましたが、現在で

はこれは当てはまりません。

エンバカデロの Delphi Prism®は、Novell®が提供する Mono®と MonoTouch を組み合わせることで、

iPhone に配布できるネイティブアプリケーションを開発、デバッグするために必要なすべての機能を提供

します。このホワイトペーパーでは、Delphi Prism を用いて iPhone アプリケーション構築の手順を紹介し、

さまざまなテクニックや共通のアプリケーション機能を見ていきます。

目次

概要 .................................................................................................................................................................... 1

はじめに ............................................................................................................................................................ 3

準備 .................................................................................................................................................................... 5

iOS SDK のインストール ........................................................................................................................... 5

Mono のインストール ................................................................................................................................ 6

MonoDevelop のインストール ................................................................................................................. 6

Delphi Prism のインストール .................................................................................................................... 6

MonoTouch SDK のインストール ............................................................................................................ 6

先に進む前に ................................................................................................................................................ 7

MonoTouch でのアプリケーションの開発 .................................................................................................. 8

Interface Builder と UI ............................................................................................................................... 9

アウトレット .............................................................................................................................................. 11

CocoaTouch のアクションとイベント .................................................................................................. 13

CocoaTouch アクションのイベント ハンドラ ...................................................................................... 14

iPhone シミュレータ ................................................................................................................................ 15

テキスト入力キーボード .......................................................................................................................... 16

ドキュメントの利用 .................................................................................................................................. 17

ファースト レスポンダ ............................................................................................................................. 18

MonoTouch イベントのイベント ハンドラ ........................................................................................... 18

ビュー コントローラ ................................................................................................................................. 19

SQLite の利用 ............................................................................................................................................ 21

テーブル ビューのデータ ソース ............................................................................................................. 23

Page 3: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 2

ナビゲーション コントローラ .................................................................................................................. 25

UIWebView を使った Web ブラウズ ..................................................................................................... 28

CoreLocation および MapKit による位置/方位のサポート ................................................................. 31

デバイスの回転 .......................................................................................................................................... 37

デバイス情報 .............................................................................................................................................. 39

近接センサと通知 ...................................................................................................................................... 43

電池状態とタイマ ...................................................................................................................................... 44

iPhone へのユーザー操作 ........................................................................................................................ 46

シェイク ..................................................................................................................................................... 47

タップ ......................................................................................................................................................... 48

ユーティリティ アプリケーション .......................................................................................................... 50

SOAP ベースの Web サービス ................................................................................................................ 52

同期か非同期か .......................................................................................................................................... 53

補助スレッドから UI へのアクセス ......................................................................................................... 54

Web サービスの利用 ................................................................................................................................ 54

画像 ............................................................................................................................................................. 59

ドラッグ可能なコントロール ................................................................................................................... 61

起動画面 ..................................................................................................................................................... 62

iPad のサポート......................................................................................................................................... 64

アイコン ..................................................................................................................................................... 64

デバッグ ..................................................................................................................................................... 67

技術リソース .................................................................................................................................................. 67

まとめ .............................................................................................................................................................. 68

著者について .................................................................................................................................................. 68

Page 4: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 3

はじめに

Delphi Prism XE は、エンバカデロ・テクノロジーズが提供する .NET およびクロ

スプラットフォーム Mono 向け開発環境の 新リリースです。スタンドアロン

製品としても、Embarcadero RAD Studio XE の一部としても利用できます。

Delphi Prism には、Windows® 上の Microsoft .NET プラットフォーム(および、

Silverlight® アプリケーションを作成する場合は Mac®)をターゲットとする

Object Pascal コンパイラ(RemObjects Oxygene コンパイラ)が含まれていま

す。Delphi Prism による .NET 構文要素のサポートでは、C# 言語の 新機能にす

べて対応しているほか、使い慣れた Delphi による Object Pascal の実装に対するさまざまな拡張機能を提

供しています。

Windows 上の .NET アプリケーションを作成する場合、Delphi Prism はインストール後、通常は Visual

Studio® 内で使用されます。Delphi Prism のインストール時に Visual Studio が既にインストールされてい

る場合、Delphi Prism はその Visual Studio と統合され、そうでない場合は、Visual Studio Shell がインス

トールされます。

Delphi Prism では、Microsoft の .NET をターゲットとするだけでなく、Novell の

Mono プラットフォーム(http://www.mono-project.com)向けのアプリケーショ

ンもコンパイルできます。つまり、.NET プログラミング スキルがあれば、アプリ

ケーションのコード ベースが Windows だけをターゲットとするのにとどまらず、

さまざまなハードウェア プラットフォーム上の Linux や Mac OS X をも対象にでき

るようになります。Mono では、これらのプラットフォームで利用できる UI や技

術をサポートするためのさまざまなツールキットやライブラリが付属およびサポー

トされています。

Mono プロジェクトの開発時には、上記のように Visual Studio 内で作業できる

ほ か に 、 Mono 専 用 の 開 発 環 境 で あ る MonoDevelop

(http://monodevelop.com)内で作業することもできます。これは無償のオー

プンソース ツール(もともと SharpDevelop というオープンソース エディタを

ベースにしたもの)ですが、直接ダウンロードしないほうがよいでしょう。そ

の特定のビルドに Delphi Prism が統合されているからです(後述の

「MonoDevelop のインストール」を参照)。

これまで、iPhone 向けの開発には、Mac 上で Apple 開発ツールを使用すること

が必要でした。つまり、Xcode® での Objective-C によるプログラミングと Interface Builder での UI 開発

を組み合わせて、iPhone シミュレータでテスト可能なネイティブ iOS1 アプリケーションを作成したあと、

iPhone に配置してさらにテストを行ってから、必要に応じて Apple の App StoreSM にアクセスするという

手順です。

1 ここで、OS X は Mac のオペレーティング システム、iOS は iPhone、iPod touch、iPad のオペレーティング システ

ムです。そのため、iOS デバイスというのは iPhone、iPad、iPod touch の総称です。このテクニカル ノートで

"iPhone" という用語を使用している場合は、通常、任意の iOS デバイスを意味します。

Page 5: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 4

Objective-C を新たに習得することなく .NET プログラミング スキルを引き続

き活かすもう一つの方法として、.NET 言語を Mono で使用し(Interface

Builder による UI 作成は依然として実施)、Novell の MonoTouch ツールキッ

トを使用してアプリケーションを作成するアプローチがあります。

MonoTouch はもともと 2009 年 9 月に発売されたもので、Mono アプリケーションから iPhone アプリケ

ーションを簡単に生成できるようにするためのものをいくつか提供しています。まず第一に、Apple の

Cocoa Touch® API(CocoaTouch は Apple の Cocoa® UI ライブラリをタッチ指向にしたもので、iPhone

で使用されています)へのマネージド バインディングを提供します。これは時に CocoaTouch.NET と呼

ばれることがあります。次に、iPhone(および iPad® や iPod touch®)をターゲットとする多数の C# アプ

リケーション テンプレートが用意されています。 後に、AOT コンパイラ2 が取り入れられています。こ

れは、(通常は JIT コンパイルされた)マネージド Mono コードをネイティブ ARM コードに変換し、決

して呼び出されないと断定できる Mono ライブラリ コードの大半を取り除き(Delphi コンパイラではス

マート リンクと呼ばれます)、実行形式ファイルとすべての従属ライブラリを結合して単一の実行形式フ

ァイルにするものです。

Apple では iOS デバイス上での動的コード生成、JIT コンパイル、共有ライブラリを禁じているため、こ

のような AOT(事前)コンパイルとネイティブ コード生成が必要になります。

メモ: アプリケーションは、Mono ランタイム環境とすべての付属コードを含んだマネージド Mono アプ

リケーションとして起動します。スマート リンカによって大量の冗長コードが取り除かれますが、それで

も MonoTouch アプリケーションは直接 Objective-C で書かれた同等のアプリケーションよりも著しく大

きいと言って差し支えないでしょう。

一時、Apple は、Apple 開発ツールで作成されていないアプリケーション(基本的に Objective-C 以外の

あらゆるもの)もすべて禁止していましたが、幸いにも、それは今ではすっかり過去のことで、

MonoTouch アプリケーションは App Store に喜んで受け入れられています。

MonoTouch そのものが C# アプリケーションをサポートしていますが、Delphi Prism には、iPhone、

iPhone touch、iPad で動作するさまざまな種類のアプリケーションの迅速な開発に役立つテンプレートが

付加されています。

メモ: Delphi Prism は Windows 上で Visual Studio 内または MonoDevelop 内で動作できますが、

MonoTouch(および Apple の Xcode スイートに含まれている Interface Builder ツール)を使用するには、

Mac 上で作業する必要があります。

2 AOT は "Ahead Of Time"(事前)の略で、JIT("Just In Time")と対比されるものです。

Page 6: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 5

準備

持っているマシンが Apple Mac だと仮定すると、Delphi Prism で iPhone アプリケーションの開発を始め

るには、いくつかのものをインストールする必要があります。

IOS SDK のインストール

iPhone SDK(iOS SDK とも呼ばれます)は無償ですが、まず自分自身をサイトに登録する必要があります。

登録に当たっては、開発対象となる市場とプラットフォームに関するいくつかの質問に答えたあと、後ほ

ど受け取る確認用の電子メールに記載されているリンクをクリックします。Web ブラウザに iOS Dev

Center が表示され、Apple ID 確認用の別の電子メールが送られてきます。

そ れ 以 降 は 、 さ ま ざ ま な 参 考 資 料 や ガ イ ド に ア ク セ ス す る た め に 、 Apple Dev Center

(http://developer.apple.com/iphone)に戻ることができますし、おそらくその必要があるでしょう。も

ちろん、あらゆるプログラミング ドキュメントやサンプル コードは Objective-C で書かれていますが、そ

れは必ずしも絶対的な障害にはなりません。

このページで、iOS SDK をダウンロードできます。ダウンロードするものは、Xcode 開発環境(Interface

Builder を含む)と iOS SDK(本稿執筆時点ではそれぞれバージョン 3.2.5 と 4.2)の 2 つの開発キットを 1

つにまとめた "Xcode and the iOS SDK" と記載されています。まとめられているためダウンロード サイズ

が 3.5 GB にもなり、Xcode が既にインストールされている場合には不必要に大きいファイルになります。

メモ: 開発ツールと SDK は無償ですが、アプリケーションをデバイスや App Store に配置するには、

Apple の iOS Developer Program ( http://developer.apple.com/programs/ios : 日 本 語 サ イ ト は

http://developer.apple.com/jp/programs/ios)に参加する必要があり、それには年間 99 ドル(日本語サイ

ト経由では 10,800 円)かかります。ただし、アプリケーションを iPhone シミュレータで実行するのに費

用はかかりません。

Page 7: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 6

MONO のインストール

Mono for OS X は http://mono-project.com/Downloads で入手できます(本稿執筆時点での 新の安定バ

ージョンは 2.8.1_3 です)。インストールは、Mac では当然ながら、非常に簡単です。

MONODEVELOP のインストール

MonoDevelop のホームページのアドレスは http://monodevelop.com ですが、Delphi Prism で開発するの

が目的であれば、このサイトは無視してください。Delphi Prism のダウンロードには、Delphi Prism が統

合された専用の MonoDevelop が含まれているからです。

DELPHI PRISM のインストール

Mac 用 Delphi Prism のインストーラは、https://downloads.embarcadero.com/free/delphi_prism (トライ

アル版 - 登録フォームに入力するかサインインすると登録コードが電子メールで送られてきます)か

http://cc.embarcadero.com/reg/delphi_prism (Delphi Prism XE の有効なライセンスを持っている場合)

のどちらかで、該当するリンクをたどってダウンロードすることができます。zip ファイルの中には、カ

スタマイズされた MonoDevelop アプリケーションが含まれているので、それをただ ~/Applications にコ

ピーします。ただし、起動はまだしないでください。

MONOTOUCH SDK のインストール

次は、http://monotouch.net/Store から MonoTouch SDK を取得します。MonoTouch は商品であり、デバ

イス上に配置するにはライセンスを購入する必要があります。ただし、トライアル版は iPhone シミュレ

ータ上で実行できます。プロフェッショナル版のシングル ユーザー ライセンスは現在 399 ドルで、それ

には、リリースされる 1 年分のアップデートがすべて含まれています。

Page 8: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 7

トライアル版をダウンロードしてインストールしますが、その際には自分の電子メール アドレスを登録す

る必要があります。

先に進む前に

では、そろそろ MonoDevelop を初めて起動することにしましょう。登録コード(トライアル版を請求し

たときに送られてきたものなど)と一緒にシリアル番号(トライアル版または完全版)を登録するため、

リンク3 をたどるように求められます。 登録してライセンス ファイルをダウンロードし、それを入力待ち

の MonoDevelop 2.4 ダイアログにインポートすると、MonoDevelop が起動します。

メモ: MonoDevelop は、起動時に、 新バージョンかどうかをデフォルトで確認します(この場合、

新バージョンではありません)。Delphi Prism アーカイブには MonoDevelop 2.4 が含まれていますが、

(本稿執筆時点での) 新バージョンは、バグ修正リリースであるバージョン 2.4.1 です。希望する場合

はアップデート(標準の .dmg ディスク イメージ)をダウンロードできますが、続けて古いバージョンに

上書きインストールしないことが重要です。そうしないと、Delphi Prism インテグレーションが失われる

ことになります。

上書きインストールするのではなく、まず MonoDevelop を終了し、その名前を MonoDevelop から

MonoDevelop2 に変更します。これで、アップデートをホームディレクトリの Applications サブディレク

トリにインストールできます。

Delphi Prism インテグレーションのファイルを元の MonoDevelop から更新版にコピーするには、ターミ

ナル ウィンドウで以下のようにいくつかのコマンドを実行します。

cd ~/Applications

cp -R MonoDevelop2.app/Contents/MacOS/lib/monodevelop/AddIns/Oxygene

MonoDevelop.app/Contents/MacOS/lib/monodevelop/AddIns

これで MonoDevelop が Prism 対応になり、MonoDevelop2 を削除(または無視)できます。

次に、 新のテンプレートをすべて揃えるため、MonoDevelop に RemObjects MonoDevelop リポジトリ

か ら ア ッ プ デ ー ト を 取 得 さ せ る 方 法 に つ い て の 説 明 ( http://www.remobjects.com/oxygene/

prismextras.aspx)に従ってください。

Windows プログラミングの経験が長い方は、MonoDevelop テキスト エディタのキー バインディングの一

部については、慣れるのに苦労するかもしれません。その場合は、MonoDevelop の設定ダイアログを使

用して、該当するエディタ コマンドを、自分にとってもっと自然なキー入力にマッピングし直したほうが

よいでしょう。

また、オープン ソースの MonoDevelop 開発環境では、使用し始めて数時間経つと、[ソリューション] ウ

ィンドウが反応しなくなったり、エディタが例外を送出して、コード補完などが働かなくなることがとき

どきあります。その場合には、ただ MonoDevelop を終了し再起動します。

これでやっと準備ができたので、さあ始めましょう。

3 Delphi Prism の次のリリースでは、この時点で Web ページが表示されるのではなく、MonoDevelop 内でダイアログ

が開きます。

Page 9: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 8

MONOTOUCH でのアプリケーションの開発

初めて iPhone アプリケーションの開発に乗り出すにあたり、慣例に従って、Hello World プログラムから

始めましょう。MonoDevelop で、メイン メニューから [ファイル|新規|ソリューション...] を選択する

(または ⇧⌘+N キーを押す)か、[ようこそ] 画面の [新しいソリューションを開始] リンクをクリックしま

す。[新しいソリューション] ウィンドウが開いて、使用可能なさまざまな Delphi Prism テンプレートが表

示されます。Hello World には画面が 1 つだけあるので、まずはウィンドウ ベースのプロジェクトから始

めます。

これで、さまざまなファイルから成る単一のプロジェクトが含まれたソリューション4 が作成されます。

4 Visual Studio の場合と同様に、ソリューションは、複数のプロジェクトも管理できる手段であり、Delphi プロジェク

ト グループに似ています。

Page 10: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 9

Info.plist は、iOS にとって重要なさまざまなプロパティを設定するのに使用されるプロパティ リスト ファ

イルです。とりあえず、これは無視します。

重要なファイルは Main.pas で、ここにコードを書きます。簡単な Application クラスには、アプリケーシ

ョンのエントリ ポイントとなるクラス メソッド Main が含まれています。AppDelegate の方がもう少し

興味深いでしょう。これは、基礎となる CocoaTouch Application オブジェクトのデリゲートを表し、ア

プリケーションの読み込みが完了したときにトリガされる FinishedLaunching イベント(そのイベント ハ

ンドラには通常、初期化コードが含まれている)などの Application のイベントに応答できます。

CocoaTouch は MVC モデルで動作し、このデリゲート モデルは、たとえば UI コントロールのイベント

ハンドラなどでよく現れます。

UI コントロールと言えば、UI をセットアップする必要があります。MainWindow.xib5 ファイルが UI を表

します。ダブルクリックすると、このファイルが Interface Builder ツールで開きます。MonoTouch プロジ

ェクトを扱う際には、このツールに多少とも時間を割くことになります。

Interface Builder に目を向ける前に、プロジェクト内のもう一方のソース ファイルも見ておきましょう。

MainWindow.xib.designer.pas は、UI の部品にアクセスするのに必要なコードが記述されている自動生成

ファイルで、.xib の分離コード ファイルと呼ばれます。このファイルについては、このあと、もう一度注

目します。

INTERFACE BUILDER と UI

Interface Builder は、Apple の Xcode 開発ツール スイートに含まれているツールの 1 つで、iOS アプリケ

ーションの UI 設計部分を作成する場となります。どのソリューション/プロジェクト テンプレートで始め

るかで、設計しようとするウィンドウのサイズが決まります。解像度がそれぞれ異なるからです。iPhone

と iPod touch は 320x4806 であるのに対して、iPad は 1024x768 です。

.xib ファイルを Interface Builder で開くと、以下のスクリーンショットに示すような 4 つのウィンドウが

表示されます。これらのそれぞれに慣れる必要があるので、これらを 1 つずつ見ていきましょう。

1 つ目はドキュメント ウィンドウです。このウィンドウでは、.xib ファイルに記述されている主要な項目

が一覧表示され、それらを選択することができます。この中で、今のところ注意すべき重要な項目は、

App Delegate と Window です。前者は、前述のソース ファイルに含まれている AppDelegate クラスに対

応するもので、後者は(ウィンドウ ベースの新規プロジェクトに必ず 1 つある)アプリケーション ウィ

ンドウを表します。

2 つ目はアプリケーションのウィンドウで、ドキュメント ウィンドウ内の [Window] 項目をダブルクリッ

クするとアクティブになります。このウィンドウは、ターゲットとなる iOS デバイスに適したサイズ(こ

の例では 320x480)になります。スクリーンショットをよく見ると、ウィンドウの上部に iPhone のステー

5 もともと、Apple の UI ファイルはバイナリで、.nib 拡張子が使用されていました。iOS アプリケーションを作成する

場合、UI ファイルは XML で記述され、.xib 拡張子が使用されます。OS X や iOS で作業する開発者にとっては、.xib

ファイルも .nib ファイルも単に NIB ファイルと呼ぶのが普通です。 6 iPhone 4 の画面は iPhone 3 よりも解像度が高くなっています(640x960)。これはピクセル解像度が増えたからです

が、ポイント単位で見ると、すべての iPhone は 320x480 の解像度になります。つまり、UI は 1 回だけ設計すれば、

すべての iPhone で使えるということです。

Page 11: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 10

タス バーが表されていることがわかります。このウィンドウは基本的にフォーム デザイナで、コントロ

ールやビューを追加して作り上げていく UI の現在の状態を表します。

3 つ目はインスペクタ ウィンドウで、[オブジェクト インスペクタ] や [プロパティ] ウィンドウと同じ目的

を果たします。このウィンドウにはページが 4 つあり、それぞれは上部のボタンかメニュー項目で選択で

きます。[Tools] メニューを確認すれば、⇧⌘+I キーを押すとインスペクタ ウィンドウが選択されることが

わかります。このとき、現在アクティブになっているタブが開かれます。ただし、⌘+1、⌘+2、⌘+3、⌘+4

の各キーを押すと、属性インスペクタ(Attributes Inspector)、接続インスペクタ(Connections

Inspector)、サイズ インスペクタ(Size Inspector)、アイデンティティ インスペクタ( Identity

Inspector)がそれぞれ選択されます。4 つのボタンをそれぞれクリックした場合も同じ動作になります。

属性インスペクタではさまざまなプロパティを調整でき、サイズ インスペクタでは選択したコントロール

のサイズとアンカー設定(Delphi 的に言えば)を操作できます。接続インスペクタでは、後述のように、

アウトレットとアクションの接続を行います。

4 つ目はライブラリ ウィンドウ([Library])です。ここでもやはり、上部のボタンでモードが切り替わり

ます。[Objects] ボタンを選択すると、ウィンドウに追加できるオブジェクトがすべて表示され(Delphi の

[ツール パレット] に似ています)、[Classes] ボタンを選択すると、使用可能なクラスがすべて一覧表示さ

れます([Media] ボタンは今回の目的には重要ではありません)。いずれのモードでも、デフォルトで表

示される長いリストをフィルタリングする検索ボックスがウィンドウの下部にあります。

今回初めて取り組むアプリケーションの UI には、2 つの Label コントロール(UILabel)、Round Rect

Button コントロール(UIButton)、Text Field コントロール(UITextField)が必要になります。[Library]

ウィンドウでこれらの入力コントロールを見つけるには、[Objects] ボタンが選択されていることを確認し

たうえで、ドロップダウン コントロールを使用して [Inputs & Values] だけを表示します(デフォルトでは

これに対して、CocoaTouch のライブラリ全体とカスタム オブジェクトが表示されています)。これでリ

ストが大幅に短くなるので、コントロールをすぐに見つけられるはずです。リスト内で、これらはすべて

Page 12: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 11

近くに並んでいます。また、検索ボックスを使用して、クラス名や説明を検索することもできます(ただ

し、その場合はドロップダウン フィルタがリセットされて、ライブラリ全体がもう一度表示されます)。

コントロールをフォームにドラッグし、下図のように配置します。これらのすべてのコントロールについ

ては、コントロールをダブルクリックするか、属性インスペクタ(⌘+1 キーで起動)で [Text] 属性または

[Title] 属性を適宜使って、テキストを編集できます。暗い背景のほうがよければ、ラベルのテキスト色と

ウィンドウ自体の背景色を設定することもできます。また、ウィンドウ属性を使用すれば、iPhone のステ

ータス バーの色も設定できます7。

テキスト フィールドをタップするとキーボードが自動的にポップアップしますが8、この仮想キーボード

には、属性インスペクタの [Text Input Traits] セクションで設定できるさまざまな属性があります。今回は、

単語の先頭文字が大文字になるように設定([Capitalize] 属性を [Words] に設定)するほか、[Return Key]

属性を [Done] に設定します(これにより、キーボード上の通常の [Return] ボタンが、強調表示された

[Done] ボタンに変わります)。

これで UI の設計が終わりましたが、Interface Builder を終了する前に、次のステップであるプログラミン

グの準備をしておく必要があります。

アウトレット

コードでは、テキスト フィールドからの読み取りと下部のラベルへの書き込みが必要になります(さらに、

可能であることを単に示すために、ボタンにも書き込みます)。これらのコントロールにアクセスするに

7 その設定は、Interface Builder ではシミュレート インターフェイス要素(Simulated Interface Element)と記述されて

いるため、どのような外見になるかを示すだけで、実行時には効果がありません。アプリケーションを完成させるには、

コードでの作業が必要です(後で行います)。 8後で説明するように、キーボードは自動的にポップアップしますが、それを閉じるのはプログラマの責任です。

Page 13: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 12

は、それらを参照する変数を定義する必要がありますが、それはデフォルトでは作成されません。これら

の変数はアウトレットと呼ばれ、[Library] ウィンドウの [Classes] ページで定義されます。

前述のとおり、このアプリケーションでは AppDelegate がコードの追加先になるので、アウトレットは

このクラスに追加する必要があります。[Library] ウィンドウの [Classes] ページで AppDelegate を見つけ

るには、ドロップダウン ボックスを使用し(使用可能なすべてのクラスが一覧表示されます)見つかるま

でスクロールするか、ウィンドウのメイン リストを上下にスクロールするか、あるいは検索ボックスを使

用します。

このクラスを選択すると、あまり有用でない継承図がウィンドウの下半分に表示されます。ウィンドウの

中央にあるドロップダウン ボックスを使って [Outlets] ビューに切り替えると、ウィンドウ オブジェクト

に既に定義されているアウトレットが 1 つ表示されます。ここで、[+] ボタンを使用して、関係するコント

ロールごとにアウトレットを 1 つ追加します。

これで変数は定義されますが、それぞれが何を表しているかをまだ Interface Builder に明示していないの

で、これらのアウトレットをコントロールに接続する必要があります。それには、アウトレットを定義す

るオブジェクトを選択(ドキュメント ウィンドウで [App Delegate] を選択)したうえで、接続インスペ

クタを使用します(⌘+2 キーを押します)。すべてのアウトレットが接続インスペクタに一覧表示され、

window アウトレットは、新たに追加したアウトレットとは異なり、接続済みであることがわかります。

アウトレットをコントロールに接続するには、そのアウトレットの右端にある小さい丸印の上にマウスを

移動し(丸印がプラス記号に変わります)、そこからドラッグしてコントロールの上にドロップします。

下図では、myLabel アウトレットが接続されるのがわかります。

Page 14: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 13

3 つのアウトレットをセットアップしたら、イベントで何が起こるかを検討できます。

COCOATOUCH のアクションとイベント

Interface Builder で使用可能な CocoaTouch コントロールには、皆さんのご期待どおり、応答可能なさま

ざまなイベントが用意されています。ただし、MonoTouch を使用する際には、イベント ハンドラの 2 つ

のセットアップ方法からどちらかを選択することになります。第 1 の方法では、Interface Builder でアウ

トレットをセットアップする必要があり、その後は、通常の .NET 形式のイベントをソース コードで使用

します。第 2 の方法は従来の Cocoa プログラミング モデルに合致しており、アクションを中心に作業が

展開します。ここでは第 2 のアプローチを説明します。

アクションは、クラス内で実装されて、Interface Builder でコントロールのイベントに接続されるメソッ

ドを表します。Interface Builder でアクションをセットアップするには、アウトレットを定義する場合と

似た方法を用います。つまり、[Library] ウィンドウで、選択したクラスの [Actions] ページを選択します。

AppDelegate にアクションを追加する必要があります。

メモ: これらのアクションは、基礎となる CocoaTouch ライブラリ内から送られてくる(コード内のイベ

ント ハンドラ メソッドがそれにマッピングされます)ので、Objective-C でプログラミングする場合と同

じルールに従います。これらのイベントはすべてパラメータを持つことが多いので、アクションの末尾に

は必ずコロンを付ける必要があります。そのため今回は、myButtonPressed: というようなアクションを追

加すると、うまくいきます。コロンを付け忘れてもエラーは発生しませんが、コードは思ったとおりには

動きません。

Page 15: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 14

アクションをイベントに接続するには、2 とおりの方法が

あります。第 1 の方法では、アクションを App Delegate

の接続インスペクタで見つけたあと([Received Actions]

リスト内にあります)、関係のあるコントロール(ボタ

ン)までドラッグします。その結果、すべてのイベントを

一覧表示するポップアップ リストが生成されますが(左

側のスクリーンショットを参照)、その中で、必要と思わ

れるものは Touch Up Inside イベントです。これは、ユー

ザーがボタンに触れたあと指を離したときにトリガされる

ものです。

アクションを接続する第 2 の方法は、まずボタンを選択し

たあと(その結果、使用可能なイベントがすべて接続イン

スペクタに一覧表示されます)、必要なイベントをドキュ

メント ウィンドウの App Delegate までドラッグします。

これにより、使用可能なアクションのポップアップ リス

トが表示されます(今回の例では、リスト内の項目は 1 つ

だけです)。

どちらの方法でも、接続を作成し .xib ファイルを保存すれ

ば(⌘+S キーを押す)、MonoDevelop に戻って、次のス

テップであるコード作成を進めることができます。

COCOATOUCH アクションのイベント ハンドラ

MonoDevelop に戻ると分離コード ファイルが再生成されるので、次はそれに目を向けましょう(以下に

掲載するリストでは、わかりやすくするために重要でない一部の行を割愛しています)。分離コード ファ

イル内のこの部分に記述されているのは、AppDelegate クラスの部分クラス宣言です(これは Main.pas

でも部分的に宣言されています)。ここでは、MonoTouch 属性を使用して、この Mono クラスが

CocoaTouch レベルで Objective-C の AppDelegate クラスに必ずバインドされるようにしています。

そこにはイベント ハンドラ メソッド myButtonPressed の宣言があり、それを Objective-C で記述された

アクションにバインドするための別の属性が付いているのがわかります。実装なしに宣言だけをここに記

述できるようにする partial および empty キーワードに注意してください。このメソッドは、Main.pas で

実装します。クラスの残りの部分は、アウトレットを表すプロパティ(実際のコードでの設定アクセサ、

取得アクセサ、private 変数を伴う)とさらに多くのバインド属性で構成されます。

[MonoTouch.Foundation.Register('AppDelegate')]

AppDelegate = public partial class

Private

[MonoTouch.Foundation.Export('myButtonPressed:')]

method myButtonPressed(sender: MonoTouch.UIKit.UIButton); partial; empty;

[MonoTouch.Foundation.Connect('window')]

property window: MonoTouch.UIKit.UIWindow

read get_window write set_window;

[MonoTouch.Foundation.Connect('myButton')]

Page 16: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 15

property myButton: MonoTouch.UIKit.UIButton

read get_myButton write set_myButton;

[MonoTouch.Foundation.Connect('myLabel')]

property myLabel: MonoTouch.UIKit.UILabel

read get_myLabel write set_myLabel;

[MonoTouch.Foundation.Connect('myTextBox')]

property myTextBox: MonoTouch.UIKit.UITextField

read get_myTextBox write set_myTextBox;

end;

Main.pas に切り替えて、この部分クラスに含まれているイベント ハンドラの宣言と実装を以下のように

追加する必要があります。

type

AppDelegate = public class

...

private

method myButtonPressed(sender: MonoTouch.UIKit.UIButton); partial;

end;

method AppDelegate.myButtonPressed(sender: MonoTouch.UIKit.UIButton);

begin

myLabel.Text := 'Hello world! Erm, I mean Hello ' + myTextBox.Text + '!';

end;

正直なところ、このコードは通常の Delphi コードのように見えます。[ビルド]

メニューのオプションを使ってプロジェクトのビルドを確認できます(また、

⌘+K ではソリューション内のアクティブなプロジェクトがビルドされ、⌘+B

ではソリューション内のすべてのプロジェクトがビルドされます)。

IPHONE シミュレータ

では、そろそろアプリケーションをテストしましょう。アプリケーションは、

MonoDevelop か ら [ 実 行 ] メ ニ ュ ー ま た は ⌥⌘↩ キ ー ( つ ま り 、

option+command+enter キーあるいは Mac キーボードを使い始めたばかりの

ユーザーにとっては alt+Apple+enter キー)を使って実行でき、iPhone シミ

ュレータで起動されます。指ではなくマウスを使って、アプリケーションとや

り取りできます。マルチタッチを実装してある場合は、option(alt)キーを押

しながら操作することで、2 本指タッチをまねることができます。

メモ: iPhone シミュレータは、エミュレータではなくシミュレータです。そのため、ARM コードではな

く通常の Intel コードを実行することになりますが、そのことやその他のさまざまな理由により、アプリケ

ーションのパフォーマンスと動作は、実際のデバイスに配置した場合と非常に異なる可能性があります。

Page 17: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 16

テキスト フィールドをタップすると、キーボードがすぐにポップアップします。その中のボタンが強調表

示されており、名前を入力したら [Done] を押すようにユーザーに促します。残念ながら、今は押してもま

だ何も起こりません。何かが起こるようにするのは私たちの責任です。一方、[Touch me] ボタンはうまく

動きます。

起動時にあいさつのラベルを消して空にする何らかの初期化コードを追加しなければなりません(あるい

は、Interface Builder でラベルをクリアします)。また、ボタンのキャプションも変更し(末尾に 1 文字

追加するだけです)、このキーボードに対処します。このコードはすべて、オーバーライドされた

FinishedLaunching メソッドに記述します。画面の表示を命じるところで window.MakeKeyAndVisible() が

呼び出されるので、スタートアップ コードはその直前に記述します。ラベルをクリアするのは些細なこと

ですが、ボタン キャプション(あるいはタイトル)の方は少し判然としません。結局、現在の "標準状態

" のタイトルを取得して、更新した "標準状態" のタイトルを別途設定する必要があることがわかります。

myLabel.Text := '';

myButton.SetTitle(myButton.Title(UIControlState.Normal) + '!',

UIControlState.Normal);

時には、コード補完ウィンドウに目を通して、どのメソッドやプロパティが使用できるかを確かめる必要

が あ り ま す 。 MonoTouch ド キ ュ メ ン ト ( 作 成 中 で す が か な り 良 い も の が

http://monotouch.net/Documentation で利用可能)を徹底的に調べなければならないことも時にはありま

す。あるいは、Apple の Web サイト(http://developer.apple.com/library/ios)で公開されている

CocoaTouch のおおもとのドキュメントに立ち戻ることも時には必要でしょう。構文が少しおかしいよう

に見えることもときどきありますが、それでもこれらは、メソッドやプロパティなどに関するすべてです

ので、リファレンスとして、必要なときには計り知れないほど貴重なものです。

先に進む前に、ひと言補足しておきます。Interface Builder で iPhone ステータス バーを不透明な黒に設定

しても、シミュレータでは、上記のスクリーンショットとは異なり、(なぜか)その設定が無視されるこ

とに気がつくでしょう。この問題は、その設定を代わりにコードで行うことで克服できます。同じ

FinishedLaunching メソッドで、以下のコードを冒頭付近に追加します。

UIApplication.SharedApplication.StatusBarStyle := UIStatusBarStyle.BlackOpaque;

メモ: UIApplication.SharedApplication を使用すれば、基礎となる Application オブジェクトにコードの

どこからでもアクセスできます。

テキスト入力キーボード

既に述べたように、キーボードを閉じる必要があるとわかった時点で、そうするようにテキスト フィール

ドに命じる必要があります。しかし、その対処方法をどうやって見つければよいのでしょうか。そうです

ね、手始めにインターネットで検索するというのも悪くないでしょう。何と言っても、MonoTouch プロ

グラマがよくつまずく問題についての膨大な量の情報があるからです(もちろん、CocoaTouch プログラ

マにとってはなおさらです)。しかし、ここでは、ドキュメントを調べて解決策の見つけ方を探りましょ

う。そのために、まず Apple のリファレンス サイトから始めます。

Page 18: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 17

ドキュメントの利用

http://developer.apple.com/library/ios では、すべての iOS フレームワークが一覧表示されています

(CocoaTouch はそのうちのいくつかを包括する用語です)。今注目しているクラスは UITextField です

が、名前の先頭の数文字から、これは UIKit フレームワークの構成要素であることがわかります。そこで、

[UIKit] リンクをクリックすると、『UITextField Class Reference』を含め、選択可能なリファレンス トピ

ックの全リストが表示されます。そのドキュメントをクリックすると、長く詳細なリファレンス ページが

表示されますが、その [Overview] セクションには、次のように書かれています。

"A text field object supports the use of a delegate object to handle editing-related notifications. You can

use this delegate to customize the editing behavior of the control and provide guidance for when certain

actions should occur. For more information on the methods supported by the delegate, see the

UITextFieldDelegate protocol."

(テキスト フィールド オブジェクトでは、デリゲート オブジェクトを使用して編集関係の通知を処理

できます。このデリゲートを使用すると、コントロールの編集動作をカスタマイズしたり、特定のアク

ションをいつ実行すべきかについてのガイドを提供することができます。デリゲートでサポートされて

いるメソッドの詳細については、UITextFieldDelegate プロトコルを参照してください。)

カスタマイズしようとしている編集関係の事項を探しているので、この文中のリンクをたどる必要があり

ます。通常、MonoTouch レイヤでは、この種のオプションのデリゲート オブジェクト機能は問題のメイ

ン オブジェクトに結合されるので、UITextFieldDelegate のメソッドは、MonoTouch の UITextField オブ

ジェクトにデリゲート プロパティとして実装され、デリゲート クラスを作成してテキスト フィールド オ

ブジェクトをカスタマイズする手間が省けます。ただし、デリゲートを別個のオブジェクトとして作成す

る場合は、デリゲート クラスは選択肢として残されます。

UITextFieldDelegate のページでは、デリゲートでサポートされているメソッド(あるいは、Objective-C

で言えばメッセージ)について説明しています。記載されている情報に目を通すと、メッセージ

textFieldShouldReturn: がその 1 つであることがわかります。

それでは、これの MonoTouch 版を見てみましょう。http://www.go-mono.com/docs で、まず、

[MonoTouch Framework|MonoTouch.UIKit|UITextFieldDelegate Class|Methods] のノード パスをたど

ってリファレンス ツリーを展開します。一覧表示されるメソッドのうち、今回必要なのは ShouldReturn

です。おわかりのように、MonoTouch でも一部のメンバ名は簡略化されています。このメソッドを選択

すると、ページの内容から、メソッド シグネチャは UITextField を引数に取り Boolean を返す関数である

ことがわかります。この戻り値は、[Return](または [Done])が押されたときにキーボードがデフォルト

の動作をするかどうかを示します。

これは同じデリゲート オブジェクト プロパティについての Apple と MonoTouch のドキュメントですが、

前述のとおり、MonoTouch では、デリゲート オブジェクトはテキスト フィールドに取り込まれています。

UITextField Class のヘルプを調べると、メソッドを参照できる ShouldReturn プロパティが見つかりますが、

これこそ今回使用するものです。

ヘルプによれば、このプロパティには(正しいシグネチャで)通常のメソッドを割り当てることができま

すが、無名メソッドを使用できるとも書かれています。無名メソッドは、入力の手間が少し省けるので便

利です。機能が多すぎず他で必要ないなら、無名メソッドを使用するのも理にかなっています。また、ラ

Page 19: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 18

ムダを使ってもう少し入力を減らせる可能性もありますが、ラムダとは何なのかと心配する前に、まず、

キーボードを消すには ShouldReturn にどのような機能が必要かを考えてみましょう。

ファースト レスポンダ

Windows で入力を受け取るフォーカス コントロールに も近いものは、iOS ではファースト レスポンダ

(first responder)です。テキスト フィールドをタップすると、それがファースト レスポンダになり、そ

こにキーボードが表示されます。キーボードを消すのは、このファースト レスポンダ状態を解除すること

にすぎません。

myTextBox.ShouldReturn := method(textField: UITextField): Boolean

begin Result := textField.ResignFirstResponder end;

ResignFirstResponder は、そのファースト レスポンダ状態が失われた場合に true を返すので、無名メソ

ッドからはこの値が返されます。つまり、[Return] が押されたときに、その処理をテキスト フィールドで

行わなければなりません。上記の無名メソッドは通常のメソッド実装のような外見になるように記述しま

したが、そうする必要性もメリットも実際にはありません。無名メソッドは、少し簡約して以下のような

ラムダにすることもできます。

myTextBox.ShouldReturn := (textField) ->

begin Result := textField.ResignFirstResponder end;

ラムダの本体にはステートメントが記述されるので、begin/end のペアが必要です。ただし、本体がター

ゲット関数の戻り値型と同じ型の式である場合は、さらに次のように簡略化できます。

myTextBox.ShouldReturn := (textField) -> textField.ResignFirstResponder;

これら 3 つの記述形式はすべてまったく同じ意味ですが、ラムダではパラメータ型についての明示的な情

報が省かれていることに気がつきます。コンパイラでは、左辺のデリゲート プロパティの型を通じてこれ

を解決できます。

MONOTOUCH イベントのイベント ハンドラ

シミュレータでアプリケーションを再起動して動作を確認する前に、イベント ハンドラをもう 1 つ追加し

ましょう。先に述べたように、UI コントロールのイベント ハンドラのセットアップ方法は 2 とおりあり、

そのうち、アクションを使用するアプローチを調べました。ここでは、同じ [Touch me] ボタンにイベント

ハンドラをもう 1 つ追加しますが、今度は、テキスト フィールド オブジェクトのイベントを使ってコー

ドにだけ追加します。

method AppDelegate.InfoAlert(Msg: String);

begin

using av := new UIAlertView('Info', Msg, nil, 'OK', nil) do

av.Show

end;

Page 20: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 19

...

myButton.TouchUpInside +=

method begin InfoAlert('Hello ' + myTextBox.Text) end;

上記のように、+= 演算子とメソッド(無名メソッドまたはそれ以外のメソッド)を使って、イベント ハ

ンドラ(.NET および Mono ではもちろんマルチキャスト イベント ハンドラです)を追加できます。この

イベント ハンドラでは、UIAlertView オブジェクトを通じて警告(メッセージ ボックスに も近い同等機

能)をポップアップします。

メモ: using 文を使用すると、C# の場合と同様に、Objective-C リソースを使い終えたことがわかったと

きに必ず Dispose が呼び出されてリソースが解放されることを簡潔に記述できます。上記のメソッドは、

少し長い下記バージョンとまったく同じです。

method AppDelegate.InfoAlert(Msg: String);

begin

with av := new UIAlertView('Info', Msg, nil, 'OK', nil) do

try

av.Show

finally

av.Dispose

end

end;

メモ: Objective-C では一般に、通常の Delphi Win32 プログラミングと同様に、明示的なメモリ管理が必

要です。ただし、Mono および .NET にはガベージ コレクタ(GC)があるので、メモリの後片づけをして

くれます。ユーザーは気軽にオブジェクトを作成し、その回収を、いつ行うかも含めてすべて GC に任せ

ることができますが、デバイス上の限られたメモリをユーザーが責任を持って使用する必要がある場合は、

もう必要なくなったあらゆるオブジェクトに対して Dispose メソッドを呼び出すことができます。その結

果、背後にある Objective-C オブジェクトが解放されます。

アプリケーションをテストすれば、前よりも思ったとおりに動作します。仮想キーボードの [Done] ボタン

は作動し、2 つの処理(ラベルの更新と警告のポップアップ)を行うようになります。おもしろいことに、

このボタンを押してもキーボードは消えません。テキスト ボックスがファースト レスポンダのままだか

らです。それを解決するには、ボタンのイベント ハンドラの 1 つに次のような条件を追加します。

if myTextBox.IsFirstResponder then

myTextBox.ResignFirstResponder;

ビュー コントローラ

上記のような簡単なアプリケーションでは、すべての機能が App Delegate に集約されており、純粋主義

者であれば、これは CocoaTouch Application オブジェクトのデリゲートとして機能させておくのが も

よいのではないかと言うかもしれません。標準的なアプリケーションでは、アプリケーションに含まれる

さまざまなウィンドウ上のビューのデリゲートとして 1 つ以上のビュー コントローラ(UIViewController

Page 21: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 20

またはその下位クラス)を使用する傾向が強くなります。MonoDevelop で [iPhone Navigation-based

Project] テンプレートまたは [iPhone Utility Project] テンプレートを使って作業を開始した場合は、アプリ

ケーションにビュー コントローラができます。ここでは、前者のテンプレートを使ってナビゲーションベ

ース プロジェクトを新規作成しましょう。

このテンプレートからできるプロジェクトには、前回と同様に、ウィンドウと App Delegate があります

が、重要なことに、さらにナビゲーション コントローラもあり、それはナビゲーション バーと連動して

います。これは、アプリケーションで画面間を移動でき以前の任意の画面に容易に戻ることができるよう

にするための共通ワークフローをサポートするという考え方です。iPhone では、ナビゲーション コント

ローラ(Navigation Controller)の制御下にあるナビゲーション バー(Navigation Bar)を使って、これを

たやすく実現できます。ナビゲーション バーは、ユーザーがどの画面にいるかを表します(移動可能な各

画面は実際には UIView の下位クラス オブジェクトです)。

メモ: MainWindow.xib をダブルクリックすると、Interface Builder で 2 つの UI ウィンドウが開かれる可

能性があります。この .xib ファイルには、メイン ウィンドウ(まったく空です)とナビゲーション コン

トローラ(その上にナビゲーション バーなどがあります)の両方が定義されているからです。ドキュメン

ト ウィンドウを使用すれば、そのどちらでも選んですぐに開くことができます。

対応する UITableViewController を備えた開始ビューとして UITableView がテンプレートによりセットア

ップされますが、これは、カスタマイズ性の高いリストを iPhone ユーザーに非常になじみのある形で表

示するのに適しています。テーブル(またはリスト)から項目が選択されるのに合わせて、アプリケーシ

ョンは必要に応じて他のページに移動できます。

Interface Builder で 2 つの .xib ファイルを開くと、メイン ウィンドウの上部に青いナビゲーション バーが

あるほか(ダブルクリックすることで何らかのテキストを入力できます)、ウィンドウの残りのコンテン

ツが RootViewController.xib から読み込まれることが示されます。この後者の .xib ファイルにはテーブル

ビュー(Table View コントロール)だけが記述されており、サンプル データが設定された状態で表示され

ます。

Page 22: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 21

この UITableView がどのように動作するかを調べるために、SQLite データベースから得られる何らかの情

報を表示してみましょう。コーディングは、テーブル ビューの .xib ファイルに関連付けられているソース

フ ァ イ ル で あ る RootViewController.xib.pas で 行 い ま す ( 分 離 コ ー ド フ ァ イ ル で あ る

RootViewController.xib.designer.pas と混同しないようにしましょう)。

SQLITE の利用

テーブルのことを心配する前に、メインのテーブル ビューが読み込まれたときにデータベース、テーブル、

何らかのサンプル データを作成するコードを用意します。また、後片づけをきちんとするため、データベ

ースがアンロードされたらそれを削除します。ただし、実際のアプリケーションでは、呼び出しから次の

呼び出しまでの間もデータベースを使用可能な状態にしておかなければならない場合があるのは明らかで

す。データベース テーブルの内容はデータベースから読み取られ、厳密に型指定されたリストに格納され

ます。繰り返しますが、現実のアプリケーションではメモリ要件を考慮に入れなければなりません。この

サンプルでは、ほんの一握りのレコードしかありません。

リストが厳密に型指定されているので、以下のように、読み取るデータを表す型が必要になります。

Customer = public class

public

constructor;

property CustID: Integer;

property FirstName: String;

property LastName: String;

property Town: String;

end;

ViewDidLoad と ViewDidUnload のオーバーライドされたメソッドはテンプレート プロジェクトに既に存

在しているので、以下では、Mono SQLite データベース タイプを対象に標準の ADO.NET 手法を使用する

追加コードのみ示します。

uses

...

System.Collections.Generic,

System.Data,

System.IO,

Mono.Data.Sqlite;

...

connection: SqliteConnection;

dbPath: String;

customerList: List<Customer>;

...

method RootViewController.ViewDidLoad;

const

TblColDefs = ' Customers (CustID INTEGER NOT NULL, FirstName ntext,

LastName ntext, Town ntext)';

Page 23: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 22

TblCols = ' Customers (CustID, FirstName, LastName, Town) ';

begin

inherited ViewDidLoad();

//Create the DB and insert some rows

var documents := Environment.GetFolderPath(

Environment.SpecialFolder.Personal);

dbPath := Path.Combine(documents, 'NavTestDB.db3');

var dbExists := File.Exists(dbPath);

if not dbExists then SqliteConnection.CreateFile(dbPath);

connection := new SqliteConnection('Data Source=' + dbPath);

try

connection.Open;

using cmd := connection.CreateCommand() do

begin

cmd.CommandType := CommandType.Text;

if not dbExists then

begin

var statements: array of String := [

"CREATE TABLE" + TblColDefs,

"INSERT INTO" + TblCols +

"VALUES (1, 'John', 'Smith', 'Manchester')",

...

];

for statement in statements do

begin

cmd.CommandText := statement;

cmd.ExecuteNonQuery;

end;

end;

customerList := new List<Customer>;

cmd.CommandText := 'SELECT CustID, FirstName, LastName, Town ' +

'FROM Customers ORDER BY LastName';

using reader := cmd.ExecuteReader do

begin

//read customers from DB into customerList

while reader.Read do

begin

var cust := new Customer;

cust.CustID := Convert.ToInt32(reader['CustID']);

cust.FirstName := String(reader['FirstName']);

cust.LastName := String(reader['LastName']);

cust.Town := String(reader['Town']);

customerList.Add(cust);

Page 24: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 23

end

end

end

finally

connection.Close

end;

self.TableView.Source := new CustomerDataSource(self)

end;

method RootViewController.ViewDidUnload;

begin

//Delete the sample DB. Pointlessly kill table in the DB first.

using cmd := connection.CreateCommand() do

begin

cmd.CommandText := "DROP TABLE IF EXISTS Customers";

cmd.CommandType := CommandType.Text;

connection.Open;

cmd.ExecuteNonQuery;

connection.Close;

end;

File.Delete(dbPath);

inherited ViewDidUnload()

end;

テーブル ビューのデータ ソース

上記のコードで、テーブル ビュー(Table View コントロール)そのものは完了です。残りの作業は、テー

ブル ビューの CustomerDataSource クラス(UITableViewSource の下位クラス)で行います。

ViewDidLoad のテンプレート コードの終わりを見ると、CustomerDataSource オブジェクトがセットアッ

プされています。このデータ ソース クラスは、テンプレートでは、テーブル ビュー内に定義されたネス

トしたクラスとしてセットアップされ、そのいくつかの仮想メソッドが既にオーバーライドされています。

テーブルは複数のセクションに分割でき、それぞれには(オプションで)独自のヘッダーが付きます。今

回の顧客リストでは追加セクションは必要ないので、NumberOfSections は 1 を返します。この単一セク

ションに表示する行数をテーブル ビューに指示するため、RowsInSection は controller.customerList.Count

を返します(controller はコンストラクタで設定され、ビュー コントローラにアクセスできるようになり

ます)。セクションにヘッダーを設定するには、メソッド TitleForHeader をオーバーライドする必要があ

ります。

仮想メソッドのオーバーライドは MonoDevelop では簡単です。まず、データ ソース クラスの public セ

クションに宣言を入力します。「method」に続いてメソッド名の先頭の数文字を入力したら、Ctrl+Space

を押します。すると、コード補完機能が働き、メソッドを選択しその宣言を完成させることができるよう

になります。ただし、実装については、自分で入力する必要があります。文字列 Customers を返すように

実装します。

Page 25: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 24

セルにデータを設定するには、GetCell メソッドを使用します。このメソッドのパラメータとしては、テ

ーブル ビューのほか、セルのインデックス パス(セクション番号とそのセクション内での行番号で、

Section プロパティと Row プロパティで与えられます)があります。以下のコードでまず 初に注意すべ

きことは、再利用可能なセルを通じた仮想リストがもともとサポートされていることです。非常に長いリ

ストを表示する場合、項目ごとに UITableViewCell を作成するのは、必要なメモリ使用量の観点から、実

用的でない可能性があります。そのようなことをする代わりに、スクロールされて画面から見えなくなっ

たセルを再利用できるテーブル ビューの機能を活用できます。異なるセル識別子を使用するだけで、さま

ざまなカテゴリの再利用可能セルを扱えます。

method RootViewController.CustomerDataSource.GetCell(tableView: UITableView;

indexPath: MonoTouch.Foundation.NSIndexPath): UITableViewCell;

begin

var cellId: System.String := 'Cell';

var cell := tableView.DequeueReusableCell(cellId);

if cell = nil then

begin

cell := new UITableViewCell(UITableViewCellStyle.Subtitle, cellId);

// Add in a detail disclosure icon to each cell

cell.Accessory := UITableViewCellAccessory.DetailDisclosureButton;

end;

// Configure the cell.

with cust := controller.customerList[indexPath.Row] do

begin

cell.TextLabel.Text :=

String.Format('{0} {1}', cust.FirstName, cust.LastName);

cell.DetailTextLabel.Text := cust.Town;

end;

exit cell

end;

このコードでは、テキスト値とそれより短い追加テキスト(サブタイトル)をそれぞれ設定できるセルを

作成します。これらのセルは、それぞれ TextLabel プロパティと DetailTextLabel プロパティを通じてアク

セスされます。

セルのセットアップ時に、詳細開示ボタンも追加されます。つまり、丸で囲まれた小さい矢印が各セルの

右側に追加されます。こうなると、ユーザーからのアクションには 2 とおりの可能性があります。第 1 は

行全体をタップする場合で、そのときは RowSelected がトリガされます。第 2 は詳細開示ボタンをタップ

する場合で、このときは AccessoryButtonTapped がトリガされます。RowSelected は、別の画面を表示す

るのに使用されることが多いので、今回、RowSelected ではそのまま何もせず、詳細開示ボタンをサポー

トするだけにします(このボタンをクリックすると、選択した顧客に関する何らかの情報を表示する警告

が発行されます)。

method RootViewController.CustomerDataSource.AccessoryButtonTapped(

tableView: UITableView; indexPath: NSIndexPath);

begin

Page 26: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 25

var cust := controller.customerList[indexPath.Row];

InfoAlert(string.Format ("{0} {1} has ID {2}",

cust.FirstName, cust.LastName, cust.CustID))

end;

以上の結果として、以下のようなアプリケーションができあがります。

ナビゲーション コントローラ

では、[iPhone Navigation-based Project] テンプレートを使ったナビゲーションベース プロジェクトをも

う 1 つ開始しましょう。今度は、テーブル サポートよりもナビゲーション サポートに重点を置きます。

テーブル ビューは他のページのメニューとして働くだけです。このメニューには 3 つの項目が含まれてい

ます。また、リスト/メニューにはセクションがいくつかありますが、これはただ、メニュー項目をグルー

プ化する方法を示すためです。今回、各項目は独自のセクションに存在するので、セクションが 3 つある

ことになりますが、これらのセクション内でリスト項目をどう割り当てるかは、アプリケーションに任さ

れます。

NumberOfSections メソッドが 3 を、RowsInSection メソッドが 1 を、それぞれ返すようにコーディング

したあと、コード補完機能を使ってクラス宣言の public セクションに先ほどのように TitleForHeader メソ

ッドを追加します(「method Ti」と入力したあと Ctrl+Space を押します)。このメソッドは以下のよう

に実装します。

method RootViewController.DataSource.TitleForHeader(tableView: UITableView;

Page 27: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 26

section: Int32): String;

begin

case section of

0: exit 'UIKit example';

1: exit 'CoreLocation & MapKit example';

2: exit 'Device information example';

end;

end;

メニューのセクションごとに選択肢の種類が異なり、CocoaTouch ライブラリのさまざまな部分が例とし

て表示されます。テーブル セル(つまりメニュー項目)に値を設定するには、先ほどと同じように、

GetCell にコードを追加する必要があります。ただし今度は、リスト内のセルが少ないことがわかってい

るので、前述のような再利用可能セルの機能は必要ありません。

method RootViewController.DataSource.GetCell(tableView: UITableView; indexPath:

MonoTouch.Foundation.NSIndexPath): UITableViewCell;

begin

var cell := new UITableViewCell(UITableViewCellStyle.Default, '');

if (indexPath.Section = 0) and (indexPath.Row = 0) then

cell.TextLabel.Text := 'Web browser';

if (indexPath.Section = 1) and (indexPath.Row = 0) then

cell.TextLabel.Text := 'GPS information';

if (indexPath.Section = 2) and (indexPath.Row = 0) then

cell.TextLabel.Text := 'Device information';

exit cell

end;

これらの例をどこかに実装するには、さらに 3 ページ必要になります。ソリューションのアクティブ プロ

ジェクトに新しいファイルを追加するには、メイン メニューの [ファイル|新規|ファイル](または ⌘+N

キー)を使用するか、[ソリューション] ウィンドウでプロジェクトを右クリックし [追加|新しいファイ

ル] を選択します。どちらの方法でも、ポップアップするダイアログで [iPhone and iPad] をクリックし

[iPhone View with Controller] を選択します。この 初のページには BrowserPage という名前を付けます。

以上と同じことを行って、さらに GPSPage というページを追加し、 後に InfoPage というページを追加

します。

これらの新しいファイルにはそれぞれ、ファイル名に指定したのと同じ名前の付いた UIViewController 下

位クラス オブジェクトが記述されます。ユーザーがテーブル ビューから項目を 1 つ選択したときに、こ

れらの新規ビューのいずれかを起動することになるので、RootViewController.xib.pas での 後のコーディ

ングとして、以下の RowSelected メソッドを追加しなければなりません。

method RootViewController.DataSource.RowSelected(tableView: UITableView;

indexPath: MonoTouch.Foundation.NSIndexPath);

begin

if (indexPath.Section = 0) and (indexPath.Row = 0) then

Page 28: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 27

controller.NavigationController.PushViewController(

new BrowserPage(), true);

if (indexPath.Section = 1) and (indexPath.Row = 0) then

controller.NavigationController.PushViewController(new GPSPage(), true);

if (indexPath.Section = 2) and (indexPath.Row = 0) then

controller.NavigationController.PushViewController(new InfoPage(), true);

end;

おわかりのように、ナビゲーション コントローラでは、自分のビュー コントローラ スタックに新しいビ

ュー コントローラをプッシュできます。この新しいビュー コントローラのビューが表示され、ナビゲー

ション バーには、前のページに戻るためのボタンが表示されます。そのため、元に戻るのが容易になりま

す。

後に、ナビゲーション バーのテキストを編集するには、MainWindow.xib をダブルクリックし、

[Navigation Controller] ウィンドウが表示されているのを確認したうえで(必要があれば、ドキュメント

ウィンドウで [Navigation Controller] をダブルクリックします)、ナビゲーション バーをダブルクリック

します。任意のテキストを追加します。このサンプル プロジェクトでは単に「Brian’s Stuff」と入力しま

す。

メモ: SQLite を使用したサンプル プログラムの話に戻ると、そこでは、初期化(セットアップ)コード

は ViewDidLoad に、後始末コードは ViewDidUnload に、それぞれ記述しました。これでよかった理由は、

アプリケーションの起動時にメモリにロードされ、(アプリケーションの終了時やメモリの残量が少なく

なったときなどに)ビューがメモリから削除されるたびにアンロードされるビューが 1 つだけだったか

Page 29: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 28

らです。今回のアプリケーションには、メニュー ビューのほかに、さらに 3 つの二次的なビューがあり、

そのそれぞれに初期化コードと後始末コードが必要になる場合があります。確かに、各ビューが初めて開

くと ViewDidLoad コードが実行されますが、ユーザーがメニューに戻っても ViewDidUnload は実行され

ません。同様に、同じ二次ビューに戻っても、それがまだメモリにロードされているので、ViewDidLoad

が再び実行されるわけではありません。

ビューが表示されなくなったらすぐに後始末コードを実行する必要があるのかどうか(たとえばパフォー

マンス上の理由で)、それとも、 終的にメモリから削除されるまでビューをほうっておいてよいのかど

うかを判断することが重要です。それによって、ViewDidLoad/ViewDidUnload メソッドを引き続き使用す

べきなのか、ViewDidAppear/ViewDidDisappear メソッドに切り替えるべきなのかが決まります。

UIWEBVIEW を使った WEB ブラウズ

では、Web ブラウザ ページに取りかかりましょう。このページの構成要素には、まず、Bar Button Item

コントロール(UIBarButtonitem)の付いた Navigation Bar コントロール(UINavigationBar)があります。

この両者は、[Library] ウィンドウの [Objects] タブに表示されるライブラリ ツリーの [Windows, Views &

Bars] サブノードに含まれています。さらに、2 つの Round Rect Button コントロール(UIButton)のほか、

Text Field コントロール(UITextField)、Web View コントロール(UIWebView)も必要です。このうち

の 後のものは、上記 [Objects] タブのライブラリ ツリーの [Data Views] サブノードに含まれています。

これらは、以下に示す Interface Builder のスクリーンショット(左図)のように配置できます。その右側

にあるのは、ターゲット アプリケーション ページの実行イメージです( 上部のナビゲーション バーは

メイン ウィンドウのものであることを思い出してください)。ナビゲーション バー ボタンでは、自分の

画像を Identifier 属性で選択することができます。

Page 30: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 29

これらのコントロールの一部については、実行時にアクセスできるように、アウトレットをセットアップ

する必要があります。UIViewController をベースにしたページの場合は、ドキュメント ウィンドウで

[View] の下に追加したコントロールが表示されます。アウトレットは BrowserPage オブジェクトに追加す

る必要がありますが、このオブジェクトは、ドキュメント ウィンドウで [File's Owner] として選択できま

す。以下のスクリーンショットには、5 つの新しいアウトレットの名前が表示されています。なお、ボタ

ン アウトレットを追加するのは、単に、Interface Builder でアクションをセットアップするのではなく無

名メソッド構文を使ってイベント ハンドラをセットアップできるようにするためです。アクションをセッ

トアップしてしまうと、イベント ハンドラ コードを記述したアクション メソッドを実装する必要があり

ます。

これらの UI コントロールについては、左右の矢印が [戻る] および [進む] の履歴ナビゲーション ボタンで、

下側のナビゲーション バーのボタンが現在のページを更新するという考え方です。テキスト フィールド

(Text Field コントロール)はブラウザのアドレス バーと同じものにするので、属性インスペクタを使用

して、[Keyboard] 属性を [URL] に、[Return Key] 属性を [Go] に、それぞれ設定します。

(実行中のアプリケーションで) 上部のナビゲーション バーに、メイン ページに戻るためのボタンが

あることに注意してください。

このページの実装はかなり簡単です。以下のように、ビューのロード時には、さまざまな UI コントローラ

を初期化する必要があるほか、デフォルトの Web ページが読み込まれます。

method BrowserPage.ViewDidLoad;

begin

inherited;

InitButtonsAndTextField;

InitBrowser;

Page 31: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 30

//Load a default page

LoadPage("flickr.com");

end;

これらすべての処理にヘルパ関数が使用されています。初期化関数では、コントロールのイベントをセッ

トアップします。ボタンの処理は簡単です。UIWebView 内の対応するメソッドを呼び出すだけです。前述

のとおり、テキスト フィールドの ShouldReturn プロパティにより、[Go] が押されたときにキーボードが

必ず閉じるようになりますが、さらに、その後、フィールドに入力された URL が読み込まれます。

method BrowserPage.Alert(Caption, Msg: String);

begin

using av := new UIAlertView(Caption, Msg, nil, 'OK', nil) do

av.Show;

end;

method BrowserPage.InitButtonsAndTextField;

begin

backButton.TouchUpInside += method begin webBrowser.GoBack end;

fwdButton.TouchUpInside += method begin webBrowser.GoForward end;

refreshButton.Clicked += method begin webbrowser.Reload end;

urlField.ShouldReturn := textField -> begin

Result := textField.ResignFirstResponder; //Hide keyboard

LoadPage(textField.Text.ToString);

end;

end;

method BrowserPage.InitBrowser;

begin

webbrowser.LoadStarted += method

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := true

end;

webbrowser.LoadFinished += method

begin

urlField.Text := webBrowser.Request.Url.AbsoluteString;

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := false

end;

webbrowser.LoadError += method(sender: Object; e: UIWebErrorArgs)

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := false;

Alert('Browser error', 'Web page failed to load: ' + e.Error.ToString());

end;

end;

Page 32: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 31

Web ブラウザ コントロールにもイベント ハンドラがセットアップされますが、その主な目的は、iPhone

ステータス バーのネットワーク アクティビティ インジケータを作動/停止させることです。このアイコン

は、奇妙なことに、ネットワーク アクティビティに自動的に反応するものではなく、また、あらゆるナビ

ゲーション エラーを警告として通知します。そのうえ、Web 要求によるページの読み込みが完了したと

き、ページは 終的に、要求されたものとは異なる URL に解決される可能性があります。これはモバイル

デバイスでは非常によくあることです。ページがモバイル専用版にリダイレクトされるからです。

LoadFinished イベント ハンドラは、この 終的な URL をテキスト フィールドに反映させます。

残りのメソッドは LoadPage ですが、ここでは、URL の先頭に必要な "http://" を必ず付けたあと、NSUrl

から NSUrlRequest を作成して UIWebView の LoadRequest メソッドに渡します。

method BrowserPage.LoadPage(url: String);

begin

if url <> '' then

begin

if not url.StartsWith('http') then

url := string.Format('http://{0}', url);

webbrowser.LoadRequest(new NSUrlRequest(new NSUrl(url)));

end;

//Show the URL that was requested

urlField.Text := url;

end;

これで、先ほど示した完全機能版の Web ブラウザに、デフォルトで http://flickr.com(これはその後、写

真共有サイト Flickr のモバイル版にリダイレクトされます)が表示されます。

CORELOCATION および MAPKIT による位置/方位のサポート

iPhone を始めとする 新のスマートフォンのとてもすてきな機能の 1 つは、GPS とコンパス(方位計)

の組み込みサポートです。ランニングやサイクリング中の進行状況を地図にしたり、単に移動経路を記録

できる便利なアプリケーションが、この機能を使って多数作成されています。

基本的な GPS/コンパス サポート機能が CoreLocation API を通じて提供されており、位置情報に対応した

マップ コントロール MKMapView9 が MapKit に含まれています。今回のサンプル アプリケーションの

GPSPage ビューでは、CoreLocation と MKMapView を使用して、現在の位置、方位、高度、速度を表示

します。その UI を Interface Builder で作成するには、以下のスクリーンショットに示したような 16 個の

テキスト付きラベル(Label コントロール)とマップ ビュー(Map View コントロール)を設定する必要

があります。N/A と書かれているすべてのラベルとマップ ビューは、スクリーンショットに示した接続イ

ンスペクタのように、GPSPage に定義されているアウトレットに接続しなければなりません。

では次に、コードに取りかかります。

9 MKMapView コントロールでは、Google のサービスを使用して必要な処理を行います。ユーザーは、このコントロ

ールを使用することで、Google の利用条件(http://code.google.com/apis/maps/iphone/terms.html で参照可能)に

従うことに同意したものとみなされます。

Page 33: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 32

位置情報に基づいた機能の出発点となるのは CLLocationManager クラスなので、この型の変数

locationManager を GPSPage クラスに宣言します。このオブジェクトは、ロケーションに関する GPS 情

報(GPS ハードウェアから得られる位置、進路、速度、高度10)と、コンパスによる方位情報(デバイス

が向かっている方向)を提供します。GPS に依存した情報の精度は変化しますが、これは、GPS データ本

来の性質です(追跡に使われる人工衛星の数が変化するからです)。

方位と位置の変化に応じてトリガされるコールバック機能をロケーション マネージャが提供するので、移

動を追跡できます。作成するアプリケーションの種類に応じて、データの希望精度のほか、方位/位置の変

化がアプリケーションに通知される頻度も制御することができます。詳細な経路を追跡する必要がなけれ

ば、位置変化のたびに通知を受けるのは行き過ぎでしょう。位置がたとえば 50 メートル変化したら通知

を受けるようにするほうが適切かもしれません。必要な精度が低く通知頻度が少ないと、多くの場合、電

池使用量の観点からは役に立ちます。

このコールバック メカニズムは、デリゲート オブジェクト(CLLocationManagerDelegate 型から継承)

をサポートする一般的なアプローチを使って CoreLocation に実装されており、このオブジェクトに、位

置や方位の変化を処理するためのオーバーライド対象メソッドがあります。このようなクラスのインスタ

ンスを生成して、ロケーション マネージャの Delegate プロパティに割り当てます。以下のコードはデリ

ゲート クラスの例です(メイン ビュー GPSPage がコンストラクタに渡され、そこで Page 変数に格納さ

れるので、デリゲート オブジェクトがビュー内のコントロールにアクセスできるようになることに注意し

てください)。

CoreLocationManagerDelegate nested in GPSPage =

class(CLLocationManagerDelegate)

private

10 GPS 信号またはハードウェアが利用できない場合、デバイスは、携帯電話のアンテナ搭や WiFi ホットスポットに基

づいて粗い位置情報を提供します。

Page 34: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 33

Page: GPSPage;

public

constructor (page: GPSPage);

method UpdatedHeading(manager: CLLocationManager;

newHeading: CLHeading); override;

method UpdatedLocation(manager: CLLocationManager;

newLocation, oldLocation: CLLocation); override;

end;

前述のとおり、このようなデリゲート オブジェクトとそれらの任意メソッドを取り込んで、メイン オブ

ジェクトのイベントとして公開するのが MonoTouch アプローチです。そのため、ロケーション マネージ

ャには実際には UpdatedHeading および UpdatedLocation というプロパティがあります。今回のコード

では、代わりにそれらを使用します。

これらのメソッドのシグネチャは、標準の .NET イベント シグネチャに適合します。

method UpdatedHeading(sender: Object; args: CLHeadingUpdatedEventArgs);

method UpdatedLocation(sender: Object; args: CLLocationUpdatedEventArgs);

ここで、sender はロケーション マネージャを参照しており、args パラメータには、対応するデリゲート

オブジェクト メソッドに送られる残りのパラメータに対応するプロパティが含まれています。

GPSPage.ViewDidAppear で、以下のように、ロケーション マネージャを初期化します。

locationManager := new CLLocationManager();

locationManager.DesiredAccuracy := -1; //Be as accurate as possible

locationManager.DistanceFilter := 50; //Update when we have moved 50 m

locationManager.HeadingFilter := 1; //Update when heading changes 1 degree

locationManager.UpdatedHeading += UpdatedHeading;

locationManager.UpdatedLocation += UpdatedLocation;

locationManager.StartUpdatingLocation();

locationManager.StartUpdatingHeading();

また、ViewDidDisappear で、以下のようなクリーンアップ処理を行わなければなりません。

locationManager.StopUpdatingHeading();

locationManager.StopUpdatingLocation();

locationManager.Dispose;

locationManager := nil;

メモ: このページの初期化 /後始末コードは、(ViewDidLoad と ViewDidUnload ではなく)

ViewDidAppear と ViewDidDisappear に記述し、ユーザーがメニューに戻ったときに GPS ハードウェアが

それ以上ビューに情報を通知し続けることがないようにします。

Page 35: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 34

ここで参照されているイベント ハンドラに目を向ける必要がありますが、まずは、マップ ビューも初期

化しておかなければなりません。ViewDidAppear メソッド内のロケーション マネージャ初期化コードの

上に、以下のコードを追加する必要があります。

MapView.WillStartLoadingMap += method

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := true

end;

MapView.MapLoaded += method

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := false

end;

MapView.LoadingMapFailed += method

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := false;

end;

MapView.MapType := MKMapType.Hybrid;

MapView.ShowsUserLocation := True;

//Set up the text attributes for the user location annotation callout

MapView.UserLocation.Title := 'You are here';

MapView.UserLocation.Subtitle := 'YA RLY!';

ここで、UIWebView のイベントとよく似ていて同じような処理を行う(ただし、今度はエラーをすべて無

視するだけですが)マップ ビュー イベントがあることがわかります。MapType プロパティと

ShowsUserLocation プロパティは実際には Interface Builder の属性インスペクタで設定できますが、ここ

ではそうせずに、コードで設定しています。MapType では、Google や Bing などの地図で可能な通常表

示の種類を選択できます。標準(地図)、衛星写真、ハイブリッド(衛星写真に道路標示を加えたもの)

のいずれかです。ShowUserLocation では、ユーザーの位置を決定できると仮定して、それを(注釈を使っ

て)地図に表示するかどうかを制御します。設定される 後のプロパティ UserLocation では、この地図注

釈をカスタマイズします。注釈をクリックしたときに、タイトルとサブタイトルから成る追加情報を表示

する吹き出しが開くようにすることができますが、ここで設定しているのはまさにそれです。

では、コールバック イベントの話に戻りましょう。提供される新しい方位値は 2 つしかないので、方位変

化のコールバックは短く簡単なコードになります。args 内に格納されている NewHeading オブジェクト

には、TrueHeading プロパティ(真北からの相対方位)と MagHeading プロパティ(磁北からの相対方

位)があります。また、方位値の精度(度単位)を示す HeadingAccuracy も提供されます。この精度値が

負の場合は、方位情報は取得できなかったことになります。たとえば、iPhone シミュレータの場合がそう

です。シミュレータには GPS 機能が一部ありますが、コンパスのエミュレーション機能はありません。

method GPSPage.UpdatedHeading(sender: Object;

args: CLHeadingUpdatedEventArgs);

begin

if args.newHeading.HeadingAccuracy >= 0 then

begin

MagHeadingLabel.Text := string.Format('{0:F1}° ± {1:F1}°',

Page 36: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 35

args.NewHeading.MagneticHeading, args.NewHeading.HeadingAccuracy);

TrueHeadingLabel.Text := string.Format('{0:F1}° ± {1:F1}°',

args.NewHeading.TrueHeading, args.NewHeading.HeadingAccuracy);

end

else

begin

MagHeadingLabel.Text := 'N/A';

TrueHeadingLabel.Text := 'N/A';

end

end;

位置変化のコールバックはもう少し長めですが、それは、GPS ハードウェアから取得できる値がもっと多

いからにすぎません。今度は、args には、NewLocation と OldLocation の 2 つの CLLocation オブジェク

トが格納されているため、必要があれば 2 地点間の移動距離を算出することもできます(CLLocation には

DistanceFrom メソッドが用意されています)。

method GPSPage.UpdatedLocation(sender: Object; args: CLLocationUpdatedEventArgs);

const

LatitudeDelta = 0.002; //no. of degrees to show in the map

LongitudeDelta = LatitudeDelta;

begin

var PosAccuracy:= args.NewLocation.HorizontalAccuracy;

if PosAccuracy >= 0 then

begin

var Coord := args.NewLocation.Coordinate;

//In simulator, MapKit's user location is fixed on Apple's HQ but

//CoreLocation will happily detect current location via network

//(contrary to Apple docs)

LatitudeLabel.Text := string.Format(

'{0:F6}° ± {1} m', Coord.Latitude, PosAccuracy);

LongitudeLabel.Text := string.Format(

'{0:F6}° ± {1} m', Coord.Longitude, PosAccuracy);

if Coord.IsValid then

begin

var region: MKCoordinateRegion := new MKCoordinateRegion(

Coord, new MKCoordinateSpan(LatitudeDelta, LongitudeDelta));

MapView.SetRegion(region, False);

MapView.SetCenterCoordinate(Coord, False);

MapView.SelectAnnotation(MapView.UserLocation, False);

end;

end

else

begin

LatitudeLabel.Text := 'N/A';

Page 37: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 36

LongitudeLabel.Text := 'N/A';

end;

if args.NewLocation.VerticalAccuracy >= 0 then

AltitudeLabel.Text := string.Format(

'{0:F6} m ± {1} m', args.NewLocation.Altitude,

args.NewLocation.VerticalAccuracy)

else

AltitudeLabel.Text := 'N/A';

if args.NewLocation.Course >= 0 then

CourseLabel.Text := string.Format('{0}°', args.NewLocation.Course)

else

CourseLabel.Text := 'N/A';

SpeedLabel.Text := string.Format('{0} m/s', args.NewLocation.Speed);

end;

コードを細かく見ていくと、 初の長い条件文では、位置を処理し、該当する位置と得られた精度で緯度

および経度のラベルを更新すると共にマップ ビューの位置も更新します。精度値が負の場合、位置は取得

されなかったので、N/A がラベルに書き込まれます。

コードには、シミュレータの GPS 機能について述べているコメントが含まれています。筆者がフォーラム

や Apple のドキュメントで見つけたすべてのリファレンスには、iPhone シミュレータでは CoreLocation

は常に固定位置(1 Infinite Loop, Cupertino, CA 95014 の Apple 本社)を 100 m の精度で返すと記載され

ています。筆者がテストしたところでは、これはマップ ビュー(Map View コントロール)には当てはま

り、強制的に他の動作に変更されていない限り、ユーザーの位置として常に Apple 本社の場所が通知され

ます。ただし、CoreLocation の方は筆者の位置を正しく識別し、オフィスの座標を返すことができました。

これは、さまさまな資料の記述と矛盾するように思われ、MapKit と CoreLocation でシミュレータ内部に

一致しない部分が何かあることを示しています。

一貫性を保つために、コードでは、CoreLocation の返す座標を真の位置と見なし、その座標に基づいて表

示領域を指定したり地図をセンタリングすることでマップ ビューに強制的に CoreLocation の座標を使用

させるようにします(こうするとユーザー位置注釈はなくなりますが、少なくとも本当の位置が表示され

ます)。地図表示領域は、座標と X 方向および Y 方向の差分に基づいてセットアップされます。差分は、

地球のどれだけの範囲を表示するかを度単位で指示するものです。ローカルな地域を見分けにくいよう、

どちらの差分にも小さい値を使用しています。マップ ビューのこのような制御は、CoreLocation の座標

が有効であると見なされる場合にのみ行われます。 初のいくつかのコールバックでは、初めのうち GPS

システムが通信を行っている間は座標を無効とするのが一般的です。

マップ ビューで 後に行うのは、ユーザーの位置で注釈に対して SelectAnnotation を呼び出すことです。

これは、注釈をクリックするのと同等で、その結果、(タイトルとサブタイトルの付いた)吹き出しが表

示されます。もちろん、アプリケーションで表示されているのがユーザーの実際の位置で、マップ ビュー

では Apple 本社の位置にユーザー位置注釈がある場合、それが表示されることは考えられません。サンプ

ル ソース コード(上記のコードには含まれていません)には、SHOW_FAKE_POSITION_IN_SIMULATOR

という条件付き定義があり、これを定義することで、この問題を克服し、マップ ビューのユーザー位置の

概念が必ず情報ラベルと地図の位置の両方に用いられ、その結果、ユーザー位置注釈が表示されるように

することができます。

Page 38: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 37

コードの残りの部分では、高度と方位の見慣れた処理(それらが有効であれば値を表示する)を行うと共

に、GPS 観測で判明した現在の速度も表示します。

以下のスクリーンショットでは動作中の GPS ページを示していますが、これは、上記の条件付きコンパイ

ル シンボルを定義したうえで取ったものなので、表示は Apple のドキュメントと一致しているように見え

ます。ユーザー位置注釈は実際には動的なものです。中心に青いビー玉のようなアイコンがあり、外側の

円が誤差半径を示しているほか、その両者の間にある青い円が中心から外側の円へと規則的に動き、目を

楽しませてくれます。

デバイスの回転

デバイスを 90°回転したときそれに反応して UI を再構成し縦長ではなく横長で適切に表示する iPhone ア

プリケーションが多いことに、おそらくお気づきでしょう。この回転サポートの主な基礎となっているの

が、ビュー コントローラ クラスの ShouldAutorotateToInterfaceOrientation 仮想メソッドです。デバイス

が回転されたとき、新しい向き(Portrait、LandscapeLeft、PortraitUpsideDown、LandscapeRight のいず

れか)を引数にこのメソッドが呼び出され、アプリケーションをその向きに回転すべきかどうかによって、

メソッドは True または False を返します。何もかまわず True を返しても、デバイスの回転に応じてアプ

リケーションも回転しますが、UI 自体は再構成されないことになります。今回のアプリケーションのメイ

ン フォームのような、テーブル ビューしか含まれていないシンプルなフォームの場合は、以下のように、

使用可能な領域全体をテーブル ビューが占めるので、それでも十分です。

Page 39: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 38

ただし、GPSPage のようなものでは、さまざまなコントロールが含まれていることを考えれば、もっと注

意が必要になります。そのままほうっておけば、マップ ビューは見えなくなり、右側に余白ができてしま

います。

依然として ShouldAutorotateToInterfaceOrientation が True を返す必要がありますが、それだけでなく、

回転に反応しコントロールのレイアウトを再構成するように WillAnimateRotation を実装する必要もあり

ます。UI の新しい向きを引数に取る以下のヘルパ ルーチン SetupUIForOrientation が使用されます。

SetupUIForOrientation(toInterfaceOrientation)

さらに、GPSPage が呼び出されたときにデバイスの向きがどのようにでもなっている可能性があることを

考えれば、ViewDidAppear からこのヘルパ ルーチンを呼び出す必要があります。

ViewDidAppear の冒頭に以下のコードを追加します。

if InterfaceOrientation not in [UIInterfaceOrientation.Portrait,

UIInterfaceOrientation.PortraitUpsideDown] then

SetupUIForOrientation(InterfaceOrientation);

このヘルパ ルーチンでは、向きを調べ、それに応じて、縦長モードではラベルの下に、横長モードではラ

ベルの右側に、それぞれマップ ビューを配置します。

method GPSPage.SetupUIForOrientation(orientation: UIInterfaceOrientation);

const

NavBarHghtPortrait = 44;

NavBarHghtLandscape = 32;

TextLabelsWidth = 270; //horizontal screen extent occupied by labels

TextLabelsHeight = 257; //vertical screen extent occupied by labels

begin

var DeviceHeight := Integer(UIScreen.MainScreen.Bounds.Height);

var DeviceWidth := Integer(UIScreen.MainScreen.Bounds.Width);

with AppFrame := UIScreen.MainScreen.ApplicationFrame do

if orientation in [UIInterfaceOrientation.Portrait,

Page 40: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 39

UIInterfaceOrientation.PortraitUpsideDown] then

MapView.Frame := RectangleF.FromLTRB(0, TextLabelsHeight,

DeviceWidth, AppFrame.Height - NavBarHghtPortrait)

else

MapView.Frame := RectangleF.FromLTRB(TextLabelsWidth, 0,

DeviceHeight, AppFrame.Width - NavBarHghtLandscape);

end;

上記の定数は手動で決定しました。全画面の解像度(ポイント単位)は UIScreen.MainScreen.Bounds で

与えられ(iPhone では幅 320 高さ 480)、ステータス バーを考慮に入れた画面上の使用可能な領域は

UIScreen.MainScreen.ApplicationFrame で与えられます。

たとえば、横長モード(上記)では、マップ ビューの左縁をテキスト ラベル領域の全幅の後に、上縁を

一番上のピクセル 0(ステータス バーとナビゲーション バーの直下)に、それぞれ合わせる必要がありま

す。右縁は画面の一番右のピクセルに、下縁は横長画面の下端に、それぞれ合わせる必要があります。前

者は画面の "高さ" で与えられ、後者はアプリケーション フレームの幅(画面の "幅" からステータス バ

ーの高さを差し引いたもの)からナビゲーション バーの高さを差し引いたものです。

デバイス情報

今回のアプリケーションの 終ページは、デバイスに関するさまざまな情報を表示するためのものです。

このページには、 Interface Builder でレイアウトする別のラベル群のほか、Switch コントロール

(UISwitch)が必要になります。小さめの 6 個のラベルとスイッチ(Switch コントロール)がコードで必

要なので、以下に示すように、これらにアウトレットを接続する必要があります。

Page 41: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 40

ラベルに値を設定するのに必要な情報には、デバイスの種類や画面の解像度など、ビューがロードされし

だい取得可能になるものがあります。また、Application Frame Size(アプリケーション フレームのサイ

ズ: ステータス バーのオン/オフ切り替え時に変わる)、Proximity Sensor Status(近接センサの状態)、

Battery Status(電池の状態)など、必要に応じて更新される情報もあります。ユーザーがデバイスを操作

することで更新されるもう 1 つの情報は Interaction(ユーザーからの操作)で、デバイスが回転されたり

シェイクされた(左右に振られた)とき、あるいはユーザーがタップした(画面を軽くたたいた)ときに、

それを示すように更新されます。では、これらに 1 つずつ取り組みましょう。

個々のデバイスは、クラス メソッド Version(以下の列挙型の 1 つの値を返す)を提供するヘルパ クラス

DeviceHardware を使って識別されます。

type

HardwareVersion = public (

iPhone,

iPhone3G,

iPhone3GS,

iPhone4,

iPod1G,

iPod2G,

iPod3G,

iPod4G,

iPad,

iPhoneSimulator,

iPhone4Simulator,

iPadSimulator,

Unknown);

Page 42: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 41

このクラス(ネイティブ相互運用機能を利用)のコードはここでは重要ではありませんが、サンプル プロ

ジェクトに付属しています。これは、Mono Wiki:

http://wiki.monotouch.net/HowTo/Device/Detect_the_Hardware_Type

で公開されている既存の C# コードを今回の目的に合わせて手直しし拡張したものです。また、このクラ

スには、現在のデバイスについて記述した文字列を返すクラス メソッド VersionString もあります。デバ

イスの詳細を表示するため、ViewDidAppear には以下のコードが含まれています。

deviceLabel.Text := String.Format('{0}, iOS v{1}',

DeviceHardware.VersionString, UIDevice.CurrentDevice.SystemVersion);

これに続いて、画面の解像度とアプリケーション フレームのサイズを出力する以下のヘルパ ルーチンを

呼び出します。

method InfoPage.UpdateUIMetrics;

begin

with scrn := UIScreen.MainScreen do

begin

//iPhone 4 doubles pixel count, but point count remains same

resolutionLabel.Text := string.Format('{0}x{1} points, {2}x{3} pixels',

scrn.Bounds.Width, scrn.Bounds.Height,

scrn.Bounds.Width * scrn.Scale, scrn.Bounds.Height * scrn.Scale);

frameSizeLabel.Text := string.Format('{0}x{1} points',

scrn.ApplicationFrame.Width, scrn.ApplicationFrame.Height);

end;

end;

以下のように、ステータス バー スイッチを正しい初期値に設定する必要があり、そのあと、イベント ハ

ンドラも必要です。

statusBarSwitch.On := not UIApplication.SharedApplication.StatusBarHidden;

statusBarSwitch.ValueChanged += StatusBarValueChanged;

...

method InfoPage.StatusBarValueChanged(Sender: Object; E: EventArgs);

begin

UIApplication.SharedApplication.StatusBarHidden := not statusBarSwitch.On;

// NOTE: it's required to call the inherited View property from inside a

// ViewController, as the autogenerated 'view' property is nil, and Pascal

// isn't case sensitive.

// From outside the class, the View property works fine.

if (inherited View <> nil) and ((inherited View).Window <> nil) then

(inherited View).Window.Frame := UIScreen.MainScreen.ApplicationFrame;

//Without this, the nav bar is lazy about moving to the right place

Page 43: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 42

//Required a public property to be added to the AppDelegate

var AppDel := AppDelegate(UIApplication.SharedApplication.Delegate);

var NavController := AppDel.NavController;

NavController.SetNavigationBarHidden(True, False);

NavController.SetNavigationBarHidden(False, False);

UpdateUIMetrics

end;

ここで、注意すべきことがいくつかあります。まず第 1 に、ステータス バーの表示/非表示は、単に

UIApplication.SharedApplication.StatusBarHidden を通じて制御されます。

第 2 に、ステータス バーを非表示にするだけでは、現在のビューにほとんど影響がありません。画面上に

できた新しい領域に描画するため、ベースとなるウィンドウの Frame プロパティが画面の

ApplicationFrame プロパティに一致するように設定されています。今はビュー コントローラの下位クラス

にいることを思い出してください。ベース ウィンドウはビューのプロパティで、そのビューを表す View

(大文字の V)が UIViewController に定義されています。ただし、このクラスの分離コード ファイルにも

たまたまプロパティ view(小文字の v)が定義されており、それは常に nil を返します。ビュー コントロ

ーラに関連付けられているビューにアクセスしようとするときは必ず、忘れずに inherited View を使用す

ることが不可欠です。なお、C# から MonoTouch を使用する場合も、部分クラスにこの余分な(一見無意

味な) view プロパティがありますが、これは上記のような問題ではありません。C# は Delphi Prism とは

異なり、大文字/小文字を区別する言語だからです。

後に、使用可能な領域までビューのウィンドウ サイズを変更した後でも、ナビゲーション バーが反応

すべきときに反応しないことがよくあります(ウィンドウの上の方に移動したときにナビゲーション バー

がそれを認識できたりできなかったりしているように見えます)。この問題を克服するために筆者が見い

だした 善の方法は、ステータス バーが非表示になったら、ナビゲーション バーをいったん非表示にし

たうえで再表示することです。ただし、ナビゲーション バーへのアクセスについては、少し考える必要が

あります。

ナビゲーション バーがナビゲーション コントローラのプロパティとメソッドを通じて公開されているこ

とがわかると役に立ちますが、二次的なビューからナビゲーション コントローラにアクセスするにはどう

すればよいでしょうか。

メイン ウィンドウの分離コード ファイル MainWindow.xib.designer.pas では、ナビゲーション コントロ

ーラを公開するプロパティが AppDelegate クラスに追加されています。自動生成された部分クラスには、

取得アクセサ(get_navigationController)と設定アクセサ(set_navigationController)の付いたプロパテ

ィ navigationController が定義されています。問題は、これらのシンボルがすべて private なので、作成す

るコードからアクセスできないことです。これを克服する も直接的な方法は、メイン コード ファイル

Main.pas などで AppDelegate クラスに以下のような新しい public プロパティを定義することです。

public

property NavController: UINavigationController

read get_navigationController write set_navigationController;

Page 44: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 43

もちろん、その場合は、InfoPage から AppDelegate オブジェクトにどうアクセスするかという問題があ

りますが、それはすぐに解決されます。先に、UIApplication.SharedApplication を使って Application オブ

ジェクトにアクセスする方法について述べたことを思い出してください。Application オブジェクトのデリ

ゲート オブジェクト(つまり AppDelegate)は、Application オブジェクトの Delegate プロパティを通

じて得られます。いったんナビゲーション コントローラにアクセスできるようになったら、

SetNavigationBarHidden メソッドを使用してナビゲーション バーの表示/非表示を切り替えることができ

ます。

これでようやくアプリケーション フレームのサイズが変化するので、UpdateUIMetrics ヘルパが再び呼び

出されます。

このページが 初表示されたときには、ステータス バーがありましたが、スイッチによってそれが非表示

に切り替わる場合があります。このビューを終了してメニュー画面に戻る前に、元の状態に戻さなければ

なりません。それには、ViewDidDisappear で以下の処理を行います。

statusBarSwitch.On := True;

StatusBarValueChanged(statusBarSwitch, new EventArgs);

近接センサと通知

iPhone の近接センサは、ユーザーが電話に出て端末を顔に近づけたときに端末の表示を消すのに使用され

ています。これはおそらくその他の有用なさまざまなシナリオに利用できるので、近接状態の変化につい

て通知を受ける方法を見ておきましょう。メカニズムは単純です。何かに近づいたことが検出されるかさ

れないかのどちらかで、その状況が変わったときに状態変化の通知が行われます。以下のコードは、

ViewDidAppear のものです。

UIDevice.CurrentDevice.ProximityMonitoringEnabled := True;

if UIDevice.CurrentDevice.ProximityMonitoringEnabled then

NSNotificationCenter.DefaultCenter.AddObserver(

UIDevice.ProximityStateDidChangeNotification,

method

begin

proximityLabel.Text := iif(UIDevice.CurrentDevice.ProximityState,

'Proximity detected', 'Proximity not detected');

end)

else

proximityLabel.Text := 'Proximity sensor not available';

すべてのデバイスに近接センサが搭載されているわけではないので(たとえば、シミュレータにはありま

せん)、近接監視を作動させたあと、正常に作動しているかどうかを確認するほうがよいでしょう。作動

していなければ、近接センサが搭載されていません。

適切なハードウェアがある場合は、状態変化に対処するように準備する必要があります。これが、見慣れ

たデリゲート オブジェクト アプローチ(あるいはイベント プロパティによる代替手法)を用いない場合

の 1 つです。その代わり、通知センタによって管理される通知を用いますが、その際に検知するためのオ

Page 45: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 44

ブ ザ ー バ ( 監 視 役 ) メ ソ ッ ド が 必 要 に な り ま す 。 ど の ア プ リ ケ ー シ ョ ン に も 、

NSNotificationCenter.DefaultCenter でアクセスできる通知センタがあり、AddObserver で提供されるさ

まざまなオーバーロード メソッドのうち、 も簡単なものは通知識別子のほか、NSNotification オブジェ

クトを渡されるデリゲートを引数に取ります(これらの引数はコードでは無視されているので、無名メソ

ッドで宣言する必要はありません)。MonoTouch ドキュメントでは、以下のような宣言になっています。

AddObserver(string, Action<NSNotification>) : NSObject

Action<T> は、System 名前空間に宣言されている標準の .NET ジェネリック デリゲート型です。これは、

T 型のパラメータを引数に取り、値を返さない関数を表します。

Objective-C では、通知識別子はリテラル文字列であり、以下のようにすると AddObserver の第 1 パラメ

ータとしてうまく使用できます。

new NSString('UIDeviceProximityStateDidChangeNotification')

ただし、UIDevice クラスには、プログラミングに便利なように、これらの多数の通知識別子がプロパティ

としてセットアップされています。たとえば、以下はその一部です。

UIDevice.OrientationDidChangeNotification,

UIDevice.BatteryLevelDidChangeNotification,

UIDevice.BatteryStateDidChangeNotification.

近接状態監視を有効にしたことを忘れないでください。そのため、ViewDidDisappear で以下のようにそれ

を無効にするのが適切です。

if UIDevice.CurrentDevice.ProximityMonitoringEnabled then

UIDevice.CurrentDevice.ProximityMonitoringEnabled := False;

電池状態とタイマ

電池状態監視の動作は近接状態監視とかなり似ています。すべてのデバイスで電池状態監視がサポートさ

れているわけではなく(たとえば iPhone シミュレータではサポートされていません)、サポートされて

いるかどうかを確認するには、今回もやはり、監視を有効にしたあとで監視がまだ有効かどうかを確かめ

ます。有効でなければ、監視がサポートされていません。

電池状態監視は通知を使って行えますが、それは監視を常時行う場合にのみ適しています。消費電力をも

う少し減らすには、常時ではなく一定時間ごとに(たとえば 1、2 分間に 1 回)だけチェックすることが

できます。チェックのたびに、(可能であれば)電池監視を作動させ、電池残量レベルと電池状態を確認

したあと、監視を停止させます。以下は、このチェックを行うメソッドです。

method InfoPage.ReadBatteryStatus;

begin

with dev := UIDevice.CurrentDevice do

begin

Page 46: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 45

dev.BatteryMonitoringEnabled := True;

if dev.BatteryMonitoringEnabled then

try

batteryLabel.Text := string.Format('{0}% - {1}',

Math.Round(dev.BatteryLevel * 100), dev.BatteryState);

finally

dev.BatteryMonitoringEnabled := False

end

else

begin

batteryLabel.Text := 'Battery level monitoring not available';

UpdateBatteryStatusTimer.Invalidate

end

end

end;

このコードを一定の時間間隔で実行するには、定期的反復タイマが必要です。タイマは、実行ループ

(iOS において Windows メッセージ ループと同等のもの)でスケジュールされているときにのみ動作し、

何度も作動を繰り返す必要があります。

ViewDidAppear では、以下のように、タイマが 60 秒ごとにトリガされるようにセットアップされるほか、

電池チェック コードが 初に 1 回実行されます。

UpdateBatteryStatusTimer := NSTimer.CreateRepeatingScheduledTimer(

60, new NSAction(ReadBatteryStatus));

ReadBatteryStatus;

NSAction は前述の Action<T> に似ていますが、パラメータを取らず値も返さない関数を表す Mono デリ

ゲート型です。これは、近接状態通知のセットアップ時に渡した無名メソッドとは少し異なるように見え

ますが、以下のように書けば、もっと似た外見にすることもできます。

UpdateBatteryStatusTimer := NSTimer.CreateRepeatingScheduledTimer(

60, method begin ReadBatteryStatus end);

ReadBatteryStatus;

以下のように、もっと直観的にわかりやすい形にすることもできます。

UpdateBatteryStatusTimer := NSTimer.CreateRepeatingScheduledTimer(

60, @ReadBatteryStatus);

ReadBatteryStatus;

前述のタイマ イベント ハンドラでは、電池状態監視が使用できない場合、タイマはそれ自身の Invalidate

メソッドを使ってキャンセルされることに注意してください。また、ViewDidDisappear でそれと同じメソ

ッドを呼び出してタイマを忘れずにキャンセルすることも重要です。

Page 47: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 46

IPHONE へのユーザー操作

InfoPage で扱う 後のラベルは、ユーザーからの操作に関係するもので、タップ(軽くたたく)、スワイ

プ(横方向にスライドする)、シェイク(本体を左右に振る)、回転についての情報を提供することを目

的としています。 後のデバイス回転については、既に調べたので、簡単です。渡された向きにかかわら

ず ShouldAutorotateToInterfaceOrientation が True を返すようにしたあと、WillAnimateRotation に以下

のように少しコードを書く必要があります。

method InfoPage.WillAnimateRotation(

toInterfaceOrientation: UIInterfaceOrientation; duration: Double);

begin

interactionLabel.Text := case toInterfaceorientation of

UIInterfaceOrientation.Portrait: 'iPhone is oriented normally';

UIInterfaceOrientation.LandscapeLeft: 'iPhone has been rotated right';

UIInterfaceOrientation.PortraitUpsideDown: 'iPhone is upside down';

UIInterfaceOrientation.LandscapeRight: 'iPhone has been rotated left';

end;

SetTimerToClearMotionLabel;

UpdateUIMetrics

end;

メモ: この部分のコードでは、Delphi Prism 言語の 近のある機能を使用しています。それは case 式で

すが、これはよくある case 文とは異なります。

メモ: ここでは実際に UI を再構成するわけではなく、回転という変化に応答するだけなので、通知セン

タを使用することにし、向きの変化についての通知に応えて呼び出されるオブザーバを登録したほうがよ

いでしょう。

NSNotificationCenter.DefaultCenter.AddObserver(

UIDevice.OrientationDidChangeNotification, @OrientationChanged);

...

method InfoPage.OrientationChanged(notification: NSNotification);

begin

interactionLabel.Text := case InterfaceOrientation of

UIInterfaceOrientation.Portrait: 'iPhone is oriented normally';

UIInterfaceOrientation.LandscapeLeft: 'iPhone has been rotated right';

UIInterfaceOrientation.PortraitUpsideDown: 'iPhone is upside down';

UIInterfaceOrientation.LandscapeRight: 'iPhone has been rotated left';

end;

SetTimerToClearMotionLabel;

UpdateUIMetrics

end;

Page 48: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 47

コードでは、あらゆるユーザー操作が検知されるのに応じて、ユーザー操作ラベルを更新しますが、その

後、タイマを使用して 3 秒後にラベル テキストをリセットするヘルパ ルーチンを呼び出します。同様に、

UpdateUIMetrics も呼び出して解像度ラベルを更新します。

method InfoPage.SetTimerToClearMotionLabel;

begin

if ClearMotionLabelTimer <> nil then

ClearMotionLabelTimer.Invalidate;

ClearMotionLabelTimer := NSTimer.CreateScheduledTimer(3,

method

begin

interactionLabel.Text := 'None';

ClearMotionLabelTimer := nil;

end);

end;

このコードは、近接センサに使用したタイマ コードとよく似ているので、見覚えがあるはずです。ただし、

今回は、ラベルをリセットするのに、作動し続けるタイマではなく 1 回限りのタイマが必要なので、定期

的反復タイマではなく定時タイマが作成されます。

シェイク

iPhone では、ユーザーがシェイクする(本体を左右に振る)と、それを認識できます(アプリケーション

でそれが有効になっている場合)。この機能の標準的な用途は取り消し/やり直しですが、明らかに、使い

方はプログラマの想像力しだいです。しかし、そもそも、シェイク認識を有効にするにはどうすればよい

のでしょうか。それには、いくつかのことを行う必要があります。シェイク ジェスチャはビューに向けら

れると通常考えられていますが、正しく構成すればビュー コントローラで取得することができます。ビュ

ー コントローラに、自らが問題なくファースト レスポンダになり得ると宣言させ、それに合わせて処理

を行わせる必要があります。その後、シェイク サポートを有効にし、 後に、シェイクの検出を行える

MotionEnded メソッドをオーバーライドする必要があります。

デフォルトでは、ビュー コントローラの CanBecomeFirstResponder プロパティは False を返し、かえっ

てシェイク検出の邪魔になります。ただし、幸いにも、このプロパティの取得アクセサは virtual と宣言さ

れているので、以下のようにオーバーライドすることができます。

method InfoPage.get_CanBecomeFirstResponder: Boolean;

begin

exit True

end;

ViewDisAppear で BecomeFirstResponder を、ViewDidDisappear で ResignFirstResponder を、それぞれ

呼び出すことで、 初のステップは完了です。シェイク サポートを有効にするには、以下を

ViewDidAppear に追加します。

UIApplication.SharedApplication.ApplicationSupportsShakeToEdit := True;

Page 49: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 48

残された 後のステップは、検出されたシェイクに実際に応答することです。

method InfoPage.MotionEnded(motion: UIEventSubtype; evt: UIEvent);

begin

if motion = UIEventSubtype.MotionShake then

begin

interactionLabel.Text := 'iPhone was shaken';

SetTimerToClearMotionLabel

end

end;

シェイクをもっと一般的な目的、つまり取り消し/やり直しに使用する場合は、NSUndoManager クラスを

調べてその実装に役立てる必要があるでしょう。

タップ

ユーザーが画面をタップした(軽くたたいた)場合、それに応答するには、いくつかの方法があります。

今回のアプリケーションでは、TouchesBegan メソッド、TouchesMoved メソッド、TouchesEnded メソ

ッドをオーバーライドして、起こっていることを通知するアプローチを取ります。この方法では、タップ、

ダブルタップ、マルチタップを検出することができ、場合によってはスワイプ ジェスチャも検出できます11。タッチ操作をサポートする一連の仮想メソッドの締めくくりとなるのが TouchesCancelled です。これ

は、メモリ不足のような状況のためにタッチ操作が突然終了したときに知らせてくれるので、役に立ちま

す。

method InfoPage.DescribeTouch(touch: UITouch): String;

begin

Result := case touch.TapCount of

0: 'Swipe';

1: 'Single tap';

2: 'Double tap';

else 'Multiple tap' end +

case touch.Phase of

UITouchPhase.Began: ' started';

UITouchPhase.Moved: ' moved';

UITouchPhase.Stationary: " hasn't moved";

UITouchPhase.Ended: ' ended';

UITouchPhase.Cancelled: ' cancelled' end;

end;

method InfoPage.TouchesBegan(touches: NSSet; evt: UIEvent);

begin

11一般に、ジェスチャを認識する場合は、単純なタップの場合とは異なり、座標のシーケンスを自動的に追跡する面倒

な処理を引き受けてくれるジェスチャ レコグナイザについて詳しく調べるとよいでしょう。

Page 50: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 49

var touchArray := touches.ToArray<UITouch>;

if touches.Count > 0 then

begin

var Coord := touchArray[0].LocationInView(touchArray[0].View);

if touchArray[0].TapCount < 2 then

StartCoord := Coord;

interactionLabel.Text := string.Format('{0} ({1},{2})',

DescribeTouch(touchArray[0]), Coord.X, Coord.Y);

end;

end;

method InfoPage.TouchesMoved(touches: NSSet; evt: UIEvent);

begin

var touchArray := touches.ToArray<UITouch>;

if touches.Count > 0 then

begin

var Coord := touchArray[0].LocationInView(touchArray[0].View);

interactionLabel.Text := string.Format('{0} ({1},{2})',

DescribeTouch(touchArray[0]), Coord.X, Coord.Y);

end;

end;

method InfoPage.TouchesEnded(touches: NSSet; evt: UIEvent);

begin

var touchArray := touches.ToArray<UITouch>;

if touches.Count > 0 then

begin

var Coord := touchArray[0].LocationInView(touchArray[0].View);

interactionLabel.Text := string.Format('{0} ({1},{2})->({3},{4})',

DescribeTouch(touchArray[0]),

StartCoord.X, StartCoord.Y, Coord.X, Coord.Y);

SetTimerToClearMotionLabel

end;

end;

説明文を生成するヘルパ メソッドでは、case 式の連結を使用しているほか、Delphi Prism では文字列の区

切り記号として単一引用符と二重引用符のどちらもサポートされている点も活かしています。

これらのメソッドには一連の UITouch オブジェクトが渡されるので、潜在的にマルチタッチ操作に対応で

きます。ところがプログラムでは、マルチタッチが有効になっていないので、実際にはそれに対応してい

ません。そのため、いずれの場合にも、touchArray にはただ 1 つの UITouch オブジェクトしか格納されて

いません。 初のタップ座標が StartCoord(ビュー コントローラ クラスに宣言)に記録されているので、

以下のスクリーンショットに示すように、ダブルタップまたはスワイプに関するメッセージに、終了座標

だけではなくこの開始座標も含めることができます。

Page 51: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 50

iPhone アプリケーションでマルチタッチをサポートする必要がある場合は、ViewDidLoad や Initialize な

どのスタートアップ メソッドの 1 つに以下のコードを追加する必要があります。

(inherited View).MultipleTouchEnabled := True;

iPhone シミュレータでマルチタッチをシミュレートするには、option(または alt)キーを押します。

ユーティリティ アプリケーション

使用可能な別のプロジェクト テンプレート([iPhone Utility Project] テンプレート)を利用すると、ユーテ

ィリティを作成できます。これは、2 つのビューで構成されるシンプルなアプリケーションを作成するた

めのものです。もう一方のビューに移動するためのボタンがデフォルトで付いたメイン ビューが表示され

ます。メイン ビューには小さい情報ボタンがあり、それを押すと、すてきなアニメーションでページがひ

っくり返り、もう一方のビュー(フリップサイド ビューまたは反転ビューと呼ばれます)が現れます。フ

リップサイド ビューには、(再びすてきなフリップ アニメーションを使って)メイン ビューに戻るため

のボタンが付いたナビゲーション バーがあります。

Page 52: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 51

ユーティリティ プロジェクトには多数のファイルがあるので、それらにざっと目を通しておきましょう。

空 の ウ ィ ン ド ウ と App Delegate が Main.pas 、 MainWindow.xib 、 分 離 コ ー ド フ ァ イ ル

MainWindow.designer.xib.pas に定義されています。App Delegate は、メイン ビュー コントローラのイ

ンスタンスを生成し、そのビューのサイズを適切に設定し、メイン ビューをウィンドウに配置します。こ

の メ イ ン ビ ュ ー と ビ ュ ー コ ン ト ロ ー ラ は 、 ( MainView.xib と 分 離 コ ー ド フ ァ イ ル

MainView.xiv.designer.pas に基づいた)MainView.pas と MainViewController.pas にそれぞれ定義されてい

ます。MainView.xib を Interface Builder にロードすると、情報ボタン(Info Button コントロール)が表示

され、アクション showInfo: がコントローラに定義されていることがわかります。それに対応するメソッ

ドがメイン ビュー コントローラにあります。このメソッドは、フリップサイド ビュー コントローラを生

成してビューに割り当てると共に、フリップサイド ビューのナビゲーション バーにある [Done] ボタン

(押すとビューが閉じる)のカスタム イベント ハンドラもセットアップします。

このユーティリティ プロジェクトは、(同じ .xib ファイルに定義されている)メイン ビューとメイン ビ

ュー コントローラに、クラスを定義する専用のソース ファイルがあるという点で、ここでこれまで見て

Page 53: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 52

きたプロジェクトのスタイルからずれています。この理由は、ユーティリティ プロジェクトでは、ビュー

コントローラにもビュー(メイン ビューとフリップサイド ビューの両方)にもそれぞれカスタム クラス

があるのに対して、これまでのプロジェクトでは、ビューは定義済みの型(通常は UITableView)であっ

たからです。とは言え、種々の UI 処理(さまざまなコントロールのイベント ハンドラ)をビュー コント

ローラの下位クラスで行い、ビューの下位クラスには必要なあらゆるカスタム描画/表示だけをさせる仕組

みは、やはり共通しています。

SOAP ベースの WEB サービス

ユーティリティ プロジェクトを利用して、Web サービス コンシューマを作成しましょう。ここでは、温

度を摂氏と華氏の間で変換するのにすぐに使えるシンプルな SOAP ベース Web サービスを使用します。

[iPhone Utility Project] テンプレートを使って新しい iPhone ユーティリティ プロジェクトを作成したあと、

[ソリューション] ウィンドウでプロジェクト名を右クリックし、[追加|Web 参照の追加] をクリックしま

す。その結果、Web サービス インポート ダイアログ([Web 参照の追加] ダイアログ)が表示されますが、

そこにはシンプルな温度変換 Web サービスの URL:

http://www.w3schools.com/WebServices/TempConvert.asmx

が既に入力されています。必ず [フレームワーク] フィールドを [.NET 2.0 Web サービス] に設定してから

[OK] をクリックして、該当する Web サービスをプロジェクトにインポートします。

Web ブラウザにこの Web サービス アドレスを入力すると、この TempConvert Web サービスでは

CelsiusToFahrenheit と FahrenheitToCelsius を提供していて、簡単ではありますが十分な機能を持ってい

ることがわかります。そこで、これらを今回のアプリケーションの UI に組み込みます。

ともあれ、この Web サービス インポート ダイアログを使用した結果に戻ります。

Page 54: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 53

この結果、ソリューション プロジェクトに [Web 参照] ディレクトリが追加されます。奇妙なことに、こ

のノードには、参照名 www.w3schools.com しか表示されておらず、生成されたソース ファイルを直接開

く手段がないように見えます。しかし、そのディレクトリから手動で開くことで Reference.pas というフ

ァイル内のコードを参照できます。生成されたプロキシ クラスがその中に記述されています。その名前空

間はプロジェクト名と [参照] 値の組み合わせになるので、プロジェクトをたとえば WebServices という名

前で保存し [参照] 値を変えずにそのままにしておくと、このプロキシ クラスが定義されている名前空間は

WebServices.www.w3schools.com になります。

同期か非同期か

Web サービス プロキシ クラスには、2 つの Web サービス メソッドをさまざまな方法で呼び出すための

多数のメソッドが含まれていますが、それらは単に同期呼び出しと非同期呼び出しに分類することができ

ます。同期呼び出しはこれぐらい簡単です。

method FahrenheitToCelsius(Fahrenheit: String): String;

method CelsiusToFahrenheit(Celsius: String): String;

わかりやすく、思わず使いたくなるほどですが、同期 Web サービス呼び出しが動作中にブロックされる

と UI が反応しなくなることを承知しておかなければなりません。Web サービス呼び出しが低速つまり時

間がかかる場合は、アプリケーションが反応しなくなり、ユーザーは快適に利用できなくなります。非同

期呼び出しを使用したほうがずっとよいでしょう。

提供されている非同期宣言には 2 つの異なるセットがあります。一方のセットは、通常の .NET 非同期プ

ログラミング モデルに従っています。

method BeginFahrenheitToCelsius(Fahrenheit: String; callback: AsyncCallback;

asyncState: Object): IAsyncResult;

method EndFahrenheitToCelsius(asyncResult: IAsyncResult): String;

method BeginCelsiusToFahrenheit(Celsius: String; callback: System.AsyncCallback;

asyncState: Object): IAsyncResult;

method EndCelsiusToFahrenheit(asyncResult: IAsyncResult): String;

非 同 期 Web サ ー ビ ス メ ソ ッ ド 呼 び 出 し を 起 動 す る に は 、 BeginFahrenheitToCelsius か

BeginCelsiusToFahrenheit のどちらかを呼び出すことができますが、その際には、テキスト入力値、Web

サービス メソッド終了時に呼び出されるコールバックへの参照、そのコールバックに渡される任意の状態

情報を引数に渡します。どちらのメソッドも IAsyncResult オブジェクトを返します。アプリケーションの

反応は、Web サービス メソッドの実行中もそのまま変わりません。実行が完了すると、IAsyncResult オブ

ジェクトを渡してコールバックが呼び出され、任意の状態情報は AsyncState プロパティから取得できるよ

うになります。このコールバックが呼び出されるのは、メインの UI スレッドではなく、Web サービス メ

ソッドが呼び出されたスレッドです。

Web サービス メソッドの呼び出し結果を取得するには、先に取得した IAsyncResult オブジェクトを引数

に渡して EndFahrenheitToCelsius か EndCelsiusToFahrenheit のどちらか適切な方を呼び出します。これ

は(補助スレッド上で)コールバックの内部で行われるのが一般的ですが、必要であればメイン スレッド

で行うこともできます。たとえば、BeginFahrenheitToCelsius を呼び出したあと、何らかの必要な操作を

Page 55: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 54

行うために通常の UI 処理を続けるといったこともできます。メイン メソッドで必要なことがすべて実行

されたとき、あるいは、Web サービス呼び出しの結果がなくても行えることがすべて実行されたときには、

EndFahrenheitToCelsius を呼び出すことができます。Web サービス呼び出しが終了していれば、結果をす

ぐに取得できます。まだ実行中であれば、結果が利用可能になるまで呼び出しはブロックされます。

Web サービス プロキシ クラスのもう一方のメソッド セットでは、イベント駆動型の非同期呼び出しを提

供しています。

event FahrenheitToCelsiusCompleted: FahrenheitToCelsiusCompletedEventHandler;

method FahrenheitToCelsiusAsync(Fahrenheit: String);

method FahrenheitToCelsiusAsync(Fahrenheit: String; userState: Object);

event CelsiusToFahrenheitCompleted: CelsiusToFahrenheitCompletedEventHandler;

method CelsiusToFahrenheitAsync(Celsius: String);

method CelsiusToFahrenheitAsync(Celsius: String; userState: Object);

ここで、各メソッドの呼び出しには 2 つの選択肢があることがわかります。つまり、任意の状態情報を伴

う か 伴 わ な い か で す 。 呼 び 出 し の 結 果 を 取 得 す る に は 、 FahrenheitToCelsiusCompleted か

CelsiusToFahrenheitCompleted のどちらか適切な方にイベント ハンドラを接続します。これらのイベン

トは通常の .NET イベント シグネチャで定義されています。イベント ハンドラは 2 つのパラメータを取り

ます。1 つ目はそのイベントをトリガしたオブジェクトで、2 つ目は EventArgs の下位クラス

(FahrenheitToCelsiusCompletedEventArgs か CelsiusToFahrenheitCompletedEventArgs のどちらか)で

す。これらはどちらも、Web サービス呼び出しの結果を Result プロパティで、任意の状態情報を

UserState プロパティで、それぞれ提供します。先ほどの非同期コールバックの場合と同様に、これらの

完了イベント ハンドラは、UI のメインスレッドではなく補助スレッドで呼び出されます。

補助スレッドから UI へのアクセス

非同期完了コールバックとイベント ハンドラが補助スレッドで実行されることを考えれば、そこから UI

コントロールには直接アクセスできないことに留意することが重要です。コントロールにアクセスするコ

ードは、コンパイルは成功しますが、ほとんど役に立ちません。

補助スレッドから UI にアクセスするには、InvokeOnMainThread を呼び出す必要があります。これは、UI

コードを記述した NSAction 互換デリゲート(無名メソッドかラムダでかまいません)を引数に取ります。

WEB サービスの利用

前置きはこれくらいにして、この Web サービス用の UI を作成し、その呼び出しの話に進みましょう。先

ほどのユーティリティ アプリケーションで、今のところメイン ビューはそのままにしておき、フリップ

サイド ビューにコントロールを追加します。

必要なものは、温度を入力するためのテキスト フィールド(Text Field コントロール)と、それを説明す

るラベル(Label コントロール)です。テキスト フィールドの [Text] 属性に 100 などのデフォルト温度値

を設定し、[Return Key] 属性を [Done] に設定します。また、おそらく [Keyboard] 属性を [Number Pad] に

Page 56: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 55

設定します。温度を数値で入力するだけだからです12。摂氏から華氏への変換か華氏から摂氏への変換か

を選択するため、Segmented Control コントロール(UISegmentedControl)を使用します。これは、一

体化した 2 つのボタン(一組のラジオ ボタンのようなもの)として使用できます。それぞれのセグメント

を順に編集できるので、2 つのセグメントの [Title] 属性をそれぞれ「℃ → ℉」と「℉ → ℃」に設定します。

これらの [Title] 属性の 3 つの文字はすべて、Unicode 文字セットの幅広いオプションから取得します。こ

れらの文字を Interface Builder で入力するには、[Title] 属性フィールドをクリックしたうえで、メニュー

から [編集|特殊文字...] を選択して(または、⌥⌘+T を押して)[文字] ウィンドウ13を開きます。このウィ

ンドウで、リストとドロップダウンを使ってさまざまな文字を調べて回ることができますが、何か特定の

文字を探している場合は、下部の検索ボックスが役に立ちます。以下のスクリーンショットは、これを使

用して、今扱っている 2 つの尺度での温度単位を表す 2 つの記号を探しているところです。同様に、

"arrow" を探すと、2 つのボタン セグメントのタイトルで使用している右矢印記号を含め、多数の矢印が

見つかります。

Interface Builder でビューに必要なものは、上記の他に、ふさわしい [Title] 属性の付いた変換開始用ボタ

ン(Button コントロール)と、結果を表示するためのラベル(Label コントロール)です。さらに、Web

サービスの実行には少し時間がかかることを考えて、 Activity Indicator View コントロール

(UIActivityIndicatorView)を追加し、その [Hide When Stopped] 属性と [Hidden] 属性のチェックを両方

ともオンにします。

12 [Number Pad] キーボードはまさにそれ、つまりテンキーです。つまり、このキーボードには – と . がないため、小

数の温度や負の温度を入力できないことになります。 13 テキスト編集が可能な多くのアプリケーションにはこのメニュー オプションが備わっていますが、筆者が気づいた

ところでは、Microsoft Word 2008 for Mac はその例外です(その代わり、[挿入|記号と特殊文字...] メニューでアクセ

スできる独自の文字選択ダイアログがあります)。

Page 57: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 56

コードを動作させるには、FlipsideViewController に 5 つのアウトレットを追加し、それらを以下のように

接続します。

追加するアウトレットは activityIndicator、conversionSelectionButton、convertButton、 resultLabel、

temperatureTextBox です。

プロキシ クラスの名前空間の名前(Web サービス参照をインポートする前にプロジェクトを

WebServices という名前で保存した場合は WebServices.www.w3schools.com)を忘れずに uses 句に追加

してください。それができたら、コードを追加できます。

ViewDidLoad メソッドでは、以下のように、結果を表示するラベルをクリアし、Web サービス プロキシ

クラスのインスタンスを生成し、変換ボタンがタッチされたときにそれに応答するイベント ハンドラをセ

ットアップします。

resultLabel.Text := '';

Converter := new TempConvert();

convertButton.TouchUpInside += ConvertButtonTouched;

Converter は、ビュー コントローラ クラスに宣言されている変数です。変換ボタンにユーザーがタッチし

たときは、以下のコードが実行されます。

method FlipsideViewController.ConvertButtonTouched(sender: Object;

e: EventArgs);

begin

resultLabel.Text := '';

var InputTemp: Double;

if Double.TryParse(temperatureTextBox.Text, out InputTemp) then

begin

Page 58: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 57

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := True;

activityIndicator.StartAnimating;

if conversionSelectionButton.SelectedSegment = 0 then

Converter.BeginCelsiusToFahrenheit(temperatureTextBox.Text,

@FinishedTemperatureConversion, True)

else

Converter.BeginFahrenheitToCelsius(temperatureTextBox.Text,

@FinishedTemperatureConversion, False);

end

else

resultLabel.Text := 'Invalid input temperature'

end;

テキスト フィールド内のテキスト(テンキーを指定したことを考えると、数字か空文字列のどちらか)が

数値であると仮定して、まず、ステータス バーのネットワーク アクティビティ インジケータを作動させ

ると共に、アクティビティ インジケータ コントロールのアニメーションを開始します。こうしてユーザ

ーには、アプリケーションが何かの処理でビジーになっており、ネットワークがアクセスされていること

がわかります。セグメント コントロール(Segmented Control)のチェックをオンにすると、変換を行う

方向が決まり、それにより、BeginCelsiusToFahrenheit と BeginFahrenheitToCelsius のどちらが呼び出さ

れるかが制御されます。この実装では、ただ 1 つのメソッドをコールバックとして使用していますが、ど

ちらの方向に変換が要求されたかを知る必要がある場合は、Boolean 値を任意の状態情報として渡し、摂

氏から華氏への変換かどうかを示すのに使用します。コールバックは次のようになります。

method FlipsideViewController.FinishedTemperatureConversion(

AsyncResult: IAsyncResult);

begin

var FromCelsius := Boolean(Asyncresult.AsyncState);

var Answer :=

iif(FromCelsius, Converter.EndCelsiusToFahrenheit(AsyncResult),

Converter.EndFahrenheitToCelsius(AsyncResult));

// Since we are running on a separate thread, we can not access UIKit

// objects from here, so we need to invoke those on the main thread:

InvokeOnMainThread(() ->

begin

resultLabel.Text := String.Format(

iif(FromCelsius, '{0}℃ is {1:F2}℉', '{0}℉ is {1:F2}℃'),

temperatureTextBox.Text, Convert.ToDouble(Answer));

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := False;

activityIndicator.StopAnimating;

end);

end;

任意の状態情報は取り出されて Boolean 型に復元されます。これを基に、受け取った IAsyncResult オブジ

ェ ク ト を 引 数 に 渡 し て 温 度 変 換 の 結 果 を 取 り 出 す の に 、 EndCelsiusToFahrenheit と

Page 59: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 58

EndFahrenheitToCelsius のどちらを呼び出すかを決定します。結果を書き出しアクティビティ インジケー

タを停止させるために、次の短いコードを InvokeOnMainThread を通じて間接的に実行します。(前述の

ように)今は UI スレッドで動作していないからです。

これで、キーボードを除けばかなりうまくいきます。キーボードは、ユーザーが温度を入力し終わっても

消えるようになっていません。この問題に対処するには、他の任意のコントロールが使用されたときにト

リガされるイベント ハンドラを接続し、それらの中でキーボードを消すように実装します。以下の 2 つの

ステートメントを ViewDidLoad に追加できます。これで変換ボタンの TouchUpInside イベント ハンドラ

は 2 つになったことに注意してください。

convertButton.TouchUpInside += AnyNonTextControlTouched;

conversionSelectionButton.ValueChanged += AnyNonTextControlTouched;

以下のように、ハンドラそのものは単純で、前の例で登場したものと同様です。

method FlipsideViewController.AnyNonTextControlTouched(Sender: Object;

E: EventArgs);

begin

temperatureTextBox.ResignFirstResponder

end;

これで、機能する Web サービス アプリケーションができあがりました。その機能は、何も表示されてい

ないメイン画面の裏面(フリップサイド)に搭載されています。それに目を向ける前に、今使用したばか

りの Begin/End タイプの非同期メソッドとは異なり、イベント ベースの非同期 Web サービス メソッドを

使用した場合はコードの見た目がどうなるかを調べてみたいと思います。ViewDidLoad メソッドで、Web

サービス プロキシを作成した直後に以下のステートメントを追加する必要があります。

Converter.CelsiusToFahrenheitCompleted += FinishedCelsiusToFahrenheit;

Converter.FahrenheitToCelsiusCompleted += FinishedFahrenheitToCelsius;

EventArgs の下位クラス型の異なるパラメータを取るので、これで 2 つの別個のイベント ハンドラになっ

たことに注意してください。ボタンのイベント ハンドラは以下のように変わります。

method FlipsideViewController.ConvertButtonTouched(sender: Object;

e: EventArgs);

begin

resultLabel.Text := '';

var InputTemp: Double;

if Double.TryParse(temperatureTextBox.Text, out InputTemp) then

begin

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := True;

activityIndicator.StartAnimating;

if conversionSelectionButton.SelectedSegment = 0 then

Converter.CelsiusToFahrenheitAsync(temperatureTextBox.Text)

Page 60: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 59

else

Converter.FahrenheitToCelsiusAsync(temperatureTextBox.Text);

end

else

resultLabel.Text := 'Invalid input temperature'

end;

2 つの別個の Web サービス メソッド完了イベント ハンドラがあるので、任意の状態情報パラメータを渡

す必要がないことに注意してください。以下がそれらのイベント ハンドラです。

method FlipsideViewController.FinishedCelsiusToFahrenheit(sender: Object;

args: CelsiusToFahrenheitCompletedEventArgs);

begin

InvokeOnMainThread(() ->

begin

resultLabel.Text := String.Format('{0}℃ is {1:F2}℉',

temperatureTextBox.Text, Convert.ToDouble(args.Result));

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := False;

activityIndicator.StopAnimating;

end);

end;

method FlipsideViewController.FinishedFahrenheitToCelsius(sender: Object;

args: FahrenheitToCelsiusCompletedEventArgs);

begin

InvokeOnMainThread(() ->

begin

resultLabel.Text := String.Format('{0}℉ is {1:F2}℃',

temperatureTextBox.Text, Convert.ToDouble(args.Result));

UIApplication.SharedApplication.NetworkActivityIndicatorVisible := False;

activityIndicator.StopAnimating;

end);

end;

画像

ユーティリティ プロジェクトのメイン ビューには、好きなものを配置できます。今回は、画像を追加し

ます。Interface Builder を使用すれば、メイン ビューに適切なコントロールを追加し、その属性を設定で

きますが、今回は Interface Builder を使用せずに、コードだけで作業します。

iOS プロジェクトに画像を追加するには、そのファイルをソース ディレクトリ ツリーにコピーします。今

回使用するのは Fire.jpg というファイルで(iPhone 画面のサイズよりも小さい)、ソース ファイルと一

緒にプロジェクトのメイン ディレクトリに既に格納されています。MonoDevelop で、まず画像をプロジ

ェクトに追加し(プロジェクトを右クリックし [追加|ファイルを追加] を選択するか、⌥⌘+A を押す)、

Page 61: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 60

次にプロジェクト内の該当画像を右クリックし [ビルド アクション|コンテンツ] を選択することで、画像

の存在をプロジェクトに知らせます。

これで、メイン ビュー コントローラの ViewDidLoad に以下のコードを記述できます。

method MainViewController.ViewDidLoad;

begin

inherited ViewDidLoad();

//Deal with image

var image := new UIImage("Fire.jpg");

var imageView := new UIImageView(image);

with appF := UIScreen.MainScreen.ApplicationFrame, imgS := image.Size do

imageView.Frame := new RectangleF((appF.Width - imgS.Width) div 2,

(appF.Height - imgS.Height) div 2, imgS.Width, imgS.Height);

(inherited View).AddSubview(imageView);

end;

上記コードでは、画像ファイルを画像コントロール(UIImage)に読み込み、それを画像ビュー

(UIImageView)に追加し、画像ビューのフレームをアプリケーション フレームの中央に配置し、 後に

画像ビューをメイン ビューに追加しています。これで、アプリケーションのメイン ビューは以下のスク

リーンショットのようになります。何かもう少し情報量の多い役に立つものの方が現実のアプリケーショ

ンではよいでしょうが、画像を選んだのには、ちょっとした理由があります。これは温度変換プログラム

であり、火は高温を暗示しています。

Page 62: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 61

ドラッグ可能なコントロール

遊び心をくすぐられたのなら、この画像をドラッグ可能にしてはどうでしょうか。UIImageView を継承し

ドラッグ操作に対応している新しいクラス UIDraggableImageView を作成しましょう。このクラスは実際

にはずいぶん簡単で、ユーザーが指をドラッグするのに合わせて画像ビューのフレームを移動するように

メソッド TouchesBegan、TouchesMoved、TouchesEnded をオーバーライドすることで動作します。前

のプロジェクトでは、これらのメソッドを使用してタッチ移動を追跡したことを覚えているでしょうか。

このクラスの定義は次のようになります。

type

UIDraggableImageView = public class(UIImageView)

private

StartLocation: PointF;

method MoveImage(touches: NSSet);

public

constructor(image: UIImage);

method TouchesBegan(touches: NSSet; evt: UIEvent); override;

method TouchesMoved(touches: NSSet; evt: UIEvent); override;

method TouchesEnded(touches: NSSet; evt: UIEvent); override;

end;

コンストラクタと各メソッドは以下のように実装されます。

constructor UIDraggableImageView(image: UIImage);

begin

inherited;

UserInteractionEnabled := True;

end;

method UIDraggableImageView.MoveImage(touches: NSSet);

begin

// Move relative to the original touch point

var pt := (touches.AnyObject as UITouch).LocationInView(Self);

// Use a separate frame var to ensure both new coordinates are set at once

var frame := Self.Frame;

with appFrame := UIScreen.MainScreen.ApplicationFrame do

begin

frame.X := frame.X + pt.X - StartLocation.X;

if frame.X < 0 then frame.X := 0;

if frame.X + Image.Size.Width > appFrame.Width then

frame.X := appFrame.Width - Image.Size.Width;

frame.Y := frame.Y + pt.Y - StartLocation.Y;

if frame.Y < 0 then frame.Y := 0;

if frame.Y + Image.Size.Height > appFrame.Height then

Page 63: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 62

frame.Y := appFrame.Height - Image.Size.Height;

end;

Self.Frame := frame;

end;

method UIDraggableImageView.TouchesBegan(touches: NSSet; evt: UIEvent);

begin

var pt := (touches.AnyObject as UITouch).LocationInView(Self);

StartLocation := pt;

Superview.BringSubviewToFront(Self);

end;

method UIDraggableImageView.TouchesMoved(touches: NSSet; evt: UIEvent);

begin

MoveImage(touches)

end;

method UIDraggableImageView.TouchesEnded(touches: NSSet; evt: UIEvent);

begin

MoveImage(touches)

end;

画像はシングル タッチ向きなので、TouchesBegan では、渡されたセットから任意のタッチ オブジェクト

を取得するだけです。通常はどのみち、1 つしか含まれていません。そのタッチの位置が開始点として記

録されます。ユーザーの指が動き回るのに合わせて、MoveImage ヘルパ ルーチンでは、フレームの x 座

標と y 座標を増減させつつ、フレームが画面の境界からはみ出さないようにする処理を行います。

このクラスは、http://monotouchexamples.com で公開されているコード断片を基にしたものです。

起動画面

上記の例には画像が含まれていますが、それはビューの 1 つに組み込まれています。商用アプリケーショ

ンに共通する特徴の 1 つは起動画面(またはスプラッシュ画面)で、アプリケーションの起動と初期化に

時間がかかる場合にユーザーの気を紛らす役目を果たします。Apple の UI ガイドラインでは、実行中のア

プリケーションの画像をスプラッシュ画面にすることを提唱していますが、これはよく無視されます。ア

プリケーションには通常、企業のマーケティング情報やアプリケーションと企業のロゴなどが組み込まれ

ています。しかし、スプラッシュ画面を組み込むにはどうすればよいのでしょうか。さらに、アプリケー

ションが現在よりもう少し目立つようにアイコンを組み込むにはどうすればよいでしょうか。

Page 64: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 63

これらの質問への答えは、特別な名前のさまざまなファイルをプロジェクトに追加し、それらに対して

[ビルド アクション|コンテンツ] コマンドを実行することです。まず、起動画面を見てみましょう。

起動画面を組み込むには、Default.png というファイルをプロジェクトに追加し、サイズを 320x460 にす

るだけです(iPhone の解像度は 320x480 で、この画像サイズは高さ 20 ピクセルのステータス バーを考慮

に入れたものです)。この画像は iPhone 3 と iPod touch に有効です。iPhone 4 でも有効ですが、iPhone

4 のピクセル解像度は 2 倍になったことを思い出してください。改良された表示により適切に対応する

(および元の画像が表示領域に合わせて拡大されないようにする)ために、[email protected] という

640x920 の解像度のファイルも組み込むことができます。これは、アプリケーションが iPhone 4 で起動さ

れたときに自動的に使用されます。

これまで取り組んできたこのユーティリティ プロジェクトは、このテクニカル ノートに添付されている

ファイルに収録されています。上記の仕様により、プロジェクトには 2 つの起動画像があります。これら

は同じ画像(氷の写真:低温を表す)ですが、Default.png の方はより小さい解像度に縮小されています。

ここで述べたことを実証するためと必ず正しいファイルが使用されるようにするために、小さい方のファ

イルには数字 3 が、大きい方のファイルには数字 4 が、それぞれ大きく描画されています。以下のスクリ

ーンショットでは、この同じアプリケーションが iPhone 4 シミュレータで起動されているところを示して

います。

シミュレータでは、メイン メニューから [ハードウェア|デバイス] を選択したあと [iPhone](iPhone 3 お

よび iPod touch シミュレータ用)、[iPhone (Retina)](iPhone 4 シミュレータ用)、[iPad] のいずれかを選

択することで、さまざまなハードウェアのシミュレーションを切り替えることができます。

Page 65: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 64

IPAD のサポート

iPad シミュレータで今回のどのアプリケーションを実行しても、あまりうまく合っていないように見えま

す。今回、ウィンドウとビューはすべて 320x480 の解像度に合うようにハードコードされているからです。

アプリケーションを iPad で動作させる場合は、iPad およびそこで提供されるさまざまな機能(特に

1024x768 の画面解像度)に合うように設計しなければなりません。

初から [iPad Window-based Project] テンプレートを使用している場合は、UI のサイズは状況に応じて

適切に変わります。[Universal Window-based Project] テンプレートでは、2 つの NIB ファイル(iPhone の

解像度用と iPad の解像度用に 1 つずつ)を設けることで、どちらの選択肢もカバーしています。どちらに

せよ、iPad がサポートされています。

iPad がアプリケーションで対応しなければならないターゲットである場合は、使用可能なさまざまなプロ

ジェクト オプションも検討しなければなりません([ソリューション] ウィンドウでプロジェクトを右クリ

ックし [オプション] を選択します)。特に、[iPhone Build] ページと [iPhone Application] ページのオプシ

ョンが重要です。

紙面の都合でここでは iPad プログラミングの詳細に立ち入ることができませんが、これまで見てきた手法

はすべて iPad アプリケーションのプログラミングにも完全に適用できると言って間違いありません。ただ

し、起動画面に関しては、iPad アプリケーションを起動できるさまざまな向きに対応するのに必要なさま

ざまなファイルがあります。詳細については、http://phunkwerk.posterous.com/ipad-managing-multiple-

launch-images-aka-defa の投稿を参照してください。

アイコン

iOS でアイコンが使用される場所は 3 箇所あります。つまり、ホーム画面、設定画面、スポットライト

(検索)画面です。これらの場所のそれぞれに、異なる大きさのアイコンが必要になる場合があります。

ターゲットにしているデバイスによっては、さらに各画像の寸法の追加を検討しなければならない場合が

Page 66: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 65

あります。iPhone 3 および iPod touch、iPhone 4、iPad では使用する解像度セットが別々になっているか

らです。

iPhone 3 および iPod touch をターゲットにしている簡単な場合には、これらのアイコンの画像ファイルを

2 つ組み込むことになるでしょう。Icon.png(解像度 57x57)はホーム画面で使用され、Icon-Small.png

(解像度 29x29)は設定画面のほか、スポットライト画面でも使用されます。

あらゆる iOS デバイスを対象にした汎用アプリケーションを作成するのであれば、以下のすべてのアイコ

ン ファイルを組み込む必要があるでしょう。

ファイル名 画像の大きさ 用途

Icon.png 57x57 iPhone/iPod touch のホーム画面

[email protected] 114x114 iPhone 4 のホーム画面

Icon-72.png 72x72 iPad のホーム画面

Icon-Small.png 29x29 iPhone/iPod touch のスポットライト画面と設定画面、

iPad の設定画面

[email protected] 58x58 iPhone 4 のスポットライト画面と設定画面

Icon-Small-50.png 50x50 iPad のスポットライト画面

起動画面の画像とは異なり、これらのアイコンは iOS で自動的には使用されません。代わりに、ルート フ

ァイル名をプロジェクトの Info.plist ファイル内のエントリに指定する必要があります。これは XML 形式

の情報プロパティ リスト ファイルで、iOS で処理してアプリケーションに必要なものを正しくセットアッ

プするためのものです。Info.plist をダブルクリックすると、プロパティ リスト エディタが開きます。デ

フォルトでは、このファイルにはほとんど何も記述されていません。[Add Child] ボタン(あるいは、選択

されているものによっては [Add Item] ボタン)を使って、新しいエントリを追加する必要があります。新

しいエントリ(キー)は [Icon file](これはドロップダウン リストから選択できます)でなければならず、

値は以下に示すようなルート アイコン ファイル名でなければなりません。

Page 67: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 66

Web サービスを利用したサンプルには、iPhone と iPhone 4 のアイコンが含まれているほか、プロジェク

ト オプションの 1 つを通じてホーム画面の表示名がカスタマイズされています。[プロジェクト オプショ

ン] ダイアログの [iPhone Application] ページでは、[Application Bundle] セクションの [Display name] 値に

より、ホーム画面のアイコンの下に表示されるテキストを制御できます。

メモ: Delphi Prism XE のリリース版では、MonoDevelop で実行したとき、たまにバグが発生します。オ

プションを調べて回ると、以下のような予期しないエラーでそれ以降のコンパイルが失敗することがとき

どきあります。

Error CE19: Cannot open file "/Users/brian/Projects/Prism/MyProject" (CE19) (MyProject)

(ファイル "/Users/brian/Projects/Prism/MyProject" を開けません (CE19) (MyProject))

これは通常、[Win32 アイコン] オプション([プロジェクト オプション] ダイアログの [ビルド|一般] セク

ションにあります)が、ときどきどういうわけかプロジェクト ディレクトリの値に設定されてしまうとい

う問題があり、それが原因になっています。残念ながら、MonoDevelop 内からはこれを修正できそうに

ありません。代わりに、MonoDevelop を終了し、プロジェクト ファイル(拡張子は .oxygene なので、

たとえば Myproject.oxygene などとなります)をテキスト エディタで開きます。(プロジェクト ディレ

クトリで)以下のような行を探します。

<ApplicationIcon>/Users/brian/Projects/Prism/Pages</ApplicationIcon>

Page 68: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 67

その行全体を単に削除します。

デバッグ

MonoDevelop から iOS シミュレータで MonoTouch アプリケーションを実行する際には、MonoDevelop

IDE の非常に高性能なデバッガを利用できます。これには、ブレークポイント、呼び出しへのステップイ

ン、呼び出しのステップオーバー、監視式、ローカル変数、コール スタック、スレッド情報といった通常

のデバッグ機能が用意されています。あと必要なのは、ウィンドウとコントロールがどこにあり、どのよ

うなショートカットが使用可能であるかに慣れる時間だけです。

ただし、注意すべき重要なことの 1 つに、デバッグ機能の実装方法に起因して、アプリケーションのデバ

ッグ時には、占有メモリがリリース版よりもはるかに増え、実行速度がはるかに遅くなるという点があり

ます。

さらに、アプリケーションのスタートアップ処理時に実行されるコードをデバッグしようとする際には注

意が必要です。たとえば、メイン ビュー コントローラの ViewDidLoad メソッドや App Delegate の

FinishedLaunching メソッドなどです。iOS はアプリケーションの起動時にアプリケーションを監視し、ア

プリケーションがスタートアップを問題なく完了し、ユーザーからタイムリーに使用できるようになった

かどうかを確かめます。アプリケーションがスタートアップ処理に 10 ~ 20 秒以上かかる場合、iOS はア

プリケーションがハングアップしたものと見なして強制終了します。そのため、これらのスタートアップ

メソッドの 1 つにブレークポイントを設定した場合、アプリケーションが目の前で削除されるまで、何か

をデバッグする時間はほとんどありません。

メイン ビューのスタートアップ メソッドのコードをデバッグするには、一時的なメイン ビューのボタン

から二次的なビューとして起動させることを考えてみてください。あるいは、バグを突き止めるために、

[アプリケーション出力] ウィンドウにログ情報を記録するという非常によくある方法を使用します。

Console.WriteLine を呼び出すと MonoDevelop の [アプリケーション出力] ウィンドウに一覧表示され、こ

れは非常に便利な追跡メカニズムとなります。

技術リソース

Delphi Prism は、標準の Delphi 言語をさまざまな方法で拡張しています。Delphi Prism 言語の詳細につい

ては、以下のページをご覧下さい。

英語:

http://prismwiki.embarcadero.com/en/Language

http://prismwiki.embarcadero.com/en/The_Prism_Primer

http://prismwiki.embarcadero.com/en/Anonymous_Methods_and_Delegates

日本語:

http://prismwiki.codegear.com/ja/%E8%A8%80%E8%AA%9E

http://prismwiki.codegear.com/ja/Prism_%E5%85%A5%E9%96%80

http://prismwiki.codegear.com/ja/%E7%84%A1%E5%90%8D%E3%83%A1%E3%82%BD%E3%83%83%E3

%83%89%E3%81%A8%E7%84%A1%E5%90%8D%E3%83%87%E3%83%AA%E3%82%B2%E3%83%BC%E3%

83%88

Page 69: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

Delphi Prism XE による iPhone、iPod touch、iPad 向け開発

Embarcadero Technologies 68

MonoTouch API リファレンス(英語)は、http://www.go-mono.com/docs でご覧いただけます。C#ベー

スのチュートリアルは、http://monotouch.net/Tutorials にあります。ハウツーのドキュメントは、

http://wiki.monotouch.net/HowTo および http://monotouch.info. に掲載されたいくつかの記事をご覧下さ

い。

iOS リファレンスライブラリは、http://developer.apple.com/library/ios にあります。

推奨する書籍は、「Professional iPhone Programming with MonoTouch and .NET/C#(Wallace B. McClure,

Rory Blyth, Craig Dunn, Chris Hardy, Martin Bowling 共著)」(http://www.amazon.com/dp/047063782X) で

す。

SQLite の SQL 構文については、http://www.sqlite.org/lang.html をご覧下さい。

まとめ

このテクニカル ノートでは、Delphi Prism を利用して .NET のプログラミング知識を活かしながら iPhone、

iPod touch、iPad 向けのアプリケーションを非常にスマートに作成していく方法を示しました。

MonoTouch SDK は、まったく新しいプログラミング言語を習得しなくても iPhone アプリケーションを作

成していける便利な手段となります。もちろん、作業をうまくこなすには CocoaTouch(あるいは少なく

とも CocoaTouch.Net)への理解を深めることが必要ですが、使い慣れた言語で作業すれば、新しい UI フ

レームワークへの移行を楽に行えるようにする上で役に立ちます。

目的にかなった形で分割されれば、iOS で動作するアプリケーションでビジネス ロジックを再利用できる

可能性はありますが、この種のアプリケーションには、まったく異なる UI を開発する必要があることは明

らかです。

著者について

Brian Long は、この 15 年間、Delphi、C#、C++ の言語と、Win32、.NET、Mono のプラットフォームを

中心に、トレーニングやトラブルシューティングやメンタリングを行ってきており、近年、そのリストに

iOS と Android が加わりました。余暇には、Chiltern Hills をマウンテンバイク散策したり、Unix オペレー

ティング システムの特異性や問題点を再発見したり改めて楽しんだりしています。90 年代半ばに Pascal

の問題解決についての書籍を書いた以外にも、さまざまな書籍の一部の章を執筆したり、数え切れないほ

どの雑誌記事を書いたり、ときどきは Sybex の技術編集も行っています。Brian はオンライン記事もいく

つも書いていて、http://blong.com で読むことができます。

Page 70: iPhone iPod touch iPad - Embarcadero Website · 2012-03-05 · Delphi Prism XE によるiPhone、iPod touch、iPad 向け開発 Embarcadero Technologies 1 概要 iPhone® がスマートフォン市場において成功を収め、開発者にiPhone

エンバカデロ・テクノロジーズについて

エンバカデロ・テクノロジーズは、1993 年にデータベースツールベンダーとして設立され、2008 年にボーラン

ドの開発ツール部門「CodeGear」との合併によって、アプリケーション開発者とデータベース技術者が多様な

環境でソフトウェアアプリケーションを設計、構築、実行するためのツールを提供する 大規模の独立系ツール

ベンダーとなりました。米国企業の総収入ランキング「フォーチュン 100」のうち 90 以上の企業と、世界で

300 万以上のコミュニティが、エンバカデロの Delphi®、C++Builder®、JBuilder®といった CodeGear™製品や

ER/Studio®、DBArtisan®、RapidSQL®をはじめとする DatabaseGear™製品を採用し、生産性の向上と革新的な

ソフトウェア開発を実現しています。エンバカデロ・テクノロジーズは、サンフランシスコに本社を置き、世界

各国に支社を展開しています。詳細は、www.embarcadero.com/jp をご覧ください。

Embarcadero、Embarcadero Technologies ロゴならびにすべてのエンバカデロ・テクノロジーズ製品またはサービス名は、Embarcadero

Technologies, Inc.の商標または登録商標です。その他の商標はその所有者に帰属します。