16
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

[Swift]QiitaのAPIを叩いて記事を取得して表示するサンプルアプリを書いてみた その2

Last updated at Posted at 2016-03-06

概要

[Swift]QiitaのAPIを叩いて記事を取得して表示するサンプルアプリを書いてみたの続き。

非同期処理の終了を呼び出し元で判断する方法がわからず、Notificationで書いてしまった。

これ、すっきりしなくてずっともやもやしてたので、上司に聞いてみた。
「クロージャが一番簡単だと思うよー」とさくっと言われてしまったので、クロージャにチャレンジ。

ついでに、SwiftyJSONの書き方もなんかしっくりこなかったので、JSONをモデルクラスにマッピングできるObjectMapperに乗りかえた。

モデルクラスを実装

前回版と同じ結果になるようにtitleとuserIdをプロパティにもつモデルクラスItemを実装。
ネストされたJSONの値はuser.idといったように、ドットシンタックスでつなげればいいらしい。
拡張もしやすいし、モデルクラスのほうが好き。

Item
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の仕様を変更

戻り値をクロージャで渡すようにしつつ、戻り値をモデルクラスにマッピングするように修正。
クロージャが全然わからなくて苦しんだけど、こっちのほうがすっきりしてて好きなので満足。
エラーもクロージャで渡したほうがいいかなぁ。

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の仕様を変更

ここは特に説明なしでいいかな。

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

まとめ

オプショナルの扱い、めんどくさい。

16
18
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
16
18

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?