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

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

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

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

Q&A

解決済

1回答

670閲覧

SwiftUIにてAPIを利用してデータを取得してからViewを更新する方法がわからない

Beruto

総合スコア10

Swift

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

0グッド

0クリップ

投稿2022/01/12 14:10

編集2022/01/12 14:15

SwiftUIにてアプリ開発を行っているのですが、APIを使ってデータを取得してからViewを更新する方法がわかりません。
initに、データ取得の関数、view更新の関数を順に呼び出しているのですが、
データが取得し終わる前にview更新の関数が呼び出されてしまい、画面になにも表示されません。

以下、イメージのコードです

swift

1struct SwiftApiTest: View { 2 @ObservedObject var viewModel = SwiftApiTestViewModel(count: 10) 3 var body: some View { 4 if viewModel.isProgress { 5 ProgressView() 6 } else { 7 VStack { 8 ForEach(viewModel.subViews) {view in 9 view 10 } 11 } 12 } 13 } 14} 15 16struct SubView: View, Identifiable { 17 let id = UUID() 18 let hoge: Int 19 let fuga: String 20 init?(hoge: Int?, fuga: String?) { 21 if let hoge = hoge, 22 let fuga = fuga { 23 self.hoge = hoge 24 self.fuga = fuga 25 } else { 26 print("hogeかfugaがnilです") 27 return nil 28 } 29 } 30 var body: some View { 31 HStack { 32 Text("hoge: \(hoge)") 33 Text("fuga: \(fuga)") 34 } 35 } 36} 37 38class SwiftApiTestViewModel: ObservableObject { 39 @Published var cm = CommunicationManager() 40 @Published var subViews: [SubView] = [] 41 42 init(count: Int) { 43 // データ取得 44 resume() 45 // view更新処理 46 // 上のresume()がまだ終わっていないのに呼び出されてしまう 47 subViewDuplicator(count: count) 48 } 49 50 var isProgress: Bool { 51 cm.isProgress 52 } 53 54 var hoge: Int? { 55 var value: Int? 56 if let data = cm.apiData { 57 value = data.hoge 58 } 59 return value 60 } 61 62 var fuga: String? { 63 var str: String? 64 if let data = cm.apiData { 65 str = data.fuga 66 } 67 return str 68 } 69 70 // SubViewをcount分だけ複製して配列に入れる 71 func subViewDuplicator(count: Int) { 72 for _ in 0..<count { 73 subViews.append(SubView(hoge: hoge, fuga: fuga)!) 74 } 75 } 76 77 func resume() { 78 cm.resume() 79 } 80} 81 82class CommunicationManager { 83 struct ApiData: Decodable { 84 var hoge: Int 85 var fuga: String 86 } 87 88 // 処理中か 89 var isProgress = false 90 // 取得するデータ 91 var apiData: ApiData? 92 93 func resume() { 94 // 処理開始 95 isProgress = true 96 let url = URL(string: "url")! 97 let request = URLRequest(url: url) 98 URLSession.shared.dataTask( 99 with: request, 100 completionHandler: { data, response, error in 101 // データ取得処理 102 }) 103 // 処理終了 104 isProgress = false 105 } 106}

ものすごい雑なサンプルですが、現在作成中のアプリでは
天気apiを使って取ってきた情報(1週間天気など)を一旦別View(ここではSubView)にいれ
それを配列にしてメインViewにてForEachを使って表示させています。

resume()が終わってからsubViewDuplicator()を実行させる方法を教えていただきたいです。
DispatchQueue.main.asyncなどを使うようではありますが色々試してうまく行かなかったので
質問させていただきます。

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

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

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

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

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

hoshi-takanori

2022/01/15 16:01

ツッコミどころが多すぎてどこからコメントしたらいいか悩みますが、とりあえず非同期処理について学ぶことをお勧めします。
guest

回答1

0

自己解決

DispatchSemaphoreを使って解決しました。

投稿2022/01/16 13:46

Beruto

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問