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

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データは下記の感じ。

[javascript]
{
"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
}
]
}

[/javascript]

■ ソースコード解説

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

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

[objc]
import UIKit
import Alamofire
import SwiftyJSON
[/objc]

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

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

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

[objc]
class ListViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
[/objc]

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

[objc]
var users : Users?
[/objc]

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

[objc]
override func viewDidLoad() {
super.viewDidLoad()

let tableView : UITableView!
tableView = UITableView(frame: view.frame, style: .grouped)
tableView.delegate = self
tableView.dataSource = self

view.addSubview(tableView)

[/objc]

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

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

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

[objc]
//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()
}

[/objc]

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

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

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

[objc]
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
}

[/objc]

■ 最後に

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

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

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

ListViewController.swift

[objc]
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()
}

}

[/objc]

Lovly Swift!!!

This entry was posted in Swift, Xcode, 技術情報. Bookmark the permalink.

コメントを残す

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