Alamofireで取得したデータをTableViewで表示する

2018年8月9日 Posted by PURGE

3年以上ぶりに、iOSの開発を行い始めた。今の時代はswift4 なのね。

■ 開発環境
OS : MacOS High Sierra Version 10.13.6
Xcode : Version 9.4.1

■ Server

サーバサイドは、JSONデータをRuby on Railsのように、DBスキーマから簡単に返すことができるので、Elixir言語で書かれた Phoexnix framework を利用しています。
その辺りは、後日に。

■ 取得データ
リクエスト送信先から返ってくるJSONデータは下記の感じ。

{
  "users" : [
    {
      "option" : "システムエンジニア",
      "age" : 46,
      "name" : "田島 啓之",
      "id" : 1
    },
    {
      "option" : "経理",
      "age" : 49,
      "name" : "都築 奏子",
      "id" : 2
    },
    {
      "option" : "ネットワークエンジニア",
      "age" : 45,
      "name" : "中村 栄人",
      "id" : 3
    },
    {
      "option" : "総務",
      "age" : 38,
      "name" : "千葉 博子",
      "id" : 4
    }
  ]
}

■ ソースコード解説

ListViewController.swiftのコードを説明する。

まずは、必要なライブラリをimportする。ここでは、AlamofireSwiftyJSONを利用する。

import UIKit
import Alamofire
import SwiftyJSON

次に、Swift4から、Codableというもので、構造体とJSONデータを簡単にマッピングできるようになったらしいので、Codableを利用して下記のような構造体を定義する。
これは、JSONデータのネスト構造を見てわかるように、Users構造体の中に、User構造体のリストが定義されている構造となる。

struct User : Codable{
    let id : Int
    let name: String
    let age : Int
    let option : String
}
struct Users : Codable{
    let users : [User]
}

ListViewControllerクラスは、UITableViewDelegateUITableViewDataSourceを採用する。特に問題はない。

class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

各メソッドから参照可能なように、Users構造体を定義する。初期化時には値が決まらないため、nilを許すため、オプショナル型としている。

    var users : Users?

viewDidLoad()においてUIの初期化を行う。

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tableView : UITableView!
        tableView = UITableView(frame: view.frame, style: .grouped)
        tableView.delegate = self
        tableView.dataSource = self
        
        view.addSubview(tableView)

Alamofireの主要処理部分。まずは、対象サーバへリクエストを送信して、JSONで受け取る。レスポンスがnilの場合は、そのままreturn

レスポンスがnilでない場合は、JSONDecoderで、Users構造体へマッピングする。

tableView.reloadData()は、Alamofireで取得するデータは非同期のため、初回は、tableViewは空のため、読み込みが完了した時点で、tableViewをリロードする必要がある。

        //Alamofire
        Alamofire.request("http://localhost:4000/user")
            .responseJSON{res in
                guard let json = res.data else{
                    return
                }
                self.users = try! JSONDecoder().decode(Users.self, from: json)
                
            tableView.reloadData()
        }

ここでは、リストの数を返す必要がある。通信が非同期のため、この時点では構造体はnilなので、初回は0を返す必要がある。リロードされた時に、Users構造体にデータはセットされているので、users.count でデータ数が取得できる。

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let cnt = self.users?.users.count{
            return cnt
        }
        return 0
    }

ここでは、セルのデータを設定している。やはりここも、初回はnilのため、let if で、nilチェックを行っている。
データがあれば、cell.textLabel.text を名前を設定する。

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "CELL")
        if let user = self.users?.users[indexPath.row]{
            cell.textLabel?.text = user.name
        }
        return cell
    }

■ 最後に

ここに記したコードは、初回時のデータ取得から表示までのサンプル的な最低限のコードです。もう少しリファクタリングして、構造を設計する必要がありますが、とりあえず動作原理をシンプルに理解するために記載しました。

間違い等がございましたら、ご指摘願います。

下記、全ソースコードです。

ListViewController.swift

import UIKit
import Alamofire
import SwiftyJSON

struct User : Codable{
    let id : Int
    let name: String
    let age : Int
    let option : String
}
struct Users : Codable{
    let users : [User]
}

class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var users : Users?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let tableView : UITableView!
        tableView = UITableView(frame: view.frame, style: .grouped)
        tableView.delegate = self
        tableView.dataSource = self
        
        view.addSubview(tableView)
        
        //Alamofire
        Alamofire.request("http://localhost:4000/user")
            .responseJSON{res in
                guard let json = res.data else{
                    return
                }
                self.users = try! JSONDecoder().decode(Users.self, from: json)
                
                //Debug
                print("--- User JSON ---")
                print(JSON(json))
                print("--- User Info ---")
                for user in self.users!.users{
                    print("NAME:" + user.name)
                    print("AGE:" + String(user.age))
                }
                
            tableView.reloadData()
        }
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let cnt = self.users?.users.count{
            return cnt
        }
        return 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "CELL")
        if let user = self.users?.users[indexPath.row]{
            cell.textLabel?.text = user.name
        }
        return cell
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
}

Lovly Swift!!!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です