Start Developing iOS Apps Today(11)~チュートリアル:データの追加

2014. 03. 31
●チュートリアル:データの追加

このチュートリアルは、2つ目のチュートリアル(チュートリアル:ストーリーボード)で作成したプロジェクトに基づいています。
ToDoListアプリに動的データのサポートを追加するために、これまで学んだデザインパターンの使用や、Foundationとの連携、カスタムクラスの記述を使用します。

このチュートリアルでは以下の方法を教えます。

  • 一般的なFoundationクラスとの連携
  • カスタムデータクラスの作成
  • デリゲートとデータソースプロトコルの実装
  • ビューコントローラ間でデータを渡す

このチュートリアルの全ての手順を完了すると、次のような見た目のアプリになります。

ios_simulator_add_new_item_2x.png  ios_simulator_full_list_checked_2x.png



●データクラスの作成

開始するにはXcodeで既存のプロジェクトを開きます。

この時点で、ストーリーボードを使用したToDoListアプリのためのインターフェイスとナビゲーションスキームを持っています。
ここではデータストレージとモデルオブジェクトとの動作を追加します。

アプリの目標はToDo項目のリストを作成することなので、最初に個々のToDo項目を表すためのカスタムクラスXYZToDoItemを作成します。
ご存知のように、XYZToDoItemクラスは「カスタムクラスの記述」で説明しました。


XYZToDoItemクラスの作成

  1. File > New > Fileを選択します(またはCommand + Nを押します)。

    新しいファイルのテンプレートの選択を促すダイアログが表示されます。

  2. 左側でiOSの下のCocoa Touchを選択します。

  3. Objective-C classを選択し、Nextをクリックします。

  4. Class欄で、XYZ接頭辞の後にToDoItemと入力します。

  5. "Subclass of"のポップアップメニューからNSObjectを選択します。

    正確にチュートリアルを追ってきた場合、クラスのタイトルはおそらくこの前工程のXYZToDoItemViewControllerとなっています。
    "Subclass of"でNSObjectを選択すると、Xcodeは通常のカスタムクラスを作成すると知り、以前に追加していたViewControllerテキストを削除します。

  6. Nextをクリックします。

  7. 保存場所はデフォルトでプロジェクトのディレクトリになっています。
    そのままにしておきます。

  8. Groupオプションはデフォルトでアプリ名のToDoListになっています。
    そのままにしておきます。

  9. Targetsセクションはデフォルトでアプリが選択、アプリのテストは非選択になっています。
    これは完璧なので、そのままにしておきます。

  10. Createをクリックします。

XYZToDoItemクラスは簡単に実装できます。
名前、作成日時、項目が完了したかどうかのプロパティを持ちます。
この後、XYZToDoItemクラスのインターフェイスでこれらのプロパティを追加します。


XYZToDoItemクラスの構成

  1. プロジェクトナビゲータでXYZToDoItem.hを選択します。

  2. 以下のようにインターフェイスにプロパティを追加します。

    @interface XYZToDoItem : NSObject

    @property NSString *itemName;
    @property BOOL completed;
    @property (readonly) NSDate *creationDate;

    @end

チェックポイント:Product > Buildを選択して(またはCommand + Bを押して)プロジェクトをビルドします。
貴方はまだ新しいクラスで何も使用していませんが、ビルドするとコンパイラが何らかの入力ミスを行っていないかを確認する機会を与えてくれます。
コンパイラが提供する警告やエラーを通して読むことによってそれらを修正し、全てがここで説明している方法に見えるか確認するために、このチュートリアルの手順を振り返ってください。



●データの読み込み

これで個々のリスト項目のデータを作成して格納することができるクラスができました。
また、それらの項目のリストを保持する必要があります。
これを追跡するための自然な場所は、(モデルとビュー間の調整を担当して、モデルを参照する必要がある)XYZToDoListViewControllerクラスです。

Foundationフレームワークには、項目のリストの追跡に適したクラスNSMutableArrayが含まれています。
ユーザが配列に項目を追加するために、可変配列を使用することが重要です。
不変バージョンのNSArrayでは、初期化した後に項目を追加することはできません。

配列を使用するには、それを宣言して作成することの両方が必要です。
配列の割り当てと初期化をすることによって、これを行います。


配列の割り当てと初期化

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

    項目の配列はテーブルビューコントローラの実装の詳細なので、.hファイルの代わりに.mファイルに宣言します。
    これはカスタムクラスでのプライベートになります。

  2. Xcodeがカスタムテーブルビューコントローラクラス内に作成したインターフェイスの範疇に、以下のプロパティを追加します。
    宣言は次のようになります。

    @interface XYZToDoListViewController ()

    @property NSMutableArray *toDoItems;

    @end

  3. viewDidLoadメソッドでtoDoItems配列の割り当てと初期化を行います。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.toDoItems = [[NSMutableArray alloc] init];
    }

viewDidLoadの実際のコードでは、(XYZListViewControllerを作成した時にXcodeによって挿入された)コメントアウトされているいくつかの追加の行が挿入されています。
気にせずにそのままにしておきます。

この時点で、項目を追加することができる配列を持っています。
これを行うのは別個のメソッドloadInitialDataで、viewDidLoadから呼び出します。
このコードはモジューラタスクなため独自のメソッドで行い、別個のメソッドを作成することによってコードの可読性を向上させることができます。
実際のアプリでは、このメソッドはファイルなどある種の永続ストアからデータを読み込みます。
今のところ、目標はテーブルビューがカスタムデータ項目でどのように動作するかを確認することなので、実験のためにいくつかのテストデータを作成します。

配列を作成した方法(割り当てと初期化)で項目を作成します。
その後、項目に名前を付けます。
これはテーブルビューに表示される名前です。
いくつかの項目に対してこれを行います。


初期データの読み込み

  1. @implementation行の下に、新しいメソッドloadInitialDataを追加します。

    - (void)loadInitialData {
    }

  2. このメソッド内でいくつかのリスト項目を作成し、配列に追加します。

    - (void)loadInitialData {
        XYZToDoItem *item1 = [[XYZToDoItem alloc] init];
        item1.itemName = @"Buy milk";
        [self.toDoItems addObject:item1];
        XYZToDoItem *item2 = [[XYZToDoItem alloc] init];
        item2.itemName = @"Buy eggs";
        [self.toDoItems addObject:item2];
        XYZToDoItem *item3 = [[XYZToDoItem alloc] init];
        item3.itemName = @"Read a book";
        [self.toDoItems addObject:item3];
    }

  3. viewDidLoadメソッド内でloadInitialDataを呼び出します。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        self.toDoItems = [[NSMutableArray alloc] init];
        [self loadInitialData];
    }

チェックポイント:Product > Buildを選択してプロジェクトをビルドします。
loadInitialDataメソッドの行で多数のエラーが表示されるはずです。
うまく行かない鍵は最初の行で、“Use of undeclared identifier XYZToDoItem”を言う必要があるからです。
これはXYZToDoListViewControllerをコンパイルする時に、コンパイラがXYZToDoItemについて知らないことを意味します。
コンパイラは非常に特殊であり、何に注意を払うかを明示的に指示する必要があります。


カスタムリスト項目クラスに注意を払うようにコンパイラに指示

  1. XYZToDoListViewController.mの先頭近くの行にある、#import "XYZToDoListViewController.h"を見つけます。

  2. すぐ下に次の行を追加します。

    #import "XYZToDoItem.h"

チェックポイント:Product > Buildを選択してプロジェクトをビルドします。
ここではエラー無しでビルドする必要があります。



●データの表示

この時点で、テーブルビューは
いくつかのサンプルToDo項目が事前に入っている可変配列を持っています。
ここでテーブルビューにデータを表示する必要があります。

XYZToDoListViewControllerでテーブルビューのデータソースを作成することによって、これを行います。
何らかのテーブルビューのデータソースを作成するには、UITableViewDataSourceプロトコルを実装する必要があります。
実装する必要があるメソッドは、ちょうど2つ目のチュートリアルでコメントアウトしたので、これを反転します。
テーブルビューが機能するようにするには、3つのメソッドが必要です。
1つ目はnumberOfSectionsInTableView:で、表示するセクション数をテーブルビューに伝えます。
このアプリでは、テーブルビューで単一のセクションを表示したいので、実装は簡単です。


テーブルでのセクションの表示

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

  2. 2つ目のチュートリアルでテーブルビューのデータソースメソッドをコメントアウトした場合は、ここでコメントマーカを削除します。

  3. 以下のようなテンプレートの実装部分を探します。

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 0;
    }

    単一のセクションにしたい場合、警告行を削除して、戻り値を0から1に変更します。

  4. 単一セクションを返すため、以下のようにnumberOfSectionsInTableView:データソースメソッドを変更します。

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
    // Return the number of sections.
    return 1;
    }

次のメソッドはtableView:numberOfRowsInSection:で、指定したセクションで表示する行数をテーブルビューに伝えます。
テーブルには単一のセクションが有り、各ToDo項目はテーブルビューに独自の行を持つ必要があります。
つまり行数はtoDoItem配列内のXYZToDoItemオブジェクトの数にする必要があることを意味します。


テーブル内の行数を返す

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

  2. 以下のようなテンプレートの実装部分を探します。

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        #warning Incomplete method implementation.
        // Return the number of rows in the section.
        return 0;
    }

    貴方はリストの項目数を返すようにしたいでしょう。
    幸いなことに、NSArrayは配列内の項目数を返すcountと呼ばれる便利なメソッドを持っており、行数は[self.toDoItems count]で得られます。

  3. 適切な行数を返すように、tableView:numberOfRowsInSection:データソースメソッドを変更します。

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        // Return the number of rows in the section.
        return [self.toDoItems count];
    }

最後のメソッドはtableView:cellForRowAtIndexPath:で、指定した行に表示するセルを尋ねます。
これまではコードだけで作業してきましたが、行に表示するセルはインターフェイスの大部分を占めます。
幸いなことに、XcodeはInterface Builderでカスタムセルを容易に設計することができます。
最初のタスク、テーブルビューに伝えるために静的コンテンツを使用する代わりに、動的コンテンツでプロトタイプセルを使用するセルを設計します。


テーブルビューの設定

  1. ストーリーボードを開きます。

  2. アウトラインでテーブルビューを選択します。

  3. テーブルビューが選択された状態で、ユーティリティ領域で属性インスペクタinspector_attributes_2x_20140209113430cca.png を開きます。

  4. 属性インスペクタで、テーブルビューのContent属性をStatic CellsからDynamic Prototypesに変更します。

Interface Builderは設定された静的セルを取得し、それらを全てプロトタイプに変換します。
プロトタイプセルはその名が示す通り、設定されたテキスト形式、色、画像、または他の属性を、貴方が望む際に実行時にデータソースからデータを取得して表示するセルです。
データソースは各行のプロトタイプセルを読み込んでから、行のデータを表示するために設定されます。

適切なセルを読み込むにはデータソースが呼び出される物を知っている必要があり、その名前もストーリーボードで設定する必要があります。

貴方はプロトタイプセル名を設定していますが、別のプロパティ(ユーザがタップした時のセルの外観を決定する、セルの選択スタイル)も設定することになります。
ユーザがタップした時にセルがハイライト表示されないようにするためには、セルの選択スタイルをNoneに設定します。
これは(このチュートリアルの後半で実装する機能の)ユーザがToDoリストの項目をタップした時に、完了または未了として印したいセルの動作です。


プロトタイプセルの設定

  1. テーブルで最初のテーブルビューセルを選択します。

  2. 属性インスペクタでIdentifier欄を探し、ListPrototypeCellと入力します。

  3. 属性インスペクタでSelection欄を探し、Noneを選択します。

またプロトタイプセルのフォントや他の属性を変更することもできます。
基本的な設定は容易な作業なので、しておきましょう。

次の手順はtableView:cellForRowAtIndexPath:を実装することによって、指定した行のセルをどのように設定するかをデータソースに教える事です。
このデータソースメソッドは、指定した行を表示したい時にテーブルビューによって呼び出されます。
行が少数のテーブルビューでは、おそらく全ての行が一度に画面に表示されますが、このメソッドはテーブルの各行毎に呼び出されます。
しかし多数の行を含むテーブルビューでは、特定の時点で総項目の極一部のみ表示されます。
テーブルビューにとって表示されている行のセルのみを尋ねるのが最も効率的で、tableView:cellForRowAtIndexPath:はテーブルビューにそれを行うことができます。

テーブル内の任意の行について、toDoItems配列内の対応するエントリを取り出し、項目名にセルのテキストラベルを設定します。


テーブル内のセルの表示

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

  2. tableView:cellForRowAtIndexPath:データソースメソッドを探します。
    テンプレートの実装は次のようになります。

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

        // Configure the cell...

        return cell;
    }

    テンプレートではいくつかのタスクを実行します。
    セルの識別子を保持する変数を作成し、その識別子を持つセルのためのテーブルビューを尋ね、セルを構成するためのコードが行く場所についてのコメントが追加され、そしてセルを返しています。

    貴方のアプリ用にこのコードを機能させるには、ストーリーボードで設定するために識別子を変更し、セルを構成するコードを追加する必要があります。

  3. ストーリーボードで設定するために、セル識別子を変更します。
    タイプミスを避けるために、ストーリーボードから実装ファイルにコピー&ペーストします。
    セル識別子の行は次のようになります。

    static NSString *CellIdentifier = @"ListPrototypeCell";

  4. return文の直前に以下のコード行を追加します。

    XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
    cell.textLabel.text = toDoItem.itemName;

貴方のtableView:cellForRowAtIndexPath:メソッドは以下のようになります。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ListPrototypeCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
    cell.textLabel.text = toDoItem.itemName;
    return cell;
}

チェックポイント:アプリを実行します。
loadInitialDataで追加した項目のリストがテーブルビューのセルとして表示される必要があります。



●完了として項目を印す

項目に完了したと印すことができない場合、ToDoリストとしてあまり良くありません。
ここで、そのためのサポートを追加します。
シンプルなインターフェイスは、ユーザがセルをタップした時に完了状態を切り替えられるようにし、その横にチェックマークで完了した項目を表示するようにします。
幸いなことに、テーブルビューには(特にユーザがセルをタップした時に、テーブルビューがデリゲートに通知するといった)このシンプルなインターフェイスを実装するために利用することができる、いくつかの組み込み動作が含まれています。
したがってタスクは、ユーザがテーブル内のToDo項目をタップすることに対応するコードを記述することです。

Xcodeは既にストーリーボードで設定した時に、テーブルビューのデリゲートXYZToDoListViewControllerを作成しています。
貴方はユーザのタップに応答してToDoリストの項目を適切に更新するために、tableView:didSelectRowAtIndexPath:デリゲートメソッドを実装する必要があります。

セルが選択された時に、テーブルビューはどのような選択処理をする必要があるのかを確認するために、tableView:didSelectRowAtIndexPath:デリゲートメソッドを呼び出します。
このメソッドには、ToDo項目の完了状態を更新するためのコードを記述します。


完了または未了として項目を印す

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

  2. ファイルの最後の@end行の上に、以下の行を追加します。

    #pragma mark - Table view delegate

    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {

    }

    2行目はコピー&ペーストをする代わりに、入力してみてください。
    Xcodeの素晴らしい時間節約機能の一つであるコード補完が分かります。
    Xcodeが潜在的な補完のリストを表示する際に、貴方が望む物を見つけてReturnを押すまでスクロールします。
    Xcodeは行全体を挿入します。

  3. タップには応答するが、実際にセルが選択されたままにしたくはありません。
    選択した直後にセルの選択を解除するには以下のコードを追加します。

    [tableView deselectRowAtIndexPath:indexPath animated:NO];

  4. toDoItems配列内で対応するXYZToDoItemを検索します。

    XYZToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];

  5. タップされた項目の完了状態を切り替えます。

    tappedItem.completed = !tappedItem.completed;

  6. データが更新された行を再読み込みするためにテーブルビューに伝えます。

    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];

tableView:didSelectRowAtIndexPath:メソッドは次のようになります。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
    XYZToDoItem *tappedItem = [self.toDoItems objectAtIndex:indexPath.row];
    tappedItem.completed = !tappedItem.completed;
    [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
}

チェックポイント:アプリを実行します。
loadInitialDataに追加された項目のリストがテーブルビューのセルとして表示されます。
しかし項目をタップしても何も起きていないように見えます。
何故でしょう?

その理由は、項目の完了状態を表示するためのテーブルビューセルを構成していないからです。
方法はtableView:cellForRowAtIndexPath:メソッドに戻り、項目が完了した時にインジケータを表示するようにセルを構成する必要があります。

項目が完了したことを示す一つの方法は、横にチェックマークを置くことです。
幸いなことに、テーブルビューセルは右側にセルアクセサリを持つことができます。
デフォルトではアクセサリは何もありませんが、様々なアクセサリを表示するためにセルを変更することができ、その一つにはチェックマークもあります。
貴方はToDo項目の完了状態に基づいて、セルアクセサリを設定する必要があります。


項目の完了状態を表示

  1. tableView:cellForRowAtIndexPath:メソッドを表示します。

  2. セルのテキストラベルを設定する行の直後に、以下のコードを追加します。

    if (toDoItem.completed) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }

tableView:cellForRowAtIndexPath:メソッドは次のようになります。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"ListPrototypeCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
    XYZToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
    cell.textLabel.text = toDoItem.itemName;
    if (toDoItem.completed) {
        cell.accessoryType = UITableViewCellAccessoryCheckmark;
    } else {
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    return cell;
}

チェックポイント:アプリを実行します。
loadInitialDataで追加した項目のリストがテーブルビューのセルとして表示されます。
項目をタップするとチェックマークがその横に表示されます。
同じ項目を再度タップした場合、チェックマークが消えます。



●新しい項目の追加

ToDoリストアプリの機能を作成するための最後の手順は、項目を追加する機能を実装することです。
ユーザがXYZAddToDoItemViewControllerのシーン上のテキストフィールドで項目名を入力してDoneボタンをタップした時に、ビューコントローラは新しいリスト項目を作成して渡し、ToDoリストで表示するためにXYZToDoListViewControllerに戻るようにしたいでしょう。

まず、設定するためのリスト項目を持つ必要があります。
テーブルビューと同様に、ビューコントローラはモデルへのインターフェイスを接続するための論理的な場所です。
XYZAddToDoItemViewControllerに新しいToDo項目を保持するためのプロパティを与えます。


XYZAddToDoItemViewControllerクラスにXYZToDoItemを追加する

  1. プロジェクトナビゲータでXYZAddToDoItemViewController.hを選択します。

    後でテーブルビューコントローラからリスト項目にアクセスする必要があるため、パブリックプロパティとして作成することが重要です。
    これが実装ファイルXYZAddToDoItemViewController.mではなく、インターフェイスファイルXYZAddToDoItemViewController.hで宣言する理由です。

  2. XYZAddToDoItemViewController.hで、@interface行の上にXYZToDoItem.hのインポート宣言を追加します。

    #import "XYZToDoItem.h"

  3. インターフェイスにtoDoItemプロパティを追加します。

    @interface XYZAddToDoItemViewController : UIViewController

    @property XYZToDoItem *toDoItem;

    @end

新しい項目の名前を取得するには、ビューコントローラがユーザが名前を入力するテキストフィールドのコンテンツへのアクセスが必要になります。
これを行うには、ストーリーボードでXYZAddToDoItemViewControllerクラスからテキストフィールドへの接続を作成します。


ビューコントローラへのテキストフィールドの接続

  1. アウトラインビューでXYZAddToDoItemViewControllerオブジェクトを選択します。

  2. アシスタントエディタを開くために、ウィンドウのツールバーの右上にあるAssistantボタンをクリックします。

    assistant_editor_2x.png

    エディタの右側にXYZAddToDoItemViewController.mが表示されます。
    表示されなかった場合、右側のエディタでファイル名をクリックしてXYZaddToDoItemViewController.mを選択してください。

    アシスタントエディタは一度に2つのファイルを開くことができ、インターフェイスのオブジェクトとソースファイルのプロパティを接続するなど、それらの間の操作を実行することができます。

  3. ストーリーボードでテキストフィールドを選択します。

  4. キャンバス上のテキストフィールドからエディタの右側に表示されているコードにControl+ドラッグをし、XYZAddToDoItemViewController.mの@interface行の下の行でドラッドを止めます。

    assistant_editor_drag_2x.png

  5. 表示されるダイアログで、Name欄にtextFieldと入力します。

    残りのオプションはそのままにしておきます。
    ダイアログは次のようになります。

    configure_text_field_outlet_2x.png

  6. Connectをクリックします。

    Xcodeはテキストフィールドへのポインタを格納するためにXYZAddToDoItemViewController.mに必要なコードを追加し、その接続を設定するためにストーリーボードを構成します。

更に項目を作成する時に知っておく必要があることがあります。
貴方はDoneボタンがタップされた場合のみ、項目を作成したいでしょう。
これを行うには、アウトレットとしてDoneボタンを追加します。


ビューコントローラにDoneボタンを接続

  1. ストーリーボードでアシスタントエディタを開き、ウィンドウの右端にXYZAddToDoItemViewController.mを設定します。

  2. ストーリーボードでDoneボタンを選択します。

  3. キャンバス上のDoneボタンからエディタの右側に表示されているコードにControl+ドラッグをし、XYZAddToDoItemViewController.mのtextFieldプロパティの下の行でドラッドを止めます。

  4. 表示されるダイアログで、Name欄にdoneButtonと入力します。

    残りのオプションはそのままにしておきます。
    ダイアログは次のようになります。

    configure_done_button_outlet_2x.png

  5. Connectをクリックします。

これでDoneボタンを識別するための方法を持ちました。
Doneボタンをタップすると項目が作成されるので、貴方はこれが発生すると知っている必要があります。

ユーザがDoneボタンをタップすると、(2つ目のチュートリアルで構成したインターフェイスの)ToDoリストに戻るアンワインドセグエが始動します。
セグエが実行される前に、システムはprepareForSegue:を呼び出すことによって、関連するビューコントローラを準備する機会を与えます。
これはユーザがDoneボタンをタップしたかどうかを厳密に確認するためのもので、そうであれば新しいToDo項目を作成します。
いずれかのボタンをタップした場所を確認し、それがDoneボタンであった場合に項目を作成することができます。


Doneボタンをタップした後に項目を作成

  1. プロジェクトナビゲータでXYZAddToDoItemViewController.mを選択します。

  2. @imprementation行の下にprepareForSegue:メソッドを追加します。

    - (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {
    }

  3. このメソッドでは、Doneボタンがタップされたかどうかを確認します。
    そうでない場合は項目を保存する代わりに、メソッドは何も実行せずに返すようにします。

    if (sender != self.doneButton) return;

  4. テキストフィールドにテキストがあるかどうかを確認します。

    if (self.textField.text.length > 0) {
    }

  5. テキストがある場合、新しい項目を作成してテキストフィールドのテキストに名前を付けます。
    また、完了状態がNOに設定されていることを確実にします。

    self.toDoItem = [[XYZToDoItem alloc] init];
    self.toDoItem.itemName = self.textField.text;
    self.toDoItem.completed = NO;

    テキストが無い場合、項目を保存したくないため何もしません。

prepareForSegue:メソッドは以下のようになります。

- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if (sender != self.doneButton) return;
    if (self.textField.text.length > 0) {
        self.toDoItem = [[XYZToDoItem alloc] init];
        self.toDoItem.itemName = self.textField.text;
        self.toDoItem.completed = NO;
    }
}

これで新しい項目を作成できるようになったので、ToDoリストに項目を追加できるように、XYZToDoListViewControllerに戻って項目を渡す必要があります。
これを実現するには、2つ目のチュートリアルで記述したunwindToList:メソッドを再考する必要があります。
このメソッドは、ユーザがCancelまたはDoneボタンのどちらかをタップした時に生ずる、XYZAddToDoItemViewControllerのシーンが閉じる際に呼び出されます。

unwindToList:メソッドは、アンワインドセグエのターゲットとして使用されている全てのメソッドのように、パラメータとしてセグエを取ります。
セグエパラメータは、XYZAddToDoItemViewControllerからXYZToDoListViewControllerに巻き戻るセグエです。
セグエは2つのビューコントローラ間の遷移なので、ソースビューコントローラ(XYZAddToDoItemViewController)を認識しています。
ソースビューコントローラのセグエオブジェクトを尋ねることによって、unwindToList:メソッドのソースビューコントローラに格納されているデータにアクセスすることができます。
この場合はtoDoItemへのアクセスです。
(テキストフィールドがテキストを持っていない、あるいはユーザがCancelボタンをタップして)nilの場合、項目は作成されません。
toDoItemの値がある場合、項目を取得してtoDoItems配列に追加し、テーブルビューのデータを再読み込みすることによってToDoリストに表示します。


新しい項目の格納と表示

  1. プロジェクトナビゲータでXYZToDoListViewController.mを選択します。

  2. XYZToDoListViewController.mで、@interface行の上にXYZAddToDoItemViewController.hのインポート宣言を追加します。

    #import "XYZAddToDoItemViewController.h"

  3. 2つ目のチュートリアルで追加したunwindToList:メソッドを探します。

  4. このメソッドで、XYZAddToDoItemViewControllerからアンワインドするコントローラであるソースビューコントローラを取得します。

    XYZAddToDoItemViewController *source = [segue sourceViewController];

  5. コントローラのToDo項目を取得します。

    XYZToDoItem *item = source.toDoItem;

    これはDoneボタンがタップされた時に作成された項目です。

  6. 項目が存在するかどうかを確認します。

    if (item != nil) {
    }

    nilの場合はCancelボタンで画面を閉じたか、またはテキストフィールドがテキストを持っていなかったかのどちらかで、項目を保存しません。

    存在する場合、toDoItems配列に項目を追加します。

    [self.toDoItems addObject:item];

  7. テーブルのデータを再読み込みします。

    テーブルビューはデータの追跡を保持しないため、表示するための新しいデータがある時にテーブルビューに通知するのはデータソース(この場合、テーブルビューコントローラ)の責任です。

    [self.tableView reloadData];

unwindToList:メソッドは次のようになります。

- (IBAction)unwindToList:(UIStoryboardSegue *)segue
{
    XYZAddToDoItemViewController *source = [segue sourceViewController];
    XYZToDoItem *item = source.toDoItem;
    if (item != nil) {
        [self.toDoItems addObject:item];
        [self.tableView reloadData];
    }
}

チェックポイント:アプリを実行します。
今では追加ボタン(+)をクリックして新しい項目を作成すると、ToDoリストに表示される必要があります。
おめでとう!
ユーザからの入力を受け取ってオブジェクトに格納し、2つのビューコントローラ間でオブジェクトを渡すアプリを作成できました。
これはストーリーボードベースのアプリでシーン間のデータ移動の基礎になっています。



●要約

貴方はiOSアプリ開発の入門ツアーをほとんど終えました。
最後の章ではドキュメントに関して貴方のやり方を検索する方法についてより多くの情報を与え、より高度なアプリを作成する方法を学ぶ上で採用する可能性のあるいくつかの次なる手順を提案しています。



参考文献

Apple/Start Developing iOS Apps Today

0 CommentsPosted in 資料





Wave SoundTouch music system IV
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
06 | 2017/07 | 08
Sun Mon Tue Wed Thu Fri Sat
- - - - - - 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 - - - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

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

Wish List
WACOM


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

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

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

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

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

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

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

Randomization Services

System Sound Services
Amazon


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