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

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

## gifアニメーション
![move](https://github.com/ytakzk/Swift-Alamofire-For-Qiita/raw/master/example.gif)


## Github
https://github.com/ytakzk/Swift-Alamofire-For-Qiita

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

GET /api/v1/search

```json
[{"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で記事ページを表示)

```swift: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
        }
    }
}

```

```Swift: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)

```Swift: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、ユーザのプロフィール画像、ユーザ名)

```swift: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を分解してモデルに代入した。

```swift
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に移行できそう。