Xcode 12.4, Swift 5
SwiftUIを用いて、Web上で稼働しているAPIにアクセスしてJSON形式のデータを取得し、画面上に表示するサンプルコードを作成してみました。利用するAPIやデータ、表示するViewなども極力シンプルな形にしています。
API & Data
今回は、以下のサイトで公開されているAPIを使わせていただくことにします。Todo管理ツールを想定したデータとなっていて、ユーザID、ID、タイトル、完了フラグがセットとなったデータが複数格納されています。
今回は、最もシンプルなデータを利用することにしますので、以下の形式でAPI実行して取得できるデータを対象にします。
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
Implementaion
データ取得用のViewの作成
まずは、データを取得するViewを作成していきます。以下がポイントになります。
- 取得するデータ型(ToDoData)をJSONで取得する要素のそれぞれの型に合わせ(Int, Int, String, Bool)、Codableで定義
- 取得するデータ(todo)を@Stateで定義し、値の動的な変化に対応させる
import SwiftUI
struct ApiView: View {
@State private var todo: TodoData = TodoData(userId: -1, id: -1, title: "na", completed: false)
struct TodoData: Codable {
var userId: Int
var id: Int
var title: String
var completed: Bool
}
var body: some View {
VStack(spacing: 10) {
Text("Get Data")
.padding(10)
.background(Color(.green))
.cornerRadius(20)
Text(todo.title)
}
}
}
この状態のViewは以下のようになります。

GetDataボタンをタップすることで、その下の領域に取得したデータからタイトルを表示するようにしたいと思います。現状は、初期値である”na”が表示されています。
データ取得部分の作成
まずは、GetDataボタンをタップする部分を追加していきます。タップしたら、getData()を呼び出すかたちです。
struct ApiView: View {
@State private var todo: TodoData = TodoData(userId: -1, id: -1, title: "na", completed: false)
struct TodoData: Codable {
var userId: Int
var id: Int
var title: String
var completed: Bool
}
var body: some View {
VStack(spacing: 10) {
Text("Get Data")
.padding(10)
.background(Color(.green))
.cornerRadius(20)
.onTapGesture {
getData()
}
Text(todo.title)
}
}
func getData() {
}
}
次に、getData()の中身を作成していきます。
func getData() {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { return }
URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
if let todoData = data {
let decodedData = try JSONDecoder().decode(TodoData.self, from: todoData)
self.todo = decodedData
} else {
print("No data", data as Any)
}
} catch {
print("Error", error)
}
}.resume()
}
getDataの内容について、いくつかポイント(ハイライト部分)を説明します。
URLSession, Task
URLSession.shared.dataTask(with: url) {(data, response, error) in
...
}
今回はシンプルな通信なので、shared sessionを使い、data taskを用いることにしているため上記の実装としています。

JSONDecoder
let decodedData = try JSONDecoder().decode(TodoData.self, from: todoData)
JSONDecoder.decodeにJSONのデータ型であるTodoDataを渡しています。.selfを忘れず付与するようにしてください。JSONデコードについては以下の投稿も参考にしてください。
resume
新規に作成されたタスクはsuspended状態で始まるため、タスクを開始(使用)するためには、忘れずにresume()を用いる必要があります。実際、今回のコードからこの部分を削除するだけでも、データの取得ができなくなります。

Behavior
今回実装したコードを動かすと、以下のようになります。

まとめ
今回、これ以上シンプルにはできないレベルでサンプルコードを作成してみました。実際の用途ではデータ構造がより複雑だったりと、そのままでは使えないと思いますが、こういった小さなコードから始めることで理解が深まればと思います。
SwiftUIにおける、Webアクセスに関して以下で詳細に解説していますので、今回のサンプルコードがブラックボックスのように思える方は一読していただけると理解が深まるかもしれません。
サンプルコード
import SwiftUI
struct ApiView: View {
@State private var todo: TodoData = TodoData(userId: -1, id: -1, title: "na", completed: false)
struct TodoData: Codable {
var userId: Int
var id: Int
var title: String
var completed: Bool
}
var body: some View {
VStack(spacing: 10) {
Text("Get Data")
.padding(10)
.background(Color(.green))
.cornerRadius(20)
.onTapGesture {
getData()
}
Text(todo.title)
}
}
func getData() {
guard let url = URL(string: "https://jsonplaceholder.typicode.com/todos/1") else { return }
URLSession.shared.dataTask(with: url) {(data, response, error) in
do {
if let todoData = data {
let decodedData = try JSONDecoder().decode(TodoData.self, from: todoData)
self.todo = decodedData
} else {
print("No data", data as Any)
}
} catch {
print("Error", error)
}
}.resume()
}
}
struct ApiView_Previews: PreviewProvider {
static var previews: some View {
ApiView()
}
}