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
}
最後に
ここに記したコードは、初回時のデータ取得から表示までのサンプル的な最低限のコードです。もう少しリファクタリングして、構造を設計する必要がありますが、とりあえず動作原理をシンプルに理解するために記載しました。
間違い等がございましたら、ご指摘願います。
下記、全ソースコードです。
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!!!