質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

2583閲覧

SwiftUIの初期画面(ContentView)でButtonのactionなしに関数を実行する書き方について

DeepRoastBeans

総合スコア79

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

1グッド

0クリップ

投稿2022/01/28 04:38

「iPhone アプリ開発集中講座」という本を参考に、pythonなどで処理したjsonを取得して、そのデータを一覧表示するアプリを作ろうとしています。
ContentVidwのButton(action: {})で関数を呼び出して、Jsonから取得したデータをList表示するところまでは出来たのですが、Buttonを押さずに関数を実行するには、どのように書いたら良いのでしょうか?

下記の await bousaiDataList.getPopulation() をbuttonを押さずに、アプリを開いたタイミングで実行させたいです。

ContentView.swift

swift

1import SwiftUI 2 3struct ContentView: View { 4 5 @StateObject var bousaiDataList = BousaiData() 6 7 var body: some View { 8 9 VStack { 10 Text("Hello, world!") 11 .padding() 12 Button(action: { 13 Task { 14 await bousaiDataList.getPopulation() 15 } 16 }){ 17 Text("表示") 18 } 19 List(bousaiDataList.bousaiList) { bousai in 20 21 HStack() { 22 Text(bousai.area) 23 Text("\(bousai.population)") 24 Text(bousai.capital) 25 } 26 } 27 } 28 } 29}

BousaiData.swift

swift

1import SwiftUI 2import UIKit 3 4struct BousaiItem: Identifiable { 5 let id = UUID() 6 let area: String 7 let population: UInt 8 let capital: String 9} 10 11class BousaiData: ObservableObject { 12 13 struct ResultJson: Codable { 14 struct Item: Codable { 15 let area: String? 16 let population: UInt? 17 let capital: String? 18 } 19 let item: [Item]? 20 } 21 @Published var bousaiList: [BousaiItem] = [] 22 23 func getPopulation() async { 24 print("hello!") 25 26 guard let req_url = URL(string: 27 "https://hoge.com/population.json") else { 28 return 29 } 30 print(req_url) 31 32 do { 33 let (data, _) = try await URLSession.shared.data(from: req_url) 34 let decoder = JSONDecoder() 35 let json = try decoder.decode(ResultJson.self, from: data) 36 37 guard let items = json.item else { return } 38 39 DispatchQueue.main.async { 40 self.bousaiList.removeAll() 41 } 42 43 for item in items { 44 if let area = item.area, 45 let population = item.population, 46 let capital = item.capital { 47 let bousai = BousaiItem(area: area, population: population, capital: capital) 48 DispatchQueue.main.async { 49 self.bousaiList.append(bousai) 50 } 51 } 52 } 53 print(self.bousaiList) 54 } catch { 55 print("エラーが出ました") 56 } 57 } 58}

イメージ説明

-> 今の実装だと、ボタンを押さないと表示されない

Pomu3270👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

以下二通りのどちらかでどうでしょうか。

1、以下のようにBousaiDataクラスのイニシャライザで呼んでみてはどうでしょうか。

swift

1class BousaiData: ObservableObject { 2 3 struct ResultJson: Codable { 4 struct Item: Codable { 5 let area: String? 6 let population: UInt? 7 let capital: String? 8 } 9 let item: [Item]? 10 } 11 @Published var bousaiList: [BousaiItem] = [] 12 13 init() { // 追加 14 getPopulation() // 追加 15 } // 追加 16 17 func getPopulation() async { 18 print("hello!") 19 20 guard let req_url = URL(string: 21 "https://hoge.com/population.json") else { 22 return 23 } 24 print(req_url) 25 26 do { 27 let (data, _) = try await URLSession.shared.data(from: req_url) 28 let decoder = JSONDecoder() 29 let json = try decoder.decode(ResultJson.self, from: data) 30 31 guard let items = json.item else { return } 32 33 DispatchQueue.main.async { 34 self.bousaiList.removeAll() 35 } 36 37 for item in items { 38 if let area = item.area, 39 let population = item.population, 40 let capital = item.capital { 41 let bousai = BousaiItem(area: area, population: population, capital: capital) 42 DispatchQueue.main.async { 43 self.bousaiList.append(bousai) 44 } 45 } 46 } 47 print(self.bousaiList) 48 } catch { 49 print("エラーが出ました") 50 } 51 } 52}

2、それとも、以下のように画面が表示された時に実行されるように、onAppearのクロージャーで実行することもできます。

swift

1struct ContentView: View { 2 3 @StateObject var bousaiDataList = BousaiData() 4 5 var body: some View { 6 7 VStack { 8 Text("Hello, world!") 9 .padding() 10 Button(action: { 11 Task { 12 await bousaiDataList.getPopulation() 13 } 14 }){ 15 Text("表示") 16 } 17 List(bousaiDataList.bousaiList) { bousai in 18 19 HStack() { 20 Text(bousai.area) 21 Text("\(bousai.population)") 22 Text(bousai.capital) 23 } 24 } 25 } 26 .onAppear { // 追加 27 Task { // 追加 28 await bousaiDataList.getPopulation() // 追加 29 } // 追加 30 } // 追加 31 } 32}

しかし、この2のやりかたの場合、ContentViewが表示された時に毎回データを取りに行くことになるので、パフォーマンス的にはあまり良くないかもしれません。

投稿2022/01/28 11:06

Pomu3270

総合スコア280

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DeepRoastBeans

2022/01/29 00:17

めちゃくちゃ素晴らしいです。両方でできました!!! initの方は、「async call in a function that does not support concurrency」と出たので、 以下のようにawaitと指定しました。 init() { Task { await getPopulation() } } >しかし、この2のやりかたの場合、ContentViewが表示された時に毎回データを取りに行くことになるので、パフォーマンス的にはあまり良くないかもしれません。 処理が早い方が良いですね。勉強になります!
Pomu3270

2022/01/30 06:06

期待値通り動作できて、自分も嬉しいばかりです! ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問