概要
[Swift]QiitaのAPIを叩いて記事を取得して表示するサンプルアプリを書いてみたの続き。
非同期処理の終了を呼び出し元で判断する方法がわからず、Notificationで書いてしまった。
これ、すっきりしなくてずっともやもやしてたので、上司に聞いてみた。
「クロージャが一番簡単だと思うよー」とさくっと言われてしまったので、クロージャにチャレンジ。
ついでに、SwiftyJSONの書き方もなんかしっくりこなかったので、JSONをモデルクラスにマッピングできるObjectMapperに乗りかえた。
モデルクラスを実装
前回版と同じ結果になるようにtitleとuserIdをプロパティにもつモデルクラスItemを実装。
ネストされたJSONの値はuser.idといったように、ドットシンタックスでつなげればいいらしい。
拡張もしやすいし、モデルクラスのほうが好き。
import Foundation
import ObjectMapper
struct Item: Mappable {
var title: String?
var userId: String?
init?(_ map: Map){}
mutating func mapping(map: Map) {
title <- map["title"]
userId <- map["user.id"]
}
}
APIClientの仕様を変更
戻り値をクロージャで渡すようにしつつ、戻り値をモデルクラスにマッピングするように修正。
クロージャが全然わからなくて苦しんだけど、こっちのほうがすっきりしてて好きなので満足。
エラーもクロージャで渡したほうがいいかなぁ。
import Alamofire
import ObjectMapper
class APIClient {
func getAllItems(success: (([Item]) -> Void)) {
let urlString: String = "https://qiita.com/api/v2/items"
Alamofire.request(.GET, urlString)
.responseJSON { response in
switch response.result {
case .Success(let value):
if let items = value as? NSArray {
var resultItems: [Item] = []
for item in items {
if item as? NSDictionary != nil {
resultItems.append(Mapper<Item>().map(item)!)
}
}
success(resultItems)
}
case .Failure(let error):
print(error)
}
}
}
}
あ、resultItems.append(Mapper<Item>().map(item)!)
の部分だけど、プロパティ変数にappendしたらnilにしかならなかったので、ローカル変数で対応した。
ここもかなりハマった…。
ViewControllerの仕様を変更
ここは特に説明なしでいいかな。
class ArticleListViewController: UIViewController, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
var items: [Item] = []
let client = APIClient()
override func viewDidLoad() {
super.viewDidLoad()
title = "新着記事"
tableView.dataSource = self
client.getAllItems() { resultItems in
self.items = resultItems
self.tableView.reloadData()
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "Cell")
let item = items[indexPath.row]
if let title = item.title {
cell.textLabel?.text = title
}
if let userId = item.userId {
cell.detailTextLabel?.text = userId
}
return cell
}
}
ソースコード
Githubにあげました。
https://github.com/macneko-ayu/SwiftPractice/tree/master/QiitaAPISample
まとめ
オプショナルの扱い、めんどくさい。