RSSリーダー

講義の目標

  • サーバ連携(HTTP通信、バックグラウンド処理、JSONパース)を理解すること
  • TableViewの基本的な使い方を理解すること
  • WebViewが使えるようになること

はじめに

今回のアプリはRSSリーダーとなります。RSSリーダーは最新のYahoo!ニュースの一覧を取得し、見出しをユーザーに提示するアプリです。ユーザーは見出しをクリックすることで、ニュースの本文を提示する画面を画面遷移を行い、WebViewで表示するところまで実装します。

完成品のサンプルは以下よりダウンロードできます。イメージが湧かない方は是非ご確認ください。

iOS完成品サンプル(RSSリーダー)

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

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

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

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

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

入力項目 入力値
Product Name RSSReader
Team None
Oganization Name 任意(”ALJ”など自分が所属している組織の名前を入れる)
Oganization Identifier jp.co.al-j
Language Swift
Devices iPhone
Use Core Data チェックを外す
include Unit Tests チェックを外す
include UI Tests チェックを外す

アプリの設定

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

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

素材ダウンロード

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

ファイル名 説明
iphone-icon-60@2x.png アイコンx2画像
iphone-icon-60@3x.png アイコンx3画像
iphone-setting-29@2x.png 設定x2画像
iphone-setting-29@3x.png 設定x3画像
iphone-spotlight-40@2x.png Spotlight用x2画像
iphone-spotlight-40@3x.png Spotlight用x3画像
splash-iphone-2x.png スプラッシュ画像x2画像
splash-iphone-ios7-retina4.png スプラッシュiOS7画像
splash-iphone-ios8-47.png スプラッシュiOS8画像 4.7インチ画像
splash-iphone-ios8-55-portrait.png スプラッシュiOS8 5.5インチ画像

アイコン設定

画像素材のiconフォルダの中のアイコン画像をプロジェクトに取り込んでください。

スプラッシュ画像設定

画像素材のsplashフォルダの中のスプラッシュ画像をプロジェクトに取り込んでください。

サポートするデバイスの向きの設定

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

Bundle Nameの設定

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

入力項目 入力値
Bundle Name RSS Reader

CocoaPodsの利用

今回作成するアプリのYahoo!ニュースの情報を取得するためにはHTTP通信を行い、バックグラウンドにてJSON形式で記載されたファイルをパース(解析)する必要があります。
今回、JSON形式で記載されたファイルをパース(解析)するために、「Alamofire」というライブラリを使用します。

前回と同様の手順で「Alamofire」というライブラリをCocoaPodsを使ってインストールしていきます。

「RSSReader」のXcodeプロジェクトフォルダをターミナルにドラッグしてください。

次にそのままターミナルに下記のコマンドを入力し、Enterキーを押します。

pod init

するとRSSReaderフォルダの中にPodfileが作成されています。

次にお使いのエディターで先ほど作成した「Podfile」を開いてください。
※ Xcodeで開いても構いません。

「Podfile」を開きましたら、既に記述しているものを削除して、下記の内容を入力してください。

Podfile

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '10.0'
use_frameworks!

target 'RSSReader' do
pod 'Alamofire', '~> 4.0'
end

入力が終わりましたら保存し、ターミナルで以下のコマンドを入力し、Enterキーを押してください。

pod install

これで今回使うライブラリの「Alamofire」を導入できました。
CocoaPodsでの作業は以上になります。

ここで1つ注意することがあるのですが、CocoaPodsを使用したアプリを開く場合、CocoaPodsが自動でファイルを作成した中に「RSSReader.xcworkspace」というファイルが作成されていると思います。

今後、CocoaPodsを利用した場合は、こちらのファイルを開いて作業を行いますので、「RSSReader.xcworkspace」を開いてください。

Xcodeが起動するとPodsというプロジェクトが追加され、今回利用するライブラリが追加されている事が確認できます。

それでは、引き続き今まで同様にストーリーボードで画面を作成していきます。

画面のデザイン

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

ニュースリーダー画面の作成

今回作成するアプリはニュースリーダーを表示する画面と記事の詳細を表示する画面の2画面構成なのでまずはニュースリーダーの画面から作成していきます。ViewControllerクラスはViewController.swiftを使いまわせますのでそのまま使っていきます。

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

Bar Button Itemの設置

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

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



この後、Navigation Barのタイトルを「Yahoo! 最新ニュース」に変更します。現状で「Title」と書かれている所をダブルクリックし、書き換えます。

Table Viewの設置

次に、Table Viewを設置します。ライブラリーエリアからTable Viewを選択し、画面を一杯に広げます。

次に、セルのフォーマットをカスタマイズします。
まず、TableViewを選択した状態で、Protootype Cellsを「1」にします。

今回は、「Prototype Cells」と記されたエリアに2つのラベルを配置します。同時にセルの大きさも少し広げます。

次に、これら2つのラベルにTag番号を設定します。まず、「タイトル」と書かれたラベルを選択し、インスペクターから以下のとおり、Tag番号を「1」とします。

同様に、「時刻」と書かれたラベルも同じようにTag番号を設定します。こちらのラベルのTag番号は「2」とします。

最後に、セルそのものに、Identifierを「NewsCell」に設定します。

Auto Layoutの設定

次にニュースの詳細画面の作成を行います。

ニュース詳細画面の作成

ニュースリーダー画面のデザインが完了したら、ニュース詳細画面のデザインに移ります。初期状態では1画面分のViewしか含んでいません。そこで、ニュース詳細画面用のViewControllerをStoryboard上に新規追加します。ライブラリーエリアよりView Controllerを選び、Storyboard上に配置します。

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

Bar Button Itemの設置

その次に、「戻る」ボタンをNavigation Bar上に設置します。ここでもBar Button Itemを利用します。

次に、「戻る」ボタンの見た目を変更します。ボタンを選択した上で、インスペクターから、「Title」というところに「戻る」と入力してください。


この後、Navigation Barのタイトルを「ニュース詳細」に変更します。現状で「Title」と書かれている所をダブルクリックし、書き換えます。

Web Viewの配置

次に、Web Viewを設置します。ライブラリーエリアからWeb Viewを選択し、画面を一杯に広げます。

Auto Layout設定

NewsDetailViewControllerクラスファイルの作成

まずは、ニュース詳細画面用のView Controllerクラスから作成します。ナビゲーターエリアの中にある、「RSSReader」と書かれたフォルダを右クリックし、「New File…」メニューをクリックします。

ここで新規ファイル作成のダイアログが表示されるので、「 Cocoa Touch class」を選択し、「Next」をクリックします。

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

入力項目 入力値
Class NewsDetailViewController
Subclass of UIViewController
Also create XIB file チェックを外す
Language Swift

そうすると、ナビゲーターエリアの一覧に今回作成したNewsDetailViewControllerクラス(NewsDetailViewController.swift)が表示されます。

新規View Controllerのアサイン

次に、新たに作ったNews Detail View ControllerをViewにアサインします。

まずは、Storyboard上で先ほど追加した「View Controller」をクリックし、画面全体を選択します。次に、インスペクターを開き、以下のメニューから「NewsDetailViewController」を選びます。

正しくアサインできたことを確認するために、Storyboardをズームアウトしてください。新しくアサインしたView Controllerの名前が表示されていればOKです。

Storyboard Segueによる画面遷移

Storyboard Segueの設定

今回は、以下の2つの画面遷移があるので、それぞれに対してStoryboard Segueを設定していきます。

  • ニュースリーダー画面 → ニュース詳細画面
  • ニュース詳細画面 → ニュースリーダー画面

ニュースリーダー画面からニュース詳細画面

ここではデータの受け渡しが伴う画面遷移を行うため、ViewController同士を接続します。

遷移元の画面(ViewController)上部の白いバーにあるView Controllerのアイコンをクリックします。
そのまま「Control」キーを押し続けながら、マウスを遷移先の画面(ニュース詳細画面)にドラッグし、マウスを離します。

その後現れるポップアップから「Present Modally」を選択します。

ここまでの作業を正しく行った場合、以下のようにニュースリーダー画面とニュース詳細表示画面を結ぶ矢印が表示されます。このSegue(矢印)をクリックし、インスペクターを開き、Identifier(識別子)を付けましょう。識別子は「toDetailView」とします。

ニュース詳細画面からニュースリーダー画面

次に、ニュースの詳細を見終わったら、ニュースリーダー画面へ戻れるように、Segueを設定します。まず最初にもとに戻りたいViewControllerに以下の記述を行います。ここではViewController.swiftに記述します。

ViewController.swift

@IBAction func backView(segue: UIStoryboardSegue) {

}

次に、ニュース詳細画面のナビゲーションバー上に「戻る」ボタンを設置したかと思いますが、このボタンに対してSegueを設定します。キーボード上の「Control」キーを押しながら、ViewController上のExitというボタンにドラッグしてください。

すると先ほど作成したメソッドが表示されていると思いますのでそれを選択してください。
これで元に戻るための接続が完了しました。

これにて、全てのStoryboard Segue(画面遷移)の設定は完了となります。

UIオブジェクトをコードと結びつける

Main.storyBoardとコードをアシスタントエディタで接続します。

これにて、画面デザインは完了となります。

RSSとHTTP通信

今回は、「RSSリーダー」を作成しますが、そもそもRSSとは何でしょうか?知っている方も多いかもしれませんが、知らない方のために少し解説します。

RSSの概要

簡単に説明すると、RSSとは、ニュースやブログなど各種のウェブサイトの更新情報を簡単にまとめ、配信するための幾つかの文書フォーマットの総称です。このフォーマットは標準化されていて、様々なウェブサイトで採用されています。

ユーザーはFeedly等のアプリを使い、これらを集め、最新のニュース等を網羅的に見ることができます。また、iOSやAndroidアプリとしても、シンプルなものから高機能なものまで、様々なRSSリーダーが公開されています。

RSSのフォーマット

RSSのフォーマットですが、今回はファイル形式としてJSON形式で取得します。

JSONファイルとは、JavaScript Object Notation(ジャバスクリプト オブジェクト ノーテイション)の略称で、JavaScriptにおけるオブジェクトの表記法を応用したデータ形式で、
JSONで表記されたデータは、JavaScript上ではコードとして実行するだけで読み込みができ、処理できます。
JSONファイルはこのように{}で括った中にKey値とValue値をコロン:で挟んで定義できます。
このように{}で括った中にKey値とValue値をコロン:で挟んで定義できます。

{
"id": "114",
"title": "ブログ記事タイトル",
"category": "sports",
"updated": "2014-05-28 10:57:45"
}

このようにKey値とValue値がわかりやすく書かれていて、容量も比較的軽いため、今もっとも利用されている形式の1つです。

今回は、このようなRSSフィードを実際にiOSアプリ上から取得し、解析し、Table View上に見やすく列挙します。

HTTP通信

HTTP通信は、Webサイトを閲覧する時に使用する通信方式です。HTTP通信は、昨今のインターネット通信において、最も利用されている方式であるといっても、過言ではないでしょう。

今回もRSSフィードを取得するにあたって、このHTTP通信を利用します。詳しい動作の仕組みの説明は割愛しますが、興味のある方はぜひ調べてみてください。

バックグラウンド処理

今回扱うHTTP通信の速度は、データの大きさやインターネット回線の状況に左右されます。故に、大幅な遅延も容易に想定できます。

特段説明はしませんでしたが、これまで様々な処理を実装して実行する際、フロント側(UIスレッド)で行うようにコードを記述してきました。基本的には、これで問題はないのですが、HTTP通信等、時間のかかってしまう処理をフロント側でやってしまうと、処理が修了するまでは、あたかもアプリが壊れたかのように固まってしまいます。

そこで、このように時間のかかる処理はバックグラウンド側(別スレッド)で処理する必要があります。詳しい技術的な説明は割愛しますが、レストランで食事を注文した後、料理が完成するまでは、お客さんが談笑できるように、料理そのものは裏手の厨房で行われます。それと同じように、プログラミングにおいても、「重たい処理は見えないところでやる」というイメージを持ってもらえれば結構です。このような処理方式を「非同期処理」といいます。

Alamofireライブラリ

今回は、このJSONファイルをHTTP通信によって取得し、解析するにあたって、「Alamofire」という外部ライブラリーを使用します。このライブラリーは非同期のHTTP通信を用いて、所定のJSONファイルを取得し、解析するところを担当してくれる非常に優れたライブラリーです。Alamofireライブラリーの使用法は、コーディングをする段階で解説します。

HTTP通信やJSONの解析処理などは自分で実装することも可能ですが、非常に複雑で煩雑なコーディングが伴います。そこで、自分のアプリを作成するときも、このような外部ライブラリーを積極的に活用していきましょう。

コードの記述

ここでは、「RSSリーダー」のコードの記述をしていきます。

Newsクラスの実装

まずは、ニュースのタイトルやリンク、日時等を包括的に扱うNewsクラスの実装から行います。

新規クラスの作成

これまでと同じ方式で、Xcode上で「News」というCocoa Touch classの新規クラスを作成しましょう。
正しく行った場合、News.swiftというファイルが出来上がるはずです。

Newsクラスのコーディング

Newsクラスは、包括的にニュース記事の情報を扱うための非常にシンプルなクラスです。以下のとおり、メンバー変数を宣言を行います。

News.swift

class News: NSObject {
// ▼▼ 追加 ▼▼
var title = String()
var url = String()
var date = String()
// ▲▲ 追加 ▲▲
}

View Controllerのコーディング

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

メンバー変数の宣言

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

ViewController.swift

class ViewController: UIViewController {
@IBOutlet weak var table: UITableView!
// ▼▼ 追加 ▼▼
//最新ニュースを格納する配列
var elementList = NSMutableArray()
//NewsDetailViewControllerに渡すURL
var urlForDetailView = NSURL()
// ▲▲ 追加 ▲▲

ここでAlamofileを利用するために、ViewController.swift以下の記述をします。

ViewController.swift

import UIKit
//////////////// ▼▼ 追加 ▼▼ ////////////////
import Alamofire
//////////////// ▲▲ 追加 ▲▲ ////////////////

JSONの取得

まずはJSONを取得する処理を実装します。以下の通り、ViewController.swiftにメソッドを記述して下さい。

ViewController.swift

// ▼▼ 追加 ▼▼
//HTTP通信を利用してJSONを取得
func getJSON() {
let urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.dailynews.yahoo.co.jp/fc/rss.xml&num=8"

//ステータスバーのActivity Indicatorを起動
UIApplication.shared.isNetworkActivityIndicatorVisible = true

//AlamofireでバックグランドでのJSON取得
Alamofire.request(urlString, method: .get, parameters: nil, encoding: JSONEncoding.default, headers: nil).responseJSON { (response:DataResponse<Any>) in
switch(response.result) {
case .success( _):
//成功時のコールバック処理
print("\(urlString)の取得に成功しました")
case .failure( _):
//失敗時のコールバック処理
print("\(urlString)の取得に失敗しました")
}
}
}

// ▲▲ 追加 ▲▲

まず、Yahoo! ニュースの最新記事のRSSフォードを取得するためのURLは、以下のとおりです。

http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.dailynews.yahoo.co.jp/fc/rss.xml&num=8

Alamofireのrequestメソッドで、URLの文字列を引数として「GET」で呼び出します。これによって、非同期のHTTP通信が行われ、所定のJSONファイルがdataに格納されます。この際、switch文でエラー分岐をして失敗したらなにもしないで、成功したらJSONをパースする処理を行います。

ここでswitch文で分岐した理由はもしこの分岐がない場合、JSONがもし取得できなかった場合、アプリが異常終了で落ちてしまいます。HTTP通信をする場合はネットに繋がっていないとできませんし、通信先のデータが正常であるとも限りません。そのたびにアプリが落ちてしまうのは、よいアプリとは言えません。そのためにエラーを回避する役割がこのswitch文にあります。

また、JSONを取得中は、画面最上部のステータスバーにNetwork Activity Indicatorを設置します。

これを用いることで、ユーザーにネットワーク通信を行なっていることを示せます。その具体的な手法は以下の通りです。

UIApplication.shared.isNetworkActivityIndicatorVisible = true

JSONの解析処理とTable Viewの更新

JSONは生データのままでは、単純な文字列のままです。これを処理することによって、タグ毎に切り分け、求める情報を抽出していきます。この作業を「パース」といいます。
まずは、以下のとおりViewController.swiftに記述します。

//HTTP通信を利用してJSONを取得
func getJSON() {
let urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.dailynews.yahoo.co.jp/fc/rss.xml&num=8"
//ステータスバーのActivity Indicatorを起動
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
//AlamofireでバックグランドでのJSON取得
Alamofire.request(.GET,urlString).responseJSON {
response in
switch response.result {
case .Success(let value):
//成功時のコールバック処理
print("\(urlString)の取得に成功しました")
// ▼▼ 追加 ▼▼
if let jsonDic = response.result.value as? NSDictionary {
let responseData = jsonDic["responseData"] as! NSDictionary
let responseData2 = responseData["feed"] as! NSDictionary
let entries = responseData2["entries"] as! NSArray
//ニュースの数だけ繰り返し処理を行う
for i in 0 ..< entries.count {
//新しいNewsクラスのインスタンス生成
let n = News()
//nにタイトル・URL・日時を格納
n.title = ((entries[i] as Any) as AnyObject).object(forKey: "title") as! String
n.url = ((entries[i] as Any) as AnyObject).object(forKey: "link") as! String
n.date = ((entries[i] as Any) as AnyObject).object(forKey: "publishedDate") as! String
//nをelementListに追加
self.elementList.add(n)
}
}
//ステータスバーのActivity Indicatorを停止
UIApplication.shared.isNetworkActivityIndicatorVisible = false
//最新の内容にテーブルをセット
self.table.reloadData()
// ▲▲ 追加 ▲▲
case .Failure(let error):
//失敗時のコールバック処理
print("\(urlString)の取得に失敗しました")
// ▼▼ 追加 ▼▼
//ステータスバーのActivity Indicatorを停止
UIApplication.shared.isNetworkActivityIndicatorVisible = false
// ▲▲ 追加 ▲▲
}
}
}

少し長いコードですが、順を追って説明します。その前に、もう一度今回解析するYahoo! ニュースのRSSフィードを見て行きましょう。
今回扱っているYahoo! ニュースのRSSフィードは以下のような、階層構造となっています。

{
    "responseData": {
        "feed": {
            様々なメタ情報
            "entries": [
                {
                    "title": "hoge",
                    "link": "http://hogehoge.com",
                    "publishedDate": "Mon, 13 Jul 2015 06:17:12 -0700",
                    その他情報
                }
                :
                :
            ]
            様々なメタ情報
        }
    }
}

この中から、各「entries」の「title」と「link」、「publishedDate」を得るためには、以下の戦略をとります。

  • responseDataの中身を抜き出し…(ア)
  • (ア)からfeedの中身を抜き出し…(イ)
  • (イ)からentriesの中身を1つずつ抜き出し…(ウ)
  • Newsクラスのインスタンス「n」を生成…(エ)
  • (ウ)からtitleとlinkとpublishedDateを抜き出し、「n」に格納…(オ)
  • 「n」を「elementList」に追加
  • 上記が完了したらtableの内容を更新

以上の「entries」の数だけ、(エ)と(オ)の処理を繰り返します。このように、JSONをパースし、必要な情報をNewsクラスのインスタンスに格納し、ニュースをとりまとめた「elementList」という配列を構築します。

ここでネットワーク通信は完了しているので、ステータスバーのNetwork Activity Indicatorを非表示にするメソッドを呼びます。

UIApplication.shared.isNetworkActivityIndicatorVisible = false

最後にTable Viewを一度更新しないとJSONパースしたデータを反映できないので下記のコードを記述しています。

self.table.reloadData()

これにより、「elementList」に入ったニュースのデータをTable Viewに反映することができます。

TableViewの利用

ここまでの処理で、JSONの取得と解析とTable Viewの更新ができました。次にTable Viewの扱い方を解説します。その前に、Table Viewを利用するための準備を行います。以下のとおり、ViewController.swiftにプロトコルの設定を記述して下さい。

ViewController.swift

【変更前】

class ViewController: UIViewController {

【変更後】

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

次に、Table Viewが表示されるために必要とする3つのメソッドを実装していきます。

ViewController.swift

// ▼▼ 追加 ▼▼
//Table Viewのセクション数を指定
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

//Table Viewのセルの数を指定
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return elementList.count
}

//各セルにタイトルをセット
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//セルのスタイルを標準のものに指定
let cell = tableView.dequeueReusableCell(withIdentifier: "NewsCell", for: indexPath as IndexPath)

//カスタムセル上のラベル
let titleLabel = cell.viewWithTag(1) as! UILabel
let dateLabel = cell.viewWithTag(2) as! UILabel

//セルにお気に入りサイトのタイトルを表示
let f = elementList.object(at: indexPath.row) as! News
titleLabel.text = f.title
dateLabel.text = f.date

return cell
}
// ▲▲ 追加 ▲▲

まず、最初に1つ目のメソッドでテーブルのセクションの数を設定し、2つ目のメソッドでセルの個数を設定します。これらを元に、セルが準備されるので、3つめのメソッドでセルの内容を埋めます。
3つ目のメソッドでセルの内容を埋める際に、Cell のIdentifierを指定している点に着目して下さい。このIdentifierが、Interface Builder上で設定したものとなっています。

let cell = tableView.dequeueReusableCell(withIdentifier: "NewsCell", for: indexPath as IndexPath)

また、タイトルと日時をラベルに流しこむ際に、Tag番号を指定しているところにも着目して下さい。

//カスタムセル上のラベル
let titleLabel = cell.viewWithTag(1) as! UILabel
let dateLabel =  cell.viewWithTag(2) as! UILabel

なおラベルに関してですが、今回はこの段階で、Tag番号を用いた関連付けを行なっているため、Interface Builder上で関連付けを行う必要はありません。

ここで、一点、RSSの標準の日時に形式は、以下の通りとなっています。

Mon, 13 Jul 2015 06:17:12 -0700

RSSフィードでは、世界標準時で日時として記載されます。今回はこの形式のままラベルに表示させますが、余力がある場合、ぜひこれを日本標準時に直してみて下さい。

Table Viewのセル選択時の処理

今回の「RSS」リーダー」では、セルをクリックすると、該当するニュースの本文を記したウェブページをニュース詳細画面のWeb Viewで開くようにしなければなりません。
まずは、セルがクリックされた時に呼ばれるメソッドから記述していきます。以下のように、ViewController.swiftに記述して下さい。

ViewController.swift

// ▼▼ 追加 ▼▼
//リスト中のお気に入りアイテムが選択された時の処理
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

//選択された項目のURL、Titleを参照
let n = elementList.object(at: indexPath.row) as! News
let selectedURL = n.url
//selectedURLは文字列なのでNSURL型に変換
urlForDetailView = NSURL(string: selectedURL)!

//ニュース詳細へのSegueを始動
self.performSegue(withIdentifier: "toDetailView", sender:self)
}
// ▲▲ 追加 ▲▲

ここでは、選択されたセルに該当するニュースのURLとTitleを参照し、NewsDetailViewControllerへURLを渡す準備と画面遷移を行う処理を記述しています。次に、値を渡すためのメソッドを実装します。

ViewController.swift

// ▼▼ 追加 ▼▼
//ニュース詳細画面へのSegueの発動
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetailView" {
//NewsDetailViewController(NVC)のインスタンスを作成し、
//NVCクラスのメンバー変数である「urlToRSSReaderView」に値を渡す
//let nvc = segue.destination as! NewsDetailViewController
//nvc.urlToRSSReaderView = urlForDetailView
}
}
// ▲▲ 追加 ▲▲

ViewControllerの初期処理

ここで、View Controllerの処理を行うべく、「viewDidLoad」の内容を以下の通り編集します。

ViewController.swift

override func viewDidLoad() {
super.viewDidLoad()
// ▼▼ 追加 ▼▼
table.dataSource = self
table.delegate = self
getJSON()
// ▲▲ 追加 ▲▲
}

ここで、JSONの取得、解析、及びTable Viewの更新を行うべく、「getJSON」メソッドを呼びます。

RSSフィードの更新

今のままでは、一度アプリが起動してRSSフォードが読み込まると、更新する手段がありません。そこで、上記で接続した「更新」ボタンが押されたときに呼ばれるIBAction型のメソッドを実装し、更新機能を付け足します。
以下のとおり、ViewController.swiftを指定して下さい。

ViewController.swift

//フィードを更新
@IBAction func refreshList(sender: AnyObject) {
// ▼▼ 追加 ▼▼
//最新のRSSフィードを取得
getJSON()
// ▲▲ 追加 ▲▲
}

「更新」ボタンが押されると、初期処理の時と同様、JSONを取得、解析し、Table Viewを更新する「getJSON」メソッドが呼ばれるようにします。

info.plistの更新

RSSフィードを取得するためにはinfo.plistファイルに下記の内容を追加する必要があります。
下図のようにinfo.plistで右クリックし、Open As -> Source Codeをクリックします。
そうすると、info.plistの中身であるXML形式のファイルがエディタエリアに表示されますので下記を追加します。

    <key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
// ▼▼ 追加 ▼▼
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>secure.example.com</key>
<dict>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<false/>
</dict>
</dict>
</dict>
// ▲▲ 追加 ▲▲
</dict>
</plist>

この段階でRunして実行してみましょう。下記のようにYahooニュースの情報がTableViewに表示されていればOKです。

News Datail View Controllerのコーディング

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

メンバー変数の宣言

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

NewsDetailViewController.swift

class NewsDetailViewController: UIViewController {
@IBOutlet weak var detailWebView: UIWebView!
// ▼▼ 追加 ▼▼
//ViewControllerから受け取るURL
var urlToRSSReaderView = NSURL()
// ▲▲ 追加 ▲▲

今回はウェブページを表示するにあたって、UIWebViewクラスを用います。このクラスは、iOSアプリ上に任意のウェブページを簡単に表示することを可能にします。またニュースリーダー画面からURLを受け取るための変数を用意しておきます。

WebView上にウェブページを表示

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

NewsDetailViewController.swift

// ▼▼ 追加 ▼▼
//ページを要求・表示
func makeRequest() {
//Web Viewでウェブページを呼び出す
let urlReq = NSURLRequest(url: urlToRSSReaderView as URL)
datailWebView.loadRequest(urlReq as URLRequest)
//Activity Indicator発動
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
// ▲▲ 追加 ▲▲

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

その前に、プロトコルの設定を行います。以下の通り、NewsDetailViewController.swiftを編集して下さい。

NewsDetailViewController.swift

【変更前】
class NewsDetailViewController: UIViewController {

【変更後】
class NewsDetailViewController: UIViewController, UIWebViewDelegate {

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

NewsDetailViewController.swift

// ▼▼ 追加 ▼▼
//webロードが正常に完了
func webViewDidFinishLoad(_ webView: UIWebView) {
//ステータスバーのActivity Indicatorを停止
UIApplication.shared.isNetworkActivityIndicatorVisible = false
print("Webロードが正常に行われました")
}

// Web Viewロード中にエラーが生じた場合
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
//ステータスバーのActivity Indicatorを停止
UIApplication.shared.isNetworkActivityIndicatorVisible = false
print("Web Viewロード中にエラーが生じました")
}

// ▲▲ 追加 ▲▲

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

ページのロードに成功した場合、コンソール上に「Webロードが正常に行われました」と出力され、ロードに失敗した場合は、コンソール上に「Web Viewロード中にエラーが生じました」と出力されます。

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

News Detail View Controllerの初期処理

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

NewsDetailViewController.swift

override func viewDidLoad() {
super.viewDidLoad()
// ▼▼ 追加 ▼▼
datailWebView.delegate = self
//ニュースリーダー画面から送られてきたURLのページを要求・表示
makeRequest()
// ▲▲ 追加 ▲▲
}

最後にViewController側で画面遷移するタイミングでエラーを回避するためにコメントしてあった部分を解除します。

ViewController.swift

//ニュース詳細画面へのSegueの発動
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toDetailView" {
//NewsDetailViewController(NVC)のインスタンスを作成し、
//NVCクラスのメンバー変数である「urlToRSSReaderView」に値を渡す
// ▼▼ コメント解除 ▼▼
let nvc = segue.destination as! NewsDetailViewController
nvc.urlToRSSReaderView = urlForDetailView
// ▲▲ コメント解除 ▲▲
}
}

ステータスバーの非表示

ステータスバーを表示しないように設定します。

GeneralタブのDeployment lnfoHide status berにチェックを入れます。

infoタブのCostom iOS Target Propertiesへ以下の設定を追加します。

Key Value
view controller-based status bar appearance No

ここまでで作業は完了しましたので、実際に動かしてみましょう。

ビルドと動作試験

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

起動時にRSSが正常に取得され、Table Viewのリスト上に表示されることを確認して下さい。また、セルをクリックすると、画面遷移をし、ニュース詳細画面にてニュースのページが表示されることも確認して下さい。また戻るボタンを押し、ニュースリーダー画面へ戻れることを確認してください。さらに、少し時間を置き、「更新」ボタンを押すと新しいニュースがロードされることも確認して下さい。

まとめ

今回は、RSSやJSON、HTTP通信、非同期処理の概念を得るとともに、Alamofireライブラリーを用いたJSONの取得と解析(パース)を学びました。また、Table Viewの利用法やWeb Viewを用いたWebページの表示等を取り扱いました。

今回扱った内容も、実際の開発でよく使われているテクニックばかりです。JSONの取得やパース等の具体的なテクニックも重要ですが、今後アプリを作成する上で、外部ライブラリーの使用や、非同期通信の概念の理解も大切となってきます。この際に、理解を深めるようにしましょう。