54
53

More than 5 years have passed since last update.

SwiftでAlamofireを使ってみた。QiitaのSwiftに関する投稿をパースしてみたよ。

Last updated at Posted at 2014-09-20

SwiftでAlamofireを使ってみた。
パースする内容はQiitaのSwiftに関する投稿。

gifアニメーション

move

Github

使用したAPI

Qiita APIを使用。(https://qiita.com/docs)
以下はDocumentより抜粋。

GET /api/v1/search

[{"id": 1,
 "uuid": "1a43e55e7209c8f3c565",
 "user":
  {"name": "Hiroshige Umino",
   "url_name": "yaotti",
   "profile_image_url": "https://si0.twimg.com/profile_images/2309761038/1ijg13pfs0dg84sk2y0h_normal" },
 "title": "てすと",
 "body": "<p>foooooooooooooooo</p>\n",
 "created_at": "2012-10-03 22:12:36 +0900",
 "updated_at": "2012-10-03 22:12:36 +0900",
 "created_at_in_words": "18 hours ago",
 "updated_at_in_words": "18 hours ago",
 "tags":
  [{"name": "FOOBAR",
    "url_name": "FOOBAR",
    "icon_url": "http://qiita.com/icons/thumb/missing.png",
    "versions": ['1.2', '1.3']}],
 "stock_count": 0,
 "stock_users": [],
 "comment_count": 0,
 "url": "http://qiita.com/items/1a43e55e7209c8f3c565",
 "gist_url": null,
 "tweet": false,
 "private": false,
 "stocked": false
},
 ...
]

ソースコード

ViewController
ViewController (UITableViewでリスト表示)
WebViewController (UIWebViewで記事ページを表示)

ViewController.swift
import UIKit
import Alamofire

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    var articles: Array<Article>?

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

        articles = Array()

        // Get articles
        var result: NSArray?
        Alamofire.request(.GET, "https://qiita.com/api/v1/search?q=swift",parameters: nil, encoding: .JSON)
            .responseJSON { (request, response, JSON, error) in
                result = (JSON as NSArray)

                // Make models from Json data
                for (var i = 0; i < result?.count; i++) {
                    let dic: NSDictionary = result![i] as NSDictionary
                    var article: Article = Article(
                        title: dic["title"] as String,
                        userName: dic["user"]!["url_name"] as String,
                        linkURL: dic["url"] as String,
                        imageURL:dic["user"]!["profile_image_url"] as String
                    )
                    self.articles?.append(article)
                }
                self.tableView.reloadData()
        }
    }

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

    func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int  {
        return articles!.count
    }

    func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath:NSIndexPath!) -> UITableViewCell! {
        let cell: MyTableViewCell = tableView?.dequeueReusableCellWithIdentifier("Cell") as MyTableViewCell
        cell.article = articles?[indexPath.row]
        return cell;
    }

    func tableView(tableView: UITableView?, didSelectRowAtIndexPath indexPath:NSIndexPath!) {
        // When a cell has selected, open WebViewController.
        let cell: MyTableViewCell = tableView?.cellForRowAtIndexPath(indexPath) as MyTableViewCell
        self.performSegueWithIdentifier("WebViewController", sender: cell)
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        super.prepareForSegue(segue, sender: sender)

        // Assign a model to WebViewController
        if segue.identifier == "WebViewController" {
            var cell : MyTableViewCell = sender as MyTableViewCell
            let vc: WebViewController = segue.destinationViewController as WebViewController
            vc.article = cell.article
        }
    }
}

WebViewController
import UIKit

class WebViewController: UIViewController {
    @IBOutlet weak var webView: UIWebView!
    @IBAction func backButtonPressed(sender: UIButton) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }

    var article: Article?

    override func viewDidLoad() {
        super.viewDidLoad()

        var url: NSURL = NSURL.URLWithString(self.article!.linkURL)
        var urlRequest: NSURLRequest = NSURLRequest(URL: url)
        self.webView.loadRequest(urlRequest)
    }

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


    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

View
MyTableViewCell (カスタマイズしたCell)

MyTableViewCell
import UIKit

class MyTableViewCell: UITableViewCell {
    @IBOutlet weak var userImageView: UIImageView!
    @IBOutlet weak var titleLabel: UILabel!
    @IBOutlet weak var userLabel: UILabel!

    var article: Article? {
        // When the data has been set, labels and imageView will have the values.
        didSet {
            self.titleLabel.text = self.article?.title
            self.userLabel.text = self.article?.userName
            self.userImageView.image = UIImage(named: "qiita-logo.png")

            var q_global: dispatch_queue_t = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
            var q_main: dispatch_queue_t  = dispatch_get_main_queue();
            dispatch_async(q_global, {
                let url: NSURL = NSURL.URLWithString(self.article!.imageURL)
                var error: NSError?
                let imageData: NSData = NSData(contentsOfURL: url, options: nil, error:&error)
                let image: UIImage = (error !== nil) ? UIImage(named: "qiita-logo.png") : UIImage(data: imageData)
                dispatch_async(q_main, {
                    self.userImageView.image = image
                })
            })
        }
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

Model
Article (記事タイトル、記事URL、ユーザのプロフィール画像、ユーザ名)

Article
import UIKit

class Article: NSObject {
    var title: String, userName: String, linkURL: String, imageURL: String

    init(title: String, userName: String, linkURL: String, imageURL: String) {
        self.title = title
        self.userName = userName
        self.linkURL = linkURL
        self.imageURL = imageURL
    }
}

Alamofireで返ってくるJSONの処理

Alamofireのソースコードを見てみると、返ってくるJSONはNSDictionaryを持ったArray型であることがわかる。
従って以下のようにJSONを分解してモデルに代入した。

var result: NSArray?
Alamofire.request(.GET, "https://qiita.com/api/v1/search?q=swift",parameters: nil, encoding: .JSON)
    .responseJSON { (request, response, JSON, error) in
        result = (JSON as NSArray)

        for (var i = 0; i < result?.count; i++) {
            let dic: NSDictionary = result![i] as NSDictionary
            var article: Article = Article(
                title: dic["title"] as String,
                userName: dic["user"]!["url_name"] as String,
                linkURL: dic["url"] as String,
                imageURL:dic["user"]!["profile_image_url"] as String
            )
            self.articles?.append(article)
         }
         self.tableView.reloadData()
    }

XCodeのバグ?

作業中に何度か見舞われたが、HTTP通信で取得した画像がシミュレータ上で表示されない問題。
以下にも同様な記述があったため、Xcode6のバグだと思われる。
http://stackoverflow.com/questions/25372318/error-domain-nsurlerrordomain-code-1005-the-network-connection-was-lost

所感

!と?をもう少しきちんと理解したい。

Objective-Cよりも型にうるさいので、注意が必要。

TableViewCell中の画像の表示は非同期にしているが、Cellの再利用をしているからか、勢い良くスクロールダウンした際に以前のCellのデータが表示されてしまうことがある。
このあたり、詳しい人がいれば解決法を教えて下さい。

軽くドキュメントを読んだだけでも数時間で作成できたので、Objective-Cでアプリを作ったことがあれば比較的簡単にSwiftに移行できそう。

54
53
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
53