Swift:メモ　RSSを使ったテーブルアプリ



```swift
import UIKit
class ListViewController: UITableViewController,XMLParserDelegate{//uitableviewcontrollerはdatasourceやdelegateも批准している
  var parser:XMLParser!//rssデータを解析するためのXMLParserクラスのインスタンスを格納するためのプロパティ
  var items = [Item]()//複数の記事を格納するための配列
  var item:Item?//Itemクラス型のプロパティ　Itemクラスはタイトルと本文のURLの2つのプロパティを持つ
  var currentString = ""
  //セルの個数
  override func tableView(_ tableView:UITableView,numberOfRowsInSection section:Int) -> Int {
    return items.count
  }
  //tableView:cellForRowAtはセルの内容をiPhoneに知らせるメソッド　セルの内容を戻り値に設定
  //indexPathにはtableView:cellForRowAtメソッドが設定を行っているセルの行番号が保持されている
  //IndexPathにはsectionとrowのプロパティが含まれている
  override func tableView(_ tableView: UITableView,cellForRowAt indexPath: IndexPath) -> UITableViewCell{
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    cell.textLabel?.text = items[indexPath.row].title
    //瞬時に表示するために大量のセルを作成しなくて済むようにセルの再利用を設定322
    //dequeueReusableCell(withIdentifier:for)メソッドを使う場合、引数にどのセルを再利用するか指定する→セルを選択した状態でのIdentifier項目の名前Cellが第一引数
    return cell
  }
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    startDownload()
  }
  //データのダウンロード startDownload()はオリジナルのメソッド
  func startDownload(){
    self.items = []//itemsを空にする、古いデータが残ったままダウンロードすると重複する記事が生まれてしまう
    if let url = URL(
    string: "https://aaaaaa.com/rssfeeder/"){//ニュース記事のあるwebサイトのURLを指定
      if let parser = XMLParser(contentsOf: url)//parserのインスタンスを作成　前の行で指定したURLを引数に　不正なURLが検出された時nilを返すことがあるのでメソッドの戻り値はオプショナル型
        {
        self.parser = parser
        self.parser.delegate = self
        self.parser.parse()
        //parserのデリゲートにselfを指定して最期にparserメソッドを呼び出すことでデータの解析を開始
      }
    }
  }
  func parser(_ parser: XMLParser,didStartElement elementName: String,namespaceURI:String?,qualifiedName qName: String?,attributes attributeDict:[String : String])
    //要素感の開始タグが見つかるごとに呼び出される　ダウンロードされた記事から必要なデータだけ取り出す処理を行うメソッド XMLParserDelegateで宣言されているメソッド
  {
    self.currentString=""//要素を一時的に保存する変数currentStringを空に　古い文字列が入らないように
    if elementName == "item"{//要素名がitemの場合のみニュース記事を入れる箱itemを作る
      self.item = Item()
    }
  }
  //タグで囲まれた要素を取り出す　内容が見つかると自動的にこのメソッドが呼び出される　メソッドの中に文字列を取り出す処理を書く
  func parser(_ parser: XMLParser, foundCharacters string: String) {
    self.currentString += string//引数stringには見つかった記事の内容が格納されている　引数の中身を変数currentStringに+=演算子を使って追加　この段階ではcurrentStringにどの要素名の内容が入っているかは不明
  }
  //要素名が終わる</items>が見つかると以下のメソッドが自動的に呼び出される
  func parser(_ parser: XMLParser,
        didEndElement elementName:String,//elementNameに要素名を格納
        namespaceURI:String?,
        qualifiedName qName:String?){
    switch elementName{//switch文の条件にelementNameを指定することで要素名ごとに処理が行われる
      //要素名がtitleの時はitem.titleに内容を格納　linkも同じ
    case "title":self.item?.title = currentString
    case "link":self.item?.link = currentString
    case "item":self.items.append(self.item!)//要素がitemの場合はニュース記事の終わりを意味するのでこれまで取得したデータをitemsの中に格納 append=追加する
    default : break
    }
  }
  //テーブルビューの内容を更新することで取得した記事を画面に表示
  func parserDidEndDocument(_ parser:XMLParser){
    self.tableView.reloadData()
  }
  override func prepare(for segue:UIStoryboardSegue, sender:Any?){
    if let indexPath = self.tableView.indexPathForSelectedRow{//ユーザーがタップしたセルのindexPathを取得
      let item = items[indexPath.row]//取得した値を用いてitem配列から該当する記事を取得
      let controller = segue.destination as! DetailViewController//controller定数に遷移先のビューコントローラーを格納
      controller.title = item.title//titleプロパティに記事タイトルを格納
      controller.link = item.link
    }
  }
}



```

## Swiftのお役立ち情報

https://wagtechblog.com/programing/swift-iphone-application-school

https://wagtechblog.com/programing/swift-textbook.html