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
する。ここでは、Alamofire
とSwiftyJSON
を利用する。
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
クラスは、UITableViewDelegate
とUITableViewDataSource
を採用する。特に問題はない。
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!!!