第08講 ウェブブラウザー
印刷を御希望の方はページ一番下の「印刷用ページ」より印刷してください。
PDFファイルとして保存したい場合も「印刷用ページ」より保存できます。
見出しに「★」マークがついた箇所は説明動画がございます。

目次

  1. 1 第8講のポイント
  2. 2 はじめに
  3. 3 プロジェクトの立ち上げと設定
    1. 3.1 新規プロジェクトの立ち上げ
    2. 3.2 アプリの設定
      1. 3.2.1 外部素材のインポート
      2. 3.2.2 アイコン設定とサポートするデバイスの向きの設定
    3. 3.3 Bundle display nameの設定
  4. 4 画面のデザイン
    1. 4.1 Autolayoutの無効化
    2. 4.2 ブラウザー画面のデザイン
      1. 4.2.1 Navigation Bar・Bar Button Itemの設置
      2. 4.2.2 Text Fieldの設置
      3. 4.2.3 Toolbar・Bar Button Itemの設置
      4. 4.2.4 WebViewの配置
    3. 4.3 お気に入り画面のデザイン
  5. 5 新規View Controllerの生成と画面遷移の設定
    1. 5.1 Favorites View Controllerの新規作成
    2. 5.2 Favorites View Controllerのアサイン
    3. 5.3 画面遷移の設定
  6. 6 リレーショナルデータベース
    1. 6.1 リレーショナルデータベースの概要
    2. 6.2 iOSにおけるリレーショナルデータベース
    3. 6.3 SQL言語
    4. 6.4 FMDatabaseライブラリー
  7. 7 コードの記述
    1. 7.1 Favoritesクラスの実装
      1. 7.1.1 新規クラスの作成
      2. 7.1.2 Favoritesクラスのコーディング
    2. 7.2 Favorites View Controllerのコーディング
      1. 7.2.1 メンバー変数の宣言とDelegateの設定
    3. 7.3 Delegateの設定
      1. 7.3.1 データベースの参照
      2. 7.3.2 Table Viewの構築
      3. 7.3.3 セルがクリックされた時の処理
      4. 7.3.4 「戻る」ボタンが押された時の処理
    4. 7.4 View Controllerのコーディング
      1. 7.4.1 メンバー変数の宣言
      2. 7.4.2 SQLiteデータベース とサンドボックス
      3. 7.4.3 Web View上にウェブページを表示
      4. 7.4.4 アドレスバーの設定
      5. 7.4.5 お気に入りの追加
      6. 7.4.6 お気に入り画面への遷移
      7. 7.4.7 お気に入り画面から戻った後の処理
      8. 7.4.8 View Controllerの初期処理
  8. 8 UI画面とコードの関連付け
    1. 8.1 ブラウザー画面の関連付け
    2. 8.2 お気に入り画面の関連付け
  9. 9 ビルドと動作試験
  10. 10 まとめ

第8講のポイント

第8講のポイント

  • Web Viewを利用
  • リレーショナルデータベース(SQLite)の利用

はじめに

前回の「RSSリーダー」では、RSSの取得から、XMLのパース、さらには、Table Viewの利用法まで、幅広くカバーしました。さらには、HTTP通信や非同期処理の概念等も学びました。

第8講の課題アプリは「ウェブブラウザー」となります。「ウェブブラウザー」はSafari等と同様のものです。ユーザーの要求に応じてウェブページを表示することが主目的となります。さらに付加機能として、お気に入りのウェブページを保存できるようになっています。お気に入りを保存するにあたって、今回は新たにリレーショナルデータベースというものを使います。



それでは、早速開発を始めて行きましょう! 

プロジェクトの立ち上げと設定

新しいアプリを作る際は、まず、新規プロジェクトを立ち上げとアプリの設定を行います。

新規プロジェクトの立ち上げ

新規プロジェクトを立ち上げます。その際、使用するテンプレートは「Single View Application」となります。



Product Name WebBrowser
Company Identifier com.rainbowapps
Device Family iPhone
Use Storyboard チェックを入れる
Use Automatic Reference Counting チェックを入れる
Include Unit Tests チェックを入れる

アプリの設定

新規プロジェクトを立ち上げたら、アプリの設定を行います。ここで、アプリのアイコンやアプリの表示タイトル(Bundle Display Name)、サポートするデバイスの向き(Device Orientation)を以下のように、設定します。

外部素材のインポート

まず今回使用する外部素材ファイルを一気にインポートしてしまいましょう。


今回使用する素材は以下の通りです。


icon.png アイコン画像
FMDatabase.h FMDatabaseライブラリー用ファイル
FMDatabase.m FMDatabaseライブラリー用ファイル
FMDatabaseAdditions.h FMDatabaseライブラリー用ファイル
FMDatabaseAdditions.m FMDatabaseライブラリー用ファイル
FMResultSet.h FMDatabaseライブラリー用ファイル
FMResultSet.m FMDatabaseライブラリー用ファイル
favorites.sqlite SQLiteデータベースファイル





アイコン設定とサポートするデバイスの向きの設定

素材のインポートが完了したら、Project Editorを開き、アイコンをRetina Displayと書かれたエリアの上にドラッグします。
サポートするデバイスの向きとアプリの名前は以下の通り設定します。


Bundle display nameの設定

アプリの表示タイトルを決めている設定項目「Bundle Display Name」を変更します。
Project Editorの「info」タブをクリックして「Bundle Display Name」の項目を次のように変更していきます。

 Bundle Display Name  ブラウザー



画面のデザイン

アプリの設定が完了したら、画面のデザインを行なっていきます。

Autolayoutの無効化

画面レイアウトを3.5インチ(iPhone4S以前)と4インチ(iPhone5以降)に対応させるための設定を行います。
まずはXcode4.5からデフォルトで有効になっているAutolayoutを無効にします。
※Autolayoutはまだ不安定ですので本講座はAutolayoutを無効にして画面デザインを行っていきます。
下記のように①View Controller全体を選択し、②「File Inspector」に変更して、③「Use Autolayout」のチェックを外してください。

ブラウザー画面のデザイン

Navigation Bar・Bar Button Itemの設置

まずは画面上部に、Navigation Barを設置します。ライブラリーエリアから、Navigation Barを選択し、画面の上部にドラッグします。


その次に、「更新」ボタンをNavigation Bar上に設置します。これまで使ってきたRound Rect Buttonではなく、今回はBar Button Itemを利用します。


次に、「お気に入り追加」ボタンの見た目を変更します。ボタンを選択した上で、インスペクターから、今回は通常のViewの上にTable Viewを設置していきます。ライブラリーエリアから「Identifier」を「Add」に変更します。これによって、ボタンの見た目が変更されることを確認してください。これは、「お気に入り追加」ボタンとなります。


この後、Navigation Barのタイトルを削除します。



Text Fieldの設置

次に、Navigation Barの左の方に、URLを入力するためのアドレスバーとなるText Fieldを設置します。



その後、Text Viewのサイズをインスペクターから調整します。「Width」を「260」にしましょう。


Toolbar・Bar Button Itemの設置

次に画面下部に、Toolbarオブジェクトを配置します。ライブラリーエリアからToolbarを選択して画面の一番下に設置します。



このToolbarにもう4つBar Button Itemを追加し、以下のようにします。設置したら、左寄りの2つをボタンのテキストをそれぞれ「戻る」と「進む」にします。さらに、「お気に入り追加」ボタンと同じ手法で、真ん中から右寄りの3つのボタンのIdentifierをそれぞれ、「Refresh」、「Stop」、「Bookmarks」とします。これらボタンに持たせる機能は、ボタンの内容が示す通りです。



このままだと、見栄え少々悪いので、「進む」ボタン「更新」ボタンの間にライブラリーエリアから「Flexible Space Bar Button Item」を挿入します。


WebViewの配置

最後に、画面の真ん中一杯にWeb Viewを配置します。


これでブラウザ画面の配置は完了です。

お気に入り画面のデザイン

次に、お気に入り画面のデザインを行います。まず新しいView Controllerを配置し、上部にNavigation Barを配置します。その後、以下のようにNavigation Barの左手にボタンを配置した上で、表示を「戻る」とします。最後にNavigation Barのタイトルを「お気に入り」とします。


次にTable Viewを設置し、Prototype Cellsを1として、Prototype CellsのIdentifierを「Cells」とします。


新規View Controllerの生成と画面遷移の設定

ここでは、お気に入り画面用のView Controllerを生成するとともに、画面遷移の設定を行います。

Favorites View Controllerの新規作成

まずは、お気に入り画面用のView Controllerを新しく作成します。

以下の表の通り、クラス名とオプションを設定し、「Next」をクリックし、既存のView Controllerのフォルダに保存します

 Class  FavoritesViewController
 Subclass of  UIViewController
 Targeted for iPad  チェックを外す
 With XIB for user interface  チェックを外す

正しくできた場合、FavoritesViewController.hとFavoritesViewController.mが以下のように生成されているはずです。



次は、生成したブラウザー画面とお気に入り画面の間の画面遷移の設定を行います。

Favorites View Controllerのアサイン

以下の通り、Favorites View Controllerを、実際のお気に入り画面にアサインします。



画面遷移の設定

この後、ブラウザー画面から、お気に入り画面への画面遷移(Segue)を設定します。基本的には、「ブックマーク」ボタンが押されると、お気に入り画面へのSegueが発動されるようにします。ただし、今回は直接ボタンにSegueを割り当てることはしません。理由はブラウザー画面とお気に入り画面の間でデータの受け渡しがあるからです。

今回、お気に入り画面は、ブラウザー画面上に一時的に現れるものであるという位置づけです。お気に入り画面から、ブラウザー画面へ戻る際は「次の画面にSegue」するのではなく、「前の画面に戻る」というスタンスとなります。そのため、設定するSegueは直接View ControllerからFavorites View Controllerまでのもの1つとなっています。なお、設定するSegueのタイプは、「Modal」を選択します。


Segueを設置したら、SegueのIdentifierを設定します。設置したSegueをクリックし、インスペクターからIdentifierを「toFavoritesView」にします。


リレーショナルデータベース

今回は、お気に入りページを保存するのに、「リレーショナルデータベース」というものを活用します。実装をはじめる前に、このリレーショナルデータベースに関する説明を行います。

リレーショナルデータベースの概要

リレーショナルデータベースとは、1970年にIBM社のEdgar F. Codd氏によって提唱されたリレーショナルデータモデルの理論に基づいたデータ管理方式の一種です。1件のデータを複数の項目(フィールド)の集合として表現し、データの集合を「テーブル」と呼ばれる表で表すことができます。さらに、ID番号や名前などのキーとなるデータを利用して、データの結合や抽出を容易に行うことができます。

一応公式な説明をすると、このような形になりますが、身近なところで行くと、「表」をイメージしていただいて、構いません。例として、今回お気に入りを保存するための「テーブル」の概観を以下に示します。


 id  title  url
 0  Yahoo! JAPAN  http://www.yahoo.co.jp
     

なおこの「テーブル」の名前は「my_favorites」とします。

このテーブルでは、「id」、「title」、「url」がそれぞれフィールド(カラム)名となっています。このように「表」のような形でデータを管理するデータベースをリレーショナルデータベースといいます。

リレーショナルデータベースは現在主流のウェブサービスで、ユーザーのデータを保存する代表的手法です。主な製品としては、MySQLやPostgreSQLなどがあり、双方とも世界中で広く普及しています。

iOSにおけるリレーショナルデータベース

iOSにおいては、リレーショナルデータベースとして、「SQLite」というものを利用することができます。SQLiteは手軽かつ軽量なリレーショナルの代表格です。これは1つのデータベースを単一のファイルとして扱うことができます。

今回、素材データを読み込む際、「favorites.sqlite」というファイルを読み込んだかと思います。これが今回使用するデータベースとなります。このデータベースには予め、先程示したテーブルが1つプリセットされています。今回はこのデータベースにお気に入りを登録していきます。

SQL言語

リレーショナルデータベースにおいて、データを保存したり、読みだしたりする場合、SQL言語というものがよく使われます。このSQL言語を用いることで、データベールにデータを登録したり、登録済みのデータの値を更新したり、任意のデータを抽出した上で読みだしたりすることができます。

まずは、データを登録する例から見て行きましょう。今回の「my_favorites」というテーブルに新たにデータを登録する場合は、以下のようになります。

 INSERT INTO my_favorites (title, url) VALUES (“Google”,“http://www.google.com”);

このように、テーブル名とフィード名をしてした上で、任意の値を新しく登録(INSERT)することができます。

次に、データを読み出す例を見てみましょう。同様に「my_favorites」というテーブルから全データを参照する場合、以下のようになります。

 SELECT * FROM my_favorites;

このように、リレーショナルデータベースはSQL文によって、データの登録や参照が行えるようになっています。

SQL言語はこれ以外にも様々なバリエーションがあります。データを参照する際に、特定の条件によって結果の抽出ができたり、テーブルの構成を変更したりと、実に多様な操作が行えます。ここで、全て扱うことはできませんが、興味のある人はぜひ調べてみて下さい。

FMDatabaseライブラリー

iOSからSQLiteを利用するにあたり、データを登録したり、参照したりするコードを記述しようとすると、少し複雑なコーディングが必要となります。ここで、FMDatabaseというライブラリーを使うと、コーディングを比較的簡単にすることができます。

今回は、このFMDatabaseを用いてSQLiteを操作することにします。差し当たり、冒頭で必要なファイルを一式インポートしましたが、それ以外に、以下のように必要なライブラリーの設定を施す必要があります。

ナビゲーターエリアよりプロジェクトを選択し、「Build Phases」タブを選択します。そのと、「Link Binary With Libraries」セクションの「追加」ボタンをクリックします。


その後、表示される一覧の中から、「libsqlite3.0.dylib」を選択肢、「Add」をクリックします。



その後、「Link Binary With Libraries」セクションに「libsqlite3.0.dylib」が追加されていることを確認し、完了となります。


コードの記述

ここでは、「ウェブブラウザー」のコードの記述をしていきます。

Favoritesクラスの実装

まずは、お気に入りのサイトの名前やURLを包括的に扱うFavoritesクラスの実装から行います。

新規クラスの作成

これまでと同じ方式で、Xcode上で「Favorites」というObjective-Cの新規クラスを作成しましょう。


正しく行った場合、Favorites.hとFavorites.mという2つのファイルが出来上がるはずです。


Favoritesクラスのコーディング

Favoritesクラスは、包括的にお気に入りサイトの情報を扱うための非常にシンプルなクラスです。以下のとおり、メンバー変数を宣言し、外部クラスから参照ができるように、プロパティの設定を行います。

Favorites.h
@interface Favorites : NSObject


@property NSString *url;

@property NSString *title;


@end


Favorites View Controllerのコーディング

データ受け渡しの都合上、まずは、Favorites View Controllerのコーディングを行います。

メンバー変数の宣言とDelegateの設定

まずはメンバー変数の宣言からから行なっていきます。

FavoritesViewController.m
@implementation FavoritesViewController {

    

    //お気に入り一式を格納する配列

    NSMutableArray *favoriteList;

    

    //SQLiteデータベースの名前とパス

    NSString *databaseName;

    NSString *databasePath;

    


}


Delegateの設定

このFavorites View Controllerでは、データベースに登録されたお気に入りサイトがTable View上に表示されます。お気に入りサイトが選択されたとき、もとのブラウザー画面で、その選択されたサイトのURLをロードするようにします。そこで、選択された項目のURLをブラウザー画面に伝達する必要があります。

今回の画面遷移は、「新しい画面を立ち上げる」のではなく、「前の画面に戻る」という扱いにします。前者の場合、Segue時に遷移先のメンバー変数に渡すことができますが、後者の場合は少し話が違ってきます。それは、遷移元にデータを返す必要があるからです。

ここで、Delegate通知が登場します。自分自身のDelegateを宣言し、このDelegate通知を遷移元に画面で受けるようにします。その際、所定のメソッドが呼ばれるようにプロトコルの設定を行い、そのメソッドでURLを受けるように設定します。

最初はわかりづらいかもしれませんが、とりあえず、コードを記述し、慣れるようにしましょう。それでは、以下のようにFavoritesViewController.hを編集し、独自のプロトコルの生成を行います。同時に、FMDatabaseライブラリーとFavoritesクラスを参照できるようにimport文を追記しましょう。

FavoritesViewController.h

#import <UIKit/UIKit.h>

#import "FMDatabase.h"

#import "FMDatabaseAdditions.h"

#import "Favorites.h"

@protocol FavoritesViewControllerDelegate;


@interface FavoritesViewController:UIViewController;

@property id <FavoritesViewControllerDelegate> delegate;

@end 


//独自のプロトコルを作成

@protocol FavoritesViewControllerDelegate <NSObject>

- (void)favoritesViewControllerDidCancel: (FavoritesViewController *)controller;

- (void)favoritesViewControllerDidSelect: (FavoritesViewController *)controller withUrl:(NSString *)favoriteUrl;

@end


ここにある、「id <FavoritesViewControllerDelegate> delegate」はこのクラス自身のDelegateを示します。

基本的には、ブラウザー画面側でこのFavorites View Controllerの発するDelegate通知を受け取るようにします。その上で、Delegate通知が発生した際に、呼ばれる2種類のメソッドを独自のプロトコルとして設定します。

データベースの参照

まずは、データベースを参照する前に、Favorites View Controllerの初期処理を見て行きましょう。FavoritesViewController.mの「viewDidLoad」を以下の通り改変していきます。

FavoritesViewController.m
 - (void)viewDidLoad {


    [super viewDidLoad]; 


    //favoritesを初期化

    favoriteList = [[NSMutableArray allocinit];


    //データベースのファイルパスを取得

    databaseName = @"favorites.sqlite";    

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMaskYES);

    NSString *documentDir = [documentPaths objectAtIndex:0];

    databasePath = [documentDir stringByAppendingPathComponent:databaseName];

    

    //データベースを参照して内容をfavoritesに入れる

    [self queryDB];

}


ここでは、まず、お気に入りを格納する配列である「favoriteList」を初期化しています。その後、データベースファイルの場所を取得しています。基本的には、「サンドボックス」の中の「Documents」フォルダに「favorites.sqlite3」が格納されているものとします。「サンドボックス」に関しては後ほど解説します。

次に、実際にデータベースを参照し、登録されているすべてのお気に入りサイト情報を「favoriteList」に格納するメソッドを、FavoritesViewController.mの中で記述します。

FavoritesViewController.m
//データベースより、登録されたお気に入りを参照

-(void) queryDB {


    //Databaseを開く

    FMDatabase* db = [FMDatabase databaseWithPath:databasePath];

    [db open];


    //クエリ文を指定

    NSString *query = [NSString stringWithFormat:@"SELECT * FROM my_favorites"];

    

    //クエリ開始

    [db beginTransaction];

    

    //項目ごとに新規にFavoritesインスタンスを生成し、URLとタイトルを格納

    //その後、そのインスタンスをfavoriteListに追加

    FMResultSet *results = [db executeQuery:query];

    while([results next]) {

        Favorites *f = [[Favorites allocinit];

        f.title = [results stringForColumn:@"title"];

        f.url  = [results stringForColumn:@"url"];

        [favoriteList addObject:f];

    }

    //Databaseを閉じる

    [db close];

}


まず、データベースファイルの場所をした上で、FMDatabaseクラスのインスタンスを生成します。次に、データベースを開き、SQL文(クエリ文)を実行します。ここでは、「my_favorites」テーブルに入っているデータをすべて参照するようになっています。その後、返された項目ごとにFavoritesクラスのインスタンスを生成し、タイトルとURLを格納します。これの処理をお気に入りの数だけ繰り返し、すべてのお気に入りデータの入った「favoriteList」ができあがります。読み込みが完了したら、データベースを閉じます。

Table Viewの構築

データベースからの読み込みが終わったら、お気に入りのタイトルをTable Viewに流し込みます。その前に、インターフェースファイル上でList Viewのプロトコルの設定を追加します。

FavoritesViewController.h
 【変更前】

@interface FavoritesViewController : UIViewController 

【変更後】

@interface FavoritesViewController : UIViewController <UITableViewDelegateUITableViewDataSource>


前回の「RSSリーダー」同様、以下の3つのメソッドを記述します。これらは、TableViewの構築に関わるメソッドです。

FavoritesViewController.m
//Table Viewのセクション数を指定

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

return 1;

}


//Table Viewのセルの数を指定

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return [favoriteList count];

}


//各セルにタイトルをセット

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    

    //セルのスタイルを標準のものに指定

    static NSString *CellIdentifier = @"Cells";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];


    //セルにお気に入りサイトのタイトルを表示

    Favorites *f = [favoriteList objectAtIndex:[indexPath row]];

    cell.textLabel.text = f.title;

    

    return cell;

}


基本的には、前回の「RSSリーダー」と同じ仕組でTable Viewを構築しています。唯一違っている部分は、今回は標準のセルを用いている点です。

セルがクリックされた時の処理

Table Viewが整ったところで、セルがクリックされた時に呼ばれる処理を以下の通り記述します。

FavoritesViewController.m
//リスト中のお気に入りアイテムが選択された時の処理

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

    

    //選択された項目のURLを参照

    Favorites *f = [favoriteList objectAtIndex:[indexPath row]];

    NSString *selectedURL = f.url;


    //引数でURLを指定しながらDelegate通知

    //View Controller上に設定した

    //favoritesViewControllerDidSelect」を呼び出し

    [self.delegate favoritesViewControllerDidSelect:self withUrl:selectedURL];

}


先程述べたとおり、今回はリスト中のアイテムが選択された場合、該当するサイトのURLを元のブラウザー画面に伝達する必要があります。そこで、Table View中のお気に入りの項目が選択されたとき、Delegate通知が発生するようにし、ブラウザー画面の中の「favoritesViewControllerDidSelect」というメソッドを呼び出すようにします。その際、引数としてお気に入りサイトのURLを渡します。

「戻る」ボタンが押された時の処理

最後にお気に入り画面の「戻る」ボタンが押された時に、ブラウザー画面に戻るメソッドを記述します。

FavoritesViewController.m
//「戻る」ボタンが押された時の処理

-(IBAction)back:(id)sender {

    //「戻る」ボタンが押されたことをDelegate通知

    //View Controller上に設定した

    //favoritesViewControllerDidCancel」を呼び出し

    [self.delegate favoritesViewControllerDidCancel:self];

    

}


これにて、お気に入り画面の実装は完了となります。

View Controllerのコーディング

次にView Controllerのコーディングを行います。

メンバー変数の宣言

まずはメンバー変数の宣言からから行なっていきます。

ViewController.m
@implementation ViewController {

    

    //Web View

    IBOutlet UIWebView *webView;

    //URLの入力フィールド

    IBOutlet UITextField *urlField;

    

    //表示中のページの名前とURL

    NSString *pageTitle;

    NSString *url;

    

    //SQLiteデータベースの名前とパス

    NSString *databaseName;

    NSString *databasePath;

    

    //正常にロード完了したかどうかを記録

    bool loadSuccessful;

}


今回はウェブページを表示するにあたって、UIWebViewクラスを用います。このクラスは、iOSアプリ上に任意のウェブページを簡単に表示することを可能にします。
同時に、View ControllerからFMDatabaseライブラリーとFavorites View Controllerクラスを参照できるようにします。以下の通り、ViewController.hを編集します。

ViewController.h
#import <UIKit/UIKit.h>


#import "FMDatabase.h"

#import "FMDatabaseAdditions.h"

#import "FavoritesViewController.h"

SQLiteデータベース とサンドボックス

まず、iOSデバイスは、それぞれアプリ専用の領域として、「サンドボック」が与えられています。このサンドボックスとは、iOSアプリが直接データを安全に読み書きできる領域で、アプリごとにそれぞれ用意されています。アプリ側からファイルを書きこむ(書き換える)場合、このサンドボックスにファイルがある必要があります。

今回は、データベースへの書き込みも行う都合上、初回起動時にデータベースファイル(favorites.sqlite)をプロジェクトのフォルダから、サンドボックス内の「Documents」フォルダにコピーする必要があります。そこで、起動する度に、サンドボックス内の「Documents」フォルダにデータベースファイルがあるかどうかを確認し、なければコピーするメソッドを実装していきます。

以下の通り、ViewController.mに記述して下さい。

ViewController.m
//データベースがサンドボックス内の「Documents」フォルダにあるか確認

//無ければ、プロジェクトフォルダからコピー

-(void) createAndCheckDatabase {

    

    BOOL success; 

    

    //databasePathに目的のファイルがあるか無いかを審査

    NSFileManager *fileManager = [NSFileManager defaultManager];

    success = [fileManager fileExistsAtPath:databasePath];

    

    //もしあれば、処理中断

    if(success) return

    

    //ない場合は、プロジェクトフォルダからサンドボックスへコピー

    NSString *databasePathFromApp = [[[NSBundle mainBundleresourcePathstringByAppendingPathComponent:databaseName];

    [fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];

    

}


ここにある、「databaseName」や「databasePath」の値は、後ほど初期処理を記述する際に設定します。

Web View上にウェブページを表示

まずは、Web View上にウェブページを表示するためのメソッドを記述します。

ViewController.m
//ページを要求・表示

-(void)makeRequest {

    //Web Viewでウェブページを呼び出す

    NSURLRequest *urlReq = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];

    NSLog(@"%@", [NSURL URLWithString:url]);

    [webView loadRequest:urlReq];

    

    //処理が完了するまでloadSuccessfulfalse

    loadSuccessful = false;

    

    //Activity Indicator発動

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

}


単純にWeb Viewに任意のウェブページを表示する場合は、上記のコードを見ても分かる通り、非常に簡単です。しかし、このままでは、ウェブページが正常にロードされたか、ロードに失敗したかを知ることはできません。そこで、Web ViewからDelegate通知をView Controllerで受けるようにし、成功時と失敗時に呼ばれるメソッドを実装していきます。

その前に、プロトコルの設定をインターフェースファイル上でやります。以下の通り、ViewController.hを編集して下さい。

ViewController.h
 【変更前】

@interface ViewController : UIViewController 

【変更後】

@interface ViewController : UIViewController <UIWebViewDelegate>


プロトコルの設定ができたら、実際に呼ばれるメソッドをViewController.mに実装していきます。

ViewController.m
//webロードが正常に完了

- (void)webViewDidFinishLoad:(UIWebView *)view {

    

    //ロードしたページの名前とURLを取得

    url = [[webView.request URLabsoluteString];

    pageTitle = [webView stringByEvaluatingJavaScriptFromString:@"document.title"];

    //現在のURLをアドレスバーに反映

    urlField.text = url;

    

    //ステータスバーのActivity Indicatorを停止

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    

    //処理が完了したのでloadSuccessfulture

    loadSuccessful = true;

}

// Web Viewロード中にエラーが生じた場合

- (void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error {

    //ステータスバーのActivity Indicatorを停止

    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    

    if(([[error domain]isEqual:NSURLErrorDomain]) && ([error code]!=NSURLErrorCancelled)) {

        //メッセージを表示

        UIAlertView *alert = [[UIAlertView allocinit];

        alert.title = @"エラー";

        alert.message = [NSString stringWithFormat:@"%@」をロードするのに失敗しました。", url];

        [alert addButtonWithTitle:@"OK"];

        [alert show];

    }

}


これらは、ページのロードが成功した時と失敗した時にそれぞれ呼ばれるメソッドです。

ページのロードに成功した場合、ロードしたページのタイトルとURLを取得するとおもに、アドレスバーのText Fieldの値を、ロードしたページのURLに書き換えています。

一方、ロードに失敗した場合は、その旨をUIAlertViewを用いて通知するようにしています。

なお、これらが正しく動作するためにはWeb ViewのDelegate通知をView Controllerで受けるようにしなくては行けません。そのための設定がもう一つあるのですが、それは後ほど初期処理を記述する際に行います。

アドレスバーの設定

今回、ブラウザー画面上部にURLを指定するためのText Viewを設置しました。その際、キーボード入力を正しく扱うメソッドを記述する必要があります。

まずは、インターフェースファイルにプロトコルの設定を行います。

ViewController.h
 【変更前】

@interface ViewController : UIViewController <UIWebViewDelegate>

【変更後】

@interface ViewController : UIViewController <UIWebViewDelegateUITextFieldDelegate>


次に、キーボードのreturnキーが押された時に、呼ばれるメソッドを以下の通り、ViewController.mに実装していきます。

ViewController.m
// UITextFieldのキーボード上の「Return」ボタンが押された時に呼ばれる処理

- (BOOL)textFieldShouldReturn:(UITextField *)sender {

    //キーボードの入力値を取得

    NSString *keyboardInput = sender.text;

    //http://」で始まるかを確認、もし始まらない場合は追加

    if (![keyboardInput hasPrefix:@"http://"]) {

        NSString *prefix = @"http://";

        url = [prefix stringByAppendingString:keyboardInput];

        sender.text = url;

    } else {

        url = keyboardInput;

    }

    // キーボードを閉じる

    [sender resignFirstResponder];

    

    //指定されたページをロード

    [self makeRequest];

    

    return TRUE;

}



ここで、着目すべきは、キーボードからの入力があった際に、文字列を処理しているところです。Web Viewでウェブページを表示するためにURLを渡す時、必ずURLの先頭に「http://」が含まれている必要があります。一方で、ユーザーの中には「http://」を省略する人も少なくはありません。そこで、このメソッドの中では、入力された文字列を検査し、先頭に「http://」が含まれない場合は追加するようにしています。

このメソッドが正しくよばれるためには、もうひとつ施すべき処理があるのですが、それは後ほど処理を記述する際に説明します。

お気に入りの追加

次は、お気に入りの追加処理を実装していきます。差し当たり、画面上の「お気に入り追加」ボタンに紐付くIBAction型のメソッドを実装していきます。

なお、お気に入りが追加されるときに、SQLiteデータベースにアクセスし、追加を行うクエリ文を発行します。これにより、「favorites.sqlite3」に含まれる「my_favorites」というテーブルに新たなお気に入り項目が追加されます。

それでは、View Controller.mに以下のコードを記述してください。

ViewController.m
//お気に入り追加ボタンが押され時の処理

-(IBAction)saveFavorite:(id)sender {

    //新しいページをロード中はお気に入り登録を禁止

    if (loadSuccessful == false) {

        //エラーメッセージを表示

        UIAlertView *alert = [[UIAlertView allocinit];

        alert.title = @"エラー";

        alert.message = @"正常にロードされていません";

        [alert addButtonWithTitle:@"OK"];

        [alert show];

        

        return;

    }

    //Databaseを開く

    FMDatabase* db = [FMDatabase databaseWithPath:databasePath];

    [db open];

    //クエリ文を指定

    NSString *query = [NSString stringWithFormat:@"INSERT INTO my_favorites (title, url) VALUES ('%@','%@');", pageTitleurl];

    //クエリ開始

    [db beginTransaction];

    //クエリ実行

    [db executeUpdate:query];        

    //Databaseへの変更確定

    [db commit];        

    //Databaseを閉じる

    [db close];

    //メッセージを表示

    UIAlertView *alert = [[UIAlertView allocinit];

    alert.title = @"お気に入り登録完了";

    alert.message = [NSString stringWithFormat:@"%@」を登録しました", pageTitle];

    [alert addButtonWithTitle:@"OK"];

    [alert show];

}


このメソッドでは、現在表示されているページがお気に入りとして登録される仕組みになっています。登録が行われる条件として、ページが正常にロードされていることを冒頭でチェックしています。

正常にロードされたことが確認できたら、SQLiteデータベースにアクセスし、クエリ文を発行することで、お気に入りを追加しています。SQLiteデータベースへの追加が終わったら、その旨をUIAlertViewで通知するようになっています。

お気に入り画面への遷移

次に、お気に入り画面への遷移を行うメソッドを、「お気に入り」ボタンと紐付くIBAction型のメソッドとして実装します。また、その中でSegueを発動させるメソッドも併せて記述します。
以下のようにViewController.mに記述していきます。

ViewController.m
-(IBAction)goToFavorites:(id)sender {

    //お気に入り画面へのSegueを始動

    [self performSegueWithIdentifier:@"toFavoritesView" sender:self]; 

}


//お気に入り画面へのSegueの発動

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

    

    //FavoritesViewControllerFVC)のインスタンスを作成し、

    //delegate通知をこのクラスで受けれるようにする

    if ([[segue identifierisEqualToString:@"toFavoritesView"]) {

        FavoritesViewController *fvc = (FavoritesViewController*)[segue destinationViewController];

        fvc.delegate = (id)self;

    }

}


お気に入り画面から戻った後の処理

ここでは、今まで扱ってきた、Segueを発動させるメソッドを呼び出しています。しかし、このままでは、お気に入り画面が閉じられた時に、ユーザーによって選択されたお気に入りサイトのURLを受け取る術がありません。

そこで、Favorites View Controllerからのデリゲート通知によって呼ばれるメソッド実装していきます。

その前に、ViewController.hに、Favorites View Controllerのプロトコルの設定を施す必要があります。

ViewController.h
 【変更前】

@interface  ViewController : UIViewController <UIWebViewDelegateUITextFieldDelegate >

【変更後】

@interface ViewController : UIViewController <UIWebViewDelegateUITextFieldDelegate,FavoritesViewControllerDelegate>


プロトコルの設定が終わったら、以下のようにViewController.mに実際のメソッドを記述していきます。

ViewController.m
//Favoritesのリストで「戻る」が押された

- (void)favoritesViewControllerDidCancel:(FavoritesViewController *)controller {

    //Favorites View Controllerを閉じる

[self dismissViewControllerAnimated:YES completion:nil];

}

//Favoritesのリストで何かが選択された時に呼ばれる

- (void)favoritesViewControllerDidSelect:(FavoritesViewController *)controller withUrl:(NSString *)favoriteUrl {

    //セレクトされたURLをロード

    url = favoriteUrl;

    [self makeRequest];

    //Favorites View Controllerを閉じる

[self dismissViewControllerAnimated:YES completion:nil];

}


お気に入り画面上の「戻る」ボタンが押されたとき、Delegate通知がなされ、ここで実装した「favoritesViewControllerDidCancel」が呼ばれます。同様に、お気に入り画面上のTable Viewからお気に入りが選択された際は、ここで実装した「favoritesViewControllerDidSelect」が呼ばれます。その際、引数として、選択されたお気に入り項目のURLが渡されるので、それをロードします。

View Controllerの初期処理

View Controllerの初期処理を行います。そこで、ViewController.mの中の、「ViewDidLoad」メソッドを以下のように編集します。

ViewController.m
- (void)viewDidLoad {

    [super viewDidLoad]; 

    //webViewtextFieldからのdelegate通知をこのクラスで受け取る

    webView.delegate = self;

    urlField.delegate = self;

    

    //データベースのファイルパスを取得

    databaseName = @"favorites.sqlite";    

    NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMaskYES);

    NSString *documentDir = [documentPaths objectAtIndex:0];

    databasePath = [documentDir stringByAppendingPathComponent:databaseName];

    

    //サンドボックス内の「Documents」にDBがあるかを確認、無ければコピー

    [self createAndCheckDatabase];

    //初期URLを設定

    url = @"http://www.google.co.jp";

    //初期URLのページを要求・表示

    [self makeRequest];

}


ここではまず、Text FieldとWeb ViewからのDelegate通知をそれぞれView Controllerで受け取れるようにするために、以下のような記述がなされています。

//webViewtextFieldからのdelegate通知をこのクラスで受け取る

webView.delegate = self;

urlField.delegate = self;


また、冒頭で説明したように、データベースの名前とファイルの場所を示す、「databaseName」と「databasePath」を設定しています。その後、サンドボックス内にデータベースのコピーが存在するかどうかを確認した上で、無ければコピーを作成するメソッドを呼び出しています。

最後に、最初のホームページ(ここでは「http://www.google.co.jp」を指定)を呼び出しています。

UI画面とコードの関連付け

ここまでで、基本的にコードの記述は全て完了となります。そこで、これまでに設置したUI画面上の部品とコード上の処理を関連付けます。

ブラウザー画面の関連付け

まずは、ブラウザー画面のWeb Viewから関連付けます。以下の通り、Web ViewそのものはView Controllerの中の「webView」と関連付けます。さらに、「Received Actions」以下の「goBack」、「goForward」、「reload」、「stopLoading」の4つをそれぞれ画面下部の「戻る」、「進む」、「更新」、「中止」ボタンと関連付けます。



次に、アドレスバーのText FiledをView Controllerの「urlField」と関連付けます。このとき、Text Fieldを選択する際、確実にText Fieldを選択するために、Document OutlineからText Fieldを右クリックしましょう。



同様に「お気に入り追加」ボタンのセレクタをView Controllerの中の「saveFavorite」と関連付けます。


最後に、同様の手法で「お気に入り」ボタンのセレクタをView Controllerの中の「goToFavorites」と関連付けます。


お気に入り画面の関連付け

ここでは、お気に入り画面の関連付け作業をやっていきます。
まずはTable Viewの「dataSource」と「delegate」をFavorites View Controllerに設定します。



次に、「戻る」ボタンのセレクタをFavorites View Controllerの「back」と関連付けます。


ビルドと動作試験

これにて、すべての作業は完了となります。編集内容を全て保存し、ビルドを行なってください。このテキストの内容をすべて正しくやった場合、特に問題なくアプリが動作するはずです。

まず、起動時にGoogleのホームページが表示されることを確認して下さい。その後、手動でURLを入力したり、リンクをクリックしたりしながら、適宜ウェブを閲覧しつつ、適当なタイミングでお気に入り追加ボタンを押し、お気に入り登録が完了することを確認して下さい。また、「戻る」や「進む」などのボタンが動作することも確認しましょう。

お気に入り画面からは、これまで登録したサイトの一覧が表示され、Table Viewのアイテムをクリックすると、ブラウザー画面に表示されることを確認して下さい。

まとめ

第8講では、Web Viewの扱い方やSQLiteを用いたリレーショナルデータベースの紹介を行いました。それらを元に、Safariのようなウェブブラウザーを独自に作成しました。

今回のアプリはDelegate通知や独自のプロトコルの設定等、色んな要素が重なりあっているため、難易度が多少高くなっています。一方で、ここに書かれている内容を理解できれば、iOSやObjective-Cの仕組みをマスターしたレベルまでになったといえるでしょう。もし、わかりにくいと思った場合は、ソースコードを今一度見直し、復習するようにしてください。

次回は少し方向性を変え、位置情報センサーや加速度計を扱っていきます。引き続き、頑張って行きましょう。
Comments