📡

[swift] [初心者向け] 通信処理の実行順序よくある間違い

2022/01/06に公開

アプリケーション開発において、ネットワークからデータを取得するケースがよくあります。

まず、この際によくある間違いを紹介します。

let db = Firestore.firestore()

db.collection("users").getDocuments() { (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
         userDocuments = querySnapshot!.documents // (a)
    }
}

// (b) ここに userDocuments を使うコードが書いてある

このように書いた場合に、実際には (b) -> (a) の順番で実行されます。

なので (a) -> (b) の順に実行されることを期待して書くと
(b) の時点では (a) が実行されていないので
userDocuments を使うコード は失敗します。

これは getDocuments の実装次第だと思うのですが
基本的にネットワークからデータを取得する場合は非同期処理を行うため

{ (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
         userDocuments = querySnapshot!.documents // (a)
    }
}

ここのブロックは、通信が終わった後から実行されます。

ですので、シンプルに治すとすると通信が終わってデータ取得した後に
行いたい処理はブロックの中に書いてしまいましょう。

let db = Firestore.firestore()

db.collection("users").getDocuments() { (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
         userDocuments = querySnapshot!.documents // (a)
	 // (b) ここに userDocuments を使うコードを書く
    }
}

最後に、最初のコードが実際にはどのような実行順序であったか
分かりやすくするために実行順序で並び替えるとこのようになります。

let db = Firestore.firestore()

db.collection("users").getDocuments()

// (b) ここに userDocuments を使うコードが書いてある

{ (querySnapshot, err) in
    if let err = err {
        print("Error getting documents: \(err)")
    } else {
         userDocuments = querySnapshot!.documents // (a)
    }
}

本件から進めて、関数に切り分けたケースについても記事を作成しました。
https://zenn.dev/yoneapp/articles/d378d9deef20d5

Discussion