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

Posted

技术标签:

【中文标题】转义闭包捕获变异的“自我”参数,Firebase【英文标题】:Escaping closure captures mutating 'self' parameter, Firebase 【发布时间】:2020-07-19 11:40:27 【问题描述】:

我有以下代码,如何在不将结构更改为类的情况下完成此操作。转义闭包捕获变异的“自我”参数,

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

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)
        
    

【问题讨论】:

【参考方案1】:

SwiftUI 视图可以在渲染周期中多次创建(重新创建)/复制,因此View.init 不适合加载一些外部数据。改为使用专用的视图模型类并仅在需要时显式加载。

喜欢

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()
         
    

【讨论】:

【参考方案2】:

使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)")
        
    
    //...

【讨论】:

以上是关于转义闭包捕获变异的“自我”参数,Firebase的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 转义闭包捕获变异的“自我”参数

获取 JSON,附加到数组:转义闭包捕获变异的“自我”参数

转义闭包捕获 Swift 中的变异“self”参数错误

在 Swift 3.0 中的转义闭包中改变自我(结构/枚举)

转义闭包捕获非转义参数“函数” Xcode 说

Swift 5:转义闭包捕获'inout'参数