[Swift 1.1] swiftで api を叩いて、JSONをパースして、表示させる方法 (xcodeは6.1, iOSは8.1)

More than 1 year has passed since last update.

対応バージョン

swift 1.1
xcode 6.1
iOS 8.1

目標

「yahooニュースのRSSをJSONで配ってるapiを叩いて、JSONデータをゲトして、テーブルでひ項目表示させて、セルをタップしたらwebViewで元記事が見れる」ところまで実装。

Playgroundでやってみました。

import UIKit
import XCPlayground

//make URL of google feed api
var urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml&num=8"
var url = NSURL(string: urlString)

//download by NSSession
var task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler:{data, response, error in
    //convert json data to dictionary
    var dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

    println(dict)
})

task.resume()

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

Screen Shot 2014-11-13 at 15.43.38.png

とりあえずこんな感じでゲトできる。

titleだけ表示させてみる

import UIKit
import XCPlayground

//make URL of google feed api
var urlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml&num=8"
var url = NSURL(string: urlString)

//download by NSSession
var task = NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler:{data, response, error in
    //convert json data to dictionary
    var dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

    //get responseData, feed, entries
    var responseData = dict["responseData"] as NSDictionary
    var feed = responseData["feed"] as NSDictionary
    var entries = feed["entries"] as NSArray

    //extract entries
    for entry in entries {
        println(entry["title"])
    }

    println(dict)
})

task.resume()

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)

Screen Shot 2014-11-13 at 15.38.41.png

できた!!

テーブルで表示させてみる

playgroundを離れ、普通のアプリ制作のフローでいきます。

細かいところは一旦置いといて。

import UIKit

class ViewController: UITableViewController {

    //array of entries
    var entries = NSArray()
    let newsUrlString = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&q=http://rss.itmedia.co.jp/rss/2.0/news_bursts.xml&num=8"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //count cell of table view
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return entries.count
    }

    //make tableView
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        //get cell
        var cell = tableView.dequeueReusableCellWithIdentifier("news") as UITableViewCell

        //get entry
        var entry = entries[indexPath.row] as NSDictionary

        //set title
        cell.textLabel.text = entry["title"] as? String

        return cell
    }

    //make reload button
    @IBAction func refresh(sender: AnyObject) {
        let url = NSURL(string: newsUrlString)!

        var task = NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: {data, response, error in
            // conver json to dictionary
            var dict = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary

            // get responseData entries
            if var responseData = dict["responseData"] as? NSDictionary {
                if var feed = responseData["feed"] as? NSDictionary {
                    if var entries = feed["entries"] as? NSArray {
                        // set array of entries
                        self.entries = entries
                    }
                }
            }
            //switch to main thread to relad table view
            dispatch_async(dispatch_get_main_queue(), {
                //reload table view
                self.tableView.reloadData()
            })
        })
        task.resume()
    }
}

はじめにビルドすると、、、

Screen Shot 2014-11-13 at 16.07.34.png

リロードボタンを押すと

Screen Shot 2014-11-13 at 16.07.39.png

読み込まれた!

リロードボタンの実装はstoryboardからやりました。
navigationbarにbarbuttonitemを載せ、identifierをrefreshにして、assistantEditorを開いてViewControllerにCtrl+ドラッグアンドドロップしただけです。

本文も表示

詳細のViewControllerを増やす

Screen Shot 2014-11-13 at 16.13.28.png
storyboardからViewCotnrollerを選択して、ドラッグアンドドロップ。

Screen Shot 2014-11-13 at 16.15.40.png
TableViewのViewControllerと今回のViewControllerを紐付け。Segueる。
Storyboardの左っかわで、Ctrl+ドラッグアンドドロップで紐付けできます。

Screen Shot 2014-11-13 at 16.16.18.png
Segueのidentifierを決める

以下のコードを追加して、segueを追加します。

    //add segue
    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        // Segue
        performSegueWithIdentifier("detail", sender: entries[indexPath.row])
    }

Screen Shot 2014-11-13 at 16.19.17.png
ビルドしてみるとこんな感じ。
テーブルのセルをタップすると新しいViewControllerが呼ばれて遷移する。

WebView

  • DetailControllerにWebViewを追加

storyboardでドラッグアンドドロップしたらOK。

  • DetailControllerにアウトレットを追加

assistantEditorを表示して、Ctrl+ドラッグアンドドロップ。

Screen Shot 2014-11-13 at 16.33.49.png

  • URLを読み込むコードをかく
import Foundation
import UIKit

class DetailController: UIViewController {

    @IBOutlet weak var webView: UIWebView!

    var entry = NSDictionary()

    override func viewDidLoad() {
        super.viewDidLoad()

        //read URL by webView
        var url = NSURL(string: self.entry["link"] as String)
        var request = NSURLRequest(URL: url!)
        webView.loadRequest(request)
    }
}
  • ViewController側で表示するエントリーをDetailControllerに渡すところを何とかする
    // send entry to DetailController
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "detail" {
            // get DetailController
            var detailController = segue.destinationViewController as DetailController

            // set entry
            detailController.entry = sender as NSDictionary
        }
    }

さっきsegueを追加したコードの下あたり、@IBAction func refresh の上辺りに追記。

  • ビルド

いい感じー

Screen Shot 2014-11-13 at 16.40.16.png

とりあえず

とりあえず大枠ができたので、これから自分なりにカスタマイズしていくのですが、それはまた次回、、、

(swift1.1と1.0ってかなり違うんですね。。。2.0でいいのでは・・・)

参考