Edited at

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

More than 5 years have passed since last update.

SwiftでAlamofireを使ってみた。

パースする内容はQiitaのSwiftに関する投稿。


gifアニメーション

move


Github

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


使用した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に移行できそう。