BellRinging
BellRinging

Reputation: 401

How can I use async call closure to init parameter under SwiftUI

I try to initial a value under init() method, but I got this error Escaping closure captures mutating 'self' parameter

It work if I put it under onAppear() but it won't call if the screen is on back-group, so It is not what I needed . Attached my coding ..

struct GameRowForDemo: View {

    let game : Game
    var user : User?


    init(game:Game){
        self.game = game
        let uid = "123"
        User.getById(id: uid).then { user in
            self.user = user!
        }
    }




    var body: some View {
        Text("Text")
    }
}

static func getById(id: String) -> Promise<User?>  {
    let p = Promise<User?> { (resolve , reject) in
        let db = Firestore.firestore()
        let ref = db.collection("users").document(id)
        ref.getDocument { (snapshot, err) in
            if let err = err{
                reject(err)
            }
            guard let dict = snapshot?.data() else {
                print("No User found")
                resolve(nil)
                return
            }
            do {
                let data = try JSONSerialization.data(withJSONObject: dict, options: .prettyPrinted)
                let group = try JSONDecoder.init().decode(User.self, from: data)
                resolve(group)
            }catch{
                reject(error)
            }
        }
    }
    return p
}

Upvotes: 3

Views: 2151

Answers (1)

Asperi
Asperi

Reputation: 258345

As view is non-mutating here, I would refactor provided code by decomposing related things into explicit view model as below

import Combine

class GameViewModel: ObservableObject {
    @Published var game : Game
    @Published var user : User?

    init(game: Game) {
        self.game = game
    }

    func fetchUser(uid: String) {
        User.getById(id: uid).then {[weak self] user in
            DispatchQueue.main.async {
                self?.user = user!
            }
        }
    }
}

struct GameRowForDemo: View {
    @ObservedObject var viewModel: GameViewModel

    init(viewModel: GameViewModel) {
        self.viewModel = viewModel
        viewModel.fetchUser(uid: "123")
    }

    var body: some View {
        Text("Text")
    }
}

Upvotes: 1

Related Questions