処理の組み合わせ
これまでに作成した画面とクラスを組み合わせて処理を作成します。
データバインディングを設定する
6.3 複数のUI間の連携 で作成したサンプルのように入力欄とボタンにデータバインディングを設定します。

struct ContentView: View {
@State var inputText = ""
@State var buttonEnabled = false
var body: some View {
VStack {
HStack {
TextField("検索キーワード", text: $inputText)
.onChange(of: self.inputText) {
// 3文字以上でボタン押下可能
if ($0.count >= 3) {
self.buttonEnabled = true
} else {
self.buttonEnabled = false
}
}
.textFieldStyle(.roundedBorder)
.frame(height: 32)
.padding([.leading, .trailing], 8)
Button("検索") {
// Action
}.disabled(!self.buttonEnabled)
}
.frame(height: 64)
.padding([.leading, .trailing], 16)
ScrollView {
}
}
}
}
ボタン押下時にメソッドを実行する
ボタンを押した時に、ImageLoader クラスの searchImages メソッドを実行する処理を作成します。同時に 6.4 シミュレーターでの入出力 で実装したキーボードを下げる処理も実行するようにします。

struct ContentView: View {
@State var inputText = ""
@State var buttonEnabled = false
let imageLoader = ImageLoader()
var body: some View {
VStack {
HStack {
TextField("検索キーワード", text: $inputText)
.onChange(of: self.inputText) {
// 3文字以上でボタン押下可能
if ($0.count >= 3) {
self.buttonEnabled = true
} else {
self.buttonEnabled = false
}
}
.textFieldStyle(.roundedBorder)
.frame(height: 32)
.padding([.leading, .trailing], 8)
Button("検索") {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
Task {
do {
// 画像検索
try await self.imageLoader.searchImages(keyword: self.inputText)
} catch {
print(error)
}
}
}.disabled(!self.buttonEnabled)
}
.frame(height: 64)
.padding([.leading, .trailing], 16)
ScrollView {
}
}
}
}
ここまでの動作確認
ここまでで実装したUIのバインディングの実装とJSONのパースを実際にアプリを動かして確認してみます。
ImageLoader クラスの searchImages メソッドの最後にパースした JSON をコンソールに出力するコードを追加してアプリを実行してください。
func searchImages(keyword: String) async throws {
self.imageDatas = []
let urlStr = "https://pixabay.com/api/?key=\(self.api_key)&q=\(keyword)"
let url = URL(string: urlStr.addingPercentEncoding(withAllowedCharacters: NSCharacterSet.urlQueryAllowed)!)!
let (data, response) = try await URLSession.shared.data(from: url)
// ステータスコードが200でなければエラー
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw PixabayAPIError.serverError }
// JSONを解析して作成した構造体の通りにマッピング
guard let decoded = try? JSONDecoder().decode(SearchImageDataModel.self, from: data) else { throw PixabayAPIError.noData }
self.imageDatas = decoded.hits
for item in decoded.hits {
print(item.id)
print(item.largeImageURL)
print("-------")
}
}
UIの配置確認

入力3文字以上でボタンの有効化、ボタン押下時のキーボード非表示

JSONのパースをコンソールで確認

上記のように実装した機能を確認してください。これらの機能ができていることを前提として検索結果のグリッド表示に進みます。