Hello, iOS – 深い分析

クイックスタート チュートリアルでは、基本的な Xamarin.iOS アプリケーションのビルドと実行について説明しました。 次は、より複雑なプログラムをビルドできるように、iOS アプリケーションの仕組みの理解を深めます。 このガイドでは、iOS アプリケーション開発の基本的な概念についての理解できるように、Hello, iOS チュートリアルの手順について説明します。

このガイドでは、1 つの画面の iOS アプリケーションの構築に必要なスキルと知識を開発できます。 作業した後、Xamarin.iOS アプリケーションのさまざまな部分とそれらをまとめる方法を理解できます。

Visual Studio for Mac の概要

Visual Studio for Mac は、Visual Studio と Xcode から機能を結合した無料のオープンソース IDE です。 ビジュアル デザイナー、リファクタリング ツール付きのテキスト エディター、アセンブリ ブラウザー、ソース コード統合などの機能が完全に統合されています。 このガイドでは、Visual Studio for Mac の基本的な機能についていくつか説明しますが、Visual Studio for Mac を初めてご利用になる方は、Visual Studio for Mac に関するドキュメントをご覧ください。

Visual Studio for Mac は、コードをソリューションプロジェクトに分けて整理するという Visual Studio の方法に従っています。 ソリューションとは、1 つまたは複数のプロジェクトを保持できるコンテナーです。 プロジェクトは、アプリケーション (iOS、Android など)、サポートするライブラリ、テスト アプリケーションなどの場合があります。 Phoneword アプリで、単一ビュー アプリケーション テンプレートが使用され、新しい iPhone プロジェクトが追加されています。 最初のソリューションは次のようになります。

A screenshot of the initial solution

Visual Studio の概要

Visual Studio は Microsoft 製の強力な IDE です。 ビジュアル デザイナー、リファクタリング ツール付きのテキスト エディター、アセンブリ ブラウザー、ソース コード統合などの機能が完全に統合されています。 このガイドでは、Visual Studio 用の Xamarin ツールを使用した Visual Studio のいくつかの基本的な機能について説明します。

Visual Studio は、コードをソリューションとプロジェクトに分けて整理しています。 ソリューションとは、1 つまたは複数のプロジェクトを保持できるコンテナーです。 プロジェクトは、アプリケーション (iOS、Android など)、サポートするライブラリ、テスト アプリケーションなどの場合があります。 Phoneword アプリで、単一ビュー アプリケーション テンプレートが使用され、新しい iPhone プロジェクトが追加されています。 最初のソリューションは次のようになります。

A screenshot of the initial solution

Xamarin.iOS アプリケーションの構造

左側は、ディレクトリ構造とソリューションに関連付けられているすべてのファイルを含む Solution Pad です。

The solution Pad, which contains the directory structure and all the files associated with the solution

右側は、ディレクトリ構造とソリューションに関連付けられているすべてのファイルを含むソリューション ウィンドウです。

The solution Pane, which contains the directory structure and all the files associated with the solution

Hello, iOS」チュートリアルでは、Phoneword というソリューションを作成し、iOS プロジェクト (Phoneword_iOS) をその中に配置しました。 プロジェクト内には次の項目があります。

  • References アプリケーションのビルドと実行に必要なアセンブリが含まれています。 ディレクトリを展開すると、System、System.Core、System.Xml などの .NET アセンブリへの参照、および Xamarin.iOS アセンブリへの参照が表示されます。
  • Packages - Packages ディレクトリには、あらかじめ用意されている NuGet パッケージが含まれています。
  • Resources - Resources フォルダーには、その他のメディアを格納します。
  • Main.cs – このファイルには、アプリケーションのメイン エントリ ポイントが含まれています。 アプリケーションを起動するには、メイン アプリケーション クラスの名前 AppDelegate が渡されます。
  • AppDelegate.cs – このファイルは、メイン アプリケーション クラスを含み、ウィンドウの作成、ユーザーインターフェイスの構築、オペレーティング システムからのイベントのリッスンを行います。
  • Main.storyboard - ストーリーボードは、アプリケーションのユーザー インターフェイスの視覚的なデザインを含みます。 ストーリーボード ファイルは、iOS Designer と呼ばれるグラフィカル エディターで開きます。
  • ViewController.cs - ビュー コントローラーは、ユーザーに表示されタッチする画面 (ビュー) を稼働させます。 ビュー コントローラーは、ユーザーとビュー間の対話を処理します。
  • ViewController.designer.cs - designer.cs は、ビュー内のコントロールとビュー コントローラーでのそれらのコード表現を結び付ける自動生成されたファイルです。 これは、内部の組み込みのファイルであるため、IDE は手動による変更を上書きします。多くの場合、このファイルは無視できます。
  • Info.plist - Info.plist では、アプリケーション名、アイコン、起動イメージなどのアプリケーションのプロパティが設定されます。 これは、強力なファイルで、完全な概要については、「Working with Property Lists」(プロパティ リストの操作) ガイドを参照してください。
  • Entitlements.plist - 権利のプロパティ リストを使用して、iCloud、PassKit などのアプリケーションの機能 (App Store テクノロジとも呼ばれます) を指定することができます。 Entitlements.plistの詳細については、「Working with Property Lists」(プロパティ リストの操作) ガイドを参照してください。 権利の一般的な概要については、「Device Provisioning」(デバイスのプロビジョニング) ガイドを参照してください。

アーキテクチャとアプリケーションの基礎

iOS アプリケーションにユーザー インターフェイスを読み込む前に、次の 2 つを実行する必要があります。 最初に、アプリケーションでエントリ ポイントを定義する必要があります。エントリ ポイントは、アプリケーションのプロセスがメモリに読み込まれるときに実行される最初のコードです。 次に、アプリケーション全体のイベントを処理し、オペレーティング システムと対話するクラスを定義する必要があります。

このセクションでは、次の図に示す関係について学習します。

The Architecture and App Fundamentals relationships are illustrated in this diagram

Main メソッド

iOS アプリケーションのメイン エントリ ポイントは、Application クラスです。 Application クラスは Main.cs ファイルに定義されており、静的な Main メソッドを含んでいます。 これは、新しい Xamarin.iOS アプリケーション インスタンスを作成し、OS イベントを処理する Application Delegate クラスの名前を渡します。 静的 Main メソッドのテンプレート コードは以下のように表示されます。

using System;
using UIKit;

namespace Phoneword_iOS
{
    public class Application
    {
        static void Main (string[] args)
        {
            UIApplication.Main (args, null, "AppDelegate");
        }
    }
}

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

iOS では、Application Delegate クラスがシステム イベントを処理します。このクラスは AppDelegate.cs 内にあります。 AppDelegate クラスは、アプリケーションのウィンドウを管理します。 ウィンドウはユーザー インターフェイスのコンテナーとして機能する UIWindow クラスの 1 つのインスタンスです。 既定では、アプリケーションがそのコンテンツを読み込む先の 1 つのウィンドウのみを取得し、ウィンドウは画面 (単一 UIScreen インスタンス) に接続されます。画面は物理デバイス画面のサイズに一致する境界の四角形を提供します。

AppDelegate は、アプリの起動が終了したときや、メモリが少ないときなどの重要なアプリケーション イベントに関するシステム更新情報のサブスクライブも行います。

AppDelegate テンプレートのコードは次のとおりです。

using System;
using Foundation;
using UIKit;

namespace Phoneword_iOS
{

    [Register ("AppDelegate")]
    public partial class AppDelegate : UIApplicationDelegate
    {
        public override UIWindow Window {
            get;
            set;
        }

        ...
    }
}

アプリケーションがウィンドウを定義したら、ユーザー インターフェイスの読み込みを開始できます。 次のセクションでは、UI の作成について説明します。

ユーザー インターフェイス

iOS アプリのユーザー インターフェイスは店舗の正面のようなものです。アプリケーションは、通常、1 つのウィンドウを取得しますが、必要な数のオブジェクトをウィンドウいっぱいに表示し、表示するアプリの必要に応じてオブジェクトの配置を変更することもできます。 このシナリオのオブジェクト (ユーザーに表示される物事) はビューと呼ばれます。 アプリケーションで 1 つの画面をビルドするには、コンテンツ ビュー階層にビューが相互に積み重ねられ、階層が単一のビュー コントローラーによって管理されます。 複数の画面があるアプリケーションには、複数のコンテンツ ビュー階層、それぞれに独自のビュー コントローラー、およびウィンドウ内のアプリケーションの場所のビューがあり、ユーザーに表示される画面に基づいて異なるコンテンツ ビュー階層が作成されます。

ストーリーボードを使用してユーザー インターフェイスを構築する方法の詳細については、Apple の iOS 開発者ライブラリ内にある「Xcode Overview」(Xcode の概要) の「Designing with Storyboards」(ストーリーボードを使用した設計) を参照してください。

次の図は、デバイスの画面にユーザー インターフェイスを表示するウィンドウ、ビュー、サブビュー、およびビュー コントローラー間の関係を示しています。

The relationships between the Window, Views, Subviews, and view controller

次のセクションでは、コードでビューを操作する方法について説明し、ビュー コントローラーとビュー ライフサイクルを使用してユーザーの操作をプログラムする方法を説明します。

ビュー コントローラーとビュー ライフサイクル

すべてのコンテンツ ビュー階層には、ユーザー操作を反映するビュー コントローラーがあります。 ビュー コントローラーの役割は、コンテンツ ビュー階層のビューを管理することです。 ビュー コントローラーは、コンテンツ ビュー階層の一部ではなく、インターフェイスの要素ではありません。 代わりに、画面上のオブジェクトでのユーザーの操作を実行するコードを提供します。

ビュー コントローラーとストーリーボード

ビュー コントローラーは、ストーリーボードで、シーンの下部にあるバーとして表されます。 ビュー コントローラーを選択すると、プロパティ パッド にそのプロパティが表示されます。

Selecting the view controller brings up its properties in the Properties Pane

このシーンによって表されるコンテンツ ビュー階層のカスタム ビュー コントローラー クラスは、プロパティ パッド[ID] セクションで [クラス] プロパティを編集することによって設定できます。 たとえば、私たちの Phoneword アプリケーションでは、下のスクリーンショットに示すように、最初の画面のビュー コントローラーとして ViewController が設定されます。

The Phoneword application sets the ViewController as the view controller

ビュー コントローラーは、ストーリーボードで、シーンの下部にあるバーとして表されます。 ビュー コントローラーを選択すると、プロパティ ウィンドウにそのプロパティが表示されます。

Selecting the view controller brings up its properties in the Properties Pane

このシーンによって表されるコンテンツ ビュー階層のカスタム ビュー コントローラー クラスは、プロパティ ウィンドウ[ID] セクションで [クラス] プロパティを編集することによって設定できます。 たとえば、私たちの Phoneword アプリケーションでは、下のスクリーンショットに示すように、最初の画面のビュー コントローラーとして ViewController が設定されます。

The Phoneword application sets the ViewController as the view controller

これにより、ビュー コントローラーのストーリーボード表現が ViewController C# クラスにリンクされます。 ViewController.cs ファイルを開くと、下のコードで示すように、ビュー コントローラーが UIViewControllerサブクラスになっていることがわかります。

public partial class ViewController : UIViewController
{
    public ViewController (IntPtr handle) : base (handle)
    {

    }
}

これで ViewController は、ストーリーボードでこのビュー コントローラーに関連付けられているコンテンツ ビュー階層のやり取りを実行します。 次に、ビュー ライフサイクルと呼ばれるプロセスを紹介することで、ビューの管理でのビュー コントローラーの役割について説明します。

Note

ユーザーの介入を必要としない表示専用の画面の場合は、プロパティ パッド[Class] プロパティを空白のままにすることができます。 これにより、UIViewController の既定の実装としてビュー コントローラーのバッキング クラスを設定します。これは、カスタム コードを追加する予定がない場合に適しています。

ビュー ライフサイクル

ビュー コントローラーはウィンドウからのコンテンツ ビュー階層の読み込みとアンロードを担当します。 コンテンツ ビュー階層のビューで何か重要なことが発生した場合、オペレーティング システムは、ビュー ライフサイクルのイベントを介してビュー コントローラーに通知します。 ビュー ライフサイクルでメソッドをオーバーライドすることで、画面上のオブジェクトと対話でき、応答性の高い、動的なユーザー インターフェイスを作成することができます。

次に、基本的なライフサイクル メソッドとその機能について説明します。

  • ViewDidLoad - ビュー コントローラーがコンテンツビュー階層をメモリに読み込むときに 1 回呼び出されます。 このときにサブビューが初めてコード内で利用可能になるので、これは初期セットアップを実行するために最適なタイミングです。
  • ViewWillAppear - ビュー コントローラーのビューがコンテンツ ビュー階層に追加されて画面に表示されるたびに呼び出されます。
  • ViewWillDisappear - ビュー コントローラーのビューがコンテンツ ビュー階層から削除されて画面から消える直前に毎回呼び出されます。 このライフサイクル イベントは、クリーンアップと状態の保存に使用されます。
  • ViewDidAppearViewDidDisappear - それぞれビューがコンテンツ ビュー階層に追加されるときとコンテンツ ビュー階層から削除されるときに呼び出されます。

ライフサイクルのいずれかの段階にカスタム コードを追加するときは、そのライフサイクル メソッドの基本実装オーバーライドする必要があります。 これは、既に一部のコードがアタッチされている既存のライフサイクル メソッドを利用し、追加のコードで拡張することによって実現されます。 新しいコードの前に確実に元のコードが実行されるようにベースの実装がメソッドの内部から呼び出されます。 次のセクションでこの例を示します。

ビュー コントローラーの操作の詳細については、Apple の「View Controller Programming Guide for iOS」(iOS 用ビュー コントローラー プログラミング ガイド) と UIViewController リファレンスに関するページを参照してください。

ユーザー操作に対する応答

ビュー コントローラーの最も重要な役割は、ボタンを押す操作、ナビゲーションなどのユーザーの操作に応答することです。 ユーザーの操作を処理する最も簡単な方法は、ユーザーの入力をリッスンするようにコントロールを配置し、入力に応答するためのイベント ハンドラーをアタッチすることです。 たとえば、Phoneword アプリで示したように、タッチ イベントに応答するようにボタンを配置することができます。

そのしくみを探ってみましょう。 Phoneword_iOS プロジェクトでは、TranslateButton というボタンを現在のビュー階層に追加しました。

A button was added called TranslateButton to the Content View Hierarchy

参照アウトレットは、Xcode Interface Builder を使用して作成されると、Xcode Sync によって自動的に ViewController.designer.cs 内のコントロールにマップされ、ViewController クラスで TranslateButton を使用できるようになります。 コントロールは、ビュー ライフサイクルの ViewDidLoad ステージで初めて利用可能になるので、このライフサイクル メソッドを使用して、ユーザーのタッチに応答します。

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();

    // wire up TranslateButton here
}

Phoneword アプリでは、TouchUpInside というタッチ イベントを使用してユーザーのタッチを待ち受けるようにします。 TouchUpInside は、コントロールのボタン内でのタッチ ダウン (指が画面に触れる) に続くタッチ アップ イベント (指が画面から離れる) を待ち受けます。 TouchUpInside の逆は、ユーザーがコントロールを下に押したときに発生する TouchDown イベントです。 TouchDown イベントは、多数のノイズをキャプチャし、ユーザーはコントロールから指をスライドさせて離してタッチをキャンセルするオプションを与えられません。 TouchUpInside は、ボタン タッチに応答するための最も一般的の方法であり、ユーザーがボタンを押すときに予想するエクスペリエンスを作成します。 これの詳細については、Apple の「iOS Human Interface Guidelines」(iOS ヒューマン インターフェイス ガイドライン) を参照してください。

このアプリでは、TouchUpInside イベントがラムダで処理されますが、デリゲートまたは名前付きイベント ハンドラーを使用することもできます。 最後のボタン コードは次のようになります。

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    string translatedNumber = "";

    TranslateButton.TouchUpInside += (object sender, EventArgs e) => {
      translatedNumber = Core.PhonewordTranslator.ToNumber(PhoneNumberText.Text);
      PhoneNumberText.ResignFirstResponder ();

      if (translatedNumber == "") {
        CallButton.SetTitle ("Call", UIControlState.Normal);
        CallButton.Enabled = false;
      } else {
        CallButton.SetTitle ("Call " + translatedNumber, UIControlState.Normal);
        CallButton.Enabled = true;
      }
  };
}

Phoneword で導入されているその他の概念

Phoneword アプリケーションでは、このガイドでは説明していない概念がいくつか導入されています。 たとえば、次のような概念です。

  • ボタンのテキストの変更 – Phoneword アプリでは、ボタン上で SetTitle を呼び出して、新しいテキストとボタンのコントロールの状態を渡すことによってボタンのと変更する方法を紹介しています。 たとえば、次のコードは、CallButton のテキストを "Call" に変更します。

    CallButton.SetTitle ("Call", UIControlState.Normal);
    
  • ボタンの有効化と無効化 - ボタンは、Enabled または Disabled 状態になります。 無効になっているボタンはユーザー入力に応答しません。 たとえば、次のコード例は CallButton を無効にしています。

    CallButton.Enabled = false;
    

    ボタンの詳細については、ボタンに関するガイドを参照してください。

  • キーボードを消去 – ユーザーがテキスト フィールドをタップすると、ユーザーが値を入力できるようにするキーボードが iOS によって表示されます。 残念ながら、キーボードを消去する組み込みの機能はありません。 ユーザーが TranslateButton を押したときにキーボードを消去する次のコードが TranslateButton に追加されます。

    PhoneNumberText.ResignFirstResponder ();
    

    キーボードを消去する他の例については、「Dismiss the Keyboard」 (キーボードの消去) のレシピを参照してください。

  • URL を使用して電話をかける – Phoneword アプリで Apple URL スキームを使用してシステム電話アプリを起動します。 次のコードに示すように、カスタムの URL スキームは、"tel:" プレフィックスと変換された電話番号で構成されます。

    var url = new NSUrl ("tel:" + translatedNumber);
    if (!UIApplication.SharedApplication.OpenUrl (url))
    {
        // show alert Controller
    }
    
  • アラートを表示 – シミュレーターや iPod Touch などの呼び出しをサポートしないデバイスでユーザーが電話をかけようとした場合、電話をかけることができないことを知らせる警告ダイアログが表示されます。 次のコードでは、警告コントローラーを作成して入力します。

    if (!UIApplication.SharedApplication.OpenUrl (url)) {
                    var alert = UIAlertController.Create ("Not supported", "Scheme 'tel:' is not supported on this device", UIAlertControllerStyle.Alert);
                    alert.AddAction (UIAlertAction.Create ("Ok", UIAlertActionStyle.Default, null));
                    PresentViewController (alert, true, null);
                }
    

    iOS の警告ビューの詳細については、Alert Controller のレシピを参照してください。

テスト、展開、および最後の仕上げ

Visual Studio for Mac と Visual Studio のいずれも、アプリケーションをテストおよび展開するためのオプションを多数用意しています。 このセクションでは、デバッグ オプションについて説明し、デバイスでのアプリケーションのテストのデモンストレーションを示し、カスタム アプリ アイコンと起動イメージを作成するためのツールを紹介します。

デバッグ ツール

アプリケーション コード内の問題の診断は困難なことがあります。 複雑なコードの問題の診断に役立てるために、ブレークポイントを設定するコードのステップを実行する、またはログ ウィンドウに情報を出力することができます。

デバイスに展開する

iOS シミュレーターは、アプリケーションをテストする簡単な方法です。 シミュレーターには、場所の偽装、移動のシミュレーションなどのいくつかの役に立つテストのための最適化が用意されています。 ただし、ユーザーは、最終的なアプリをシミュレーターで使用しません。 すべてのアプリケーションは、早い段階で頻繁に実際のデバイスでテストしてください。

デバイスは、プロビジョニングに時間がかかり、Apple 開発者アカウントが必要です。 デバイス プロビジョニング ガイドでは、開発用デバイスを準備する詳細な手順を説明しています。

Note

現時点では、Apple の求めにより、物理デバイスまたはシミュレーターのコードをビルドするために、開発証明書または署名 ID を用意する必要があります。 デバイス プロビジョニング ガイドの手順に従ってこれを設定します。

デバイスがプロビジョニングされたら、プラグインすることで展開し、次のスクリーンショットに示すようにビルド ツールバーでターゲットを iOS デバイスに変更して、[Start] (Play) を押します。

Pressing Start/Play

Pressing Start/Play

iOS デバイスにアプリが展開されます。

The app will deploy to the iOS device and run

カスタム アイコンを生成し、イメージを起動する

誰もが、デザイナーを使用してカスタム アイコンを作成し、アプリで目立つようにする必要がある画像を起動できるわけではありません。カスタム アプリのアートワークを生成するためのいくつかの代替の方法を次に示します。

  • Pixelmator – 約 30 ドルの Mac 用の多様な画像編集アプリです。
  • Fiverr – 5 ドルから利用でき、さまざまなデザイナーから選択してアイコンのセットを作成できます。 見つかる場合も見つからない場合もありますが、アイコンをすぐにデザインする必要がある場合は有効なリソースです。
  • Visual Studio - これを使用して、アプリ用の単純なアイコン セットを IDE で直接作成できます。
  • Fiverr – 5 ドルから利用でき、さまざまなデザイナーから選択してアイコンのセットを作成できます。 見つかる場合も見つからない場合もありますが、アイコンをすぐにデザインする必要がある場合は有効なリソースです。

アイコンと起動イメージのサイズと要件に関する詳細については、「イメージの処理」ガイドを参照してください。

まとめ

おめでとうございます。 これで、Xamarin.iOS アプリケーションのコンポーネント、およびそれを作成するためのツールを確実に理解できました。 作業の開始シリーズの次のチュートリアルでは、複数の画面を処理するようにアプリケーションを拡張します。 複数の画面を処理するようにアプリケーションを拡張する途中でナビゲーション コントローラーを実装して、ストーリーボードの Segue について学習し、モデル、ビュー、コントローラー (MVC) のパターンを紹介します。