简体   繁体   English

Escaping 闭包捕获变异的“自我”参数,Firebase

[英]Escaping closure captures mutating 'self' parameter, Firebase

I have the following code, How can i accomplish this without changing struct into class.我有以下代码,如何在不将结构更改为 class 的情况下完成此操作。 Escaping closure captures mutating 'self' parameter, Escaping 闭包捕获变异的“自我”参数,

struct RegisterView:View {
    var names = [String]()

    private func LoadPerson(){
        FirebaseManager.fetchNames(success:{(person) in
        guard let name = person.name else {return}
        self.names = name //here is the error
    }){(error) in
        print("Error: \(error)")
    }

    init(){
        LoadPerson()
    }a
    
    var body:some View{
        //ui code
    }
}

Firebasemanager.swift Firebasemanager.swift

struct FirebaseManager {
    
    func fetchPerson(
        success: @escaping (Person) -> (),
        failure: @escaping (String) -> ()
    ) {
        Database.database().reference().child("Person")
        .observe(.value, with: { (snapshot) in
            if let dictionary = snapshot.value as? [String: Any] {
                success(Person(dictionary: dictionary))
            }
        }) { (error) in
            failure(error.localizedDescription)
        }
    }
}

SwiftUI view can be created (recreated) / copied many times during rendering cycle, so View.init is not appropriate place to load some external data. SwiftUI 视图可以在渲染周期中多次创建(重新创建)/复制,因此View.init不适合加载一些外部数据。 Use instead dedicated view model class and load explicitly only when needed.改用专用视图 model class 并仅在需要时显式加载。

Like喜欢

class RegisterViewModel: ObservableObject {
    @Published var names = [String]()

    func loadPerson() {
// probably it also worth checking if person has already loaded
//      guard names.isEmpty else { return }

        FirebaseManager.fetchNames(success:{(person) in
        guard let name = person.name else {return}
        DispatchQueue.main.async {
           self.names = [name]
        }
    }){(error) in
        print("Error: \(error)")
    }
}

struct RegisterView: View {

    // in SwiftUI 1.0 it is better to inject view model from outside
    // to avoid possible recreation of vm just on parent view refresh
    @ObservedObject var vm: RegisterViewModel

//    @StateObject var vm = RegisterViewModel()   // << only SwiftUI 2.0

    var body:some View{
       Some_Sub_View()
         .onAppear {
            self.vm.loadPerson()
         }
    }
}

Make the names property @State variable.使names属性@State变量。

struct RegisterView: View {
    @State var names = [String]()

    private func LoadPerson(){
        FirebaseManager.fetchNames(success: { person in
            guard let name = person.name else { return }
            DispatchQueue.main.async {
                self.names = [name]
            }
        }){(error) in
            print("Error: \(error)")
        }
    }
    //...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM