【问题标题】:SwiftUI x Firebase - Trouble Waiting for Firebase Results before Executing CodeSwiftUI x Firebase - 在执行代码之前无法等待 Firebase 结果
【发布时间】:2021-01-02 17:01:56
【问题描述】:

提前致谢!我目前正在尝试学习如何使用 SwiftUI 构建移动应用程序,并希望将 Firebase 用于基于云的服务(数据库、身份验证)。我在尝试实现闭包以确保继续执行的代码仅在执行 Firebase 任务后执行时遇到了一些麻烦。我尝试在我的 findUser() 函数中编写一个闭包和 @escaping 函数,但我的常规程序仍然没有等待 findUser() 完成后再继续。

这里有什么想法吗?我在下面粘贴了我的 findUser() 函数,以及我目前如何调用它

func findUser(searchKey: String, searchValue: Any, completionHandler: @escaping (_ result: Dictionary<String, Any>?) -> Void) {

    var user: Dictionary<String, Any>? = nil
    let db: Firestore = getFirebaseConn()
    let usersRef = db.collection(fire.userPath) // db ref

    usersRef.whereField(searchKey, isEqualTo: searchValue).getDocuments() { (querySnapshot, err) in
        
        guard let querySnapshot = querySnapshot else {
            print("There was an error with retrieving the query snapshot")
            completionHandler(user)
            return
        }

        if let err = err {
            print("There was an error finding the user: \(err)")
            completionHandler(user)
            return
        }

        let docsList = querySnapshot.documents
        if docsList.count == 1 { // expected case we want
            print("Found by \(searchKey)!") // temp
            user = docsList[0].data()
        } else if docsList.count == 0 {
            print("Not found by \(searchKey)!") // temp
        } else { // error case...
            print("Ok, we should NOT be getting more than 1 result from \(searchKey), kekw!")
        }
        completionHandler(user)
        return
    }
}

我是这样称呼它的:

var userFound: Dictionary<String, Any>?             
findUser(searchKey: "email", searchValue: search) { (result) in
    print("Ok we got our first result")
    print(result)
    if result != nil {
        userFound = result!
    } 

}

// this chunk of code is being called BEFORE the results closure
if userFound == nil {
    print("Not found!")
} else {
    print("Found!")
}

补充说明:

我想实现类似的目标,

  1. 点击搜索
  2. Firebase 找到用户
  3. 声明用户找到
  4. 返回用户

目前是:

  1. 点击搜索
  2. 声明未找到用户
  3. 不返回任何内容
  4. Firebase 找到用户

修改正确的解决方案!

findUser() 不需要更改,但我的代码结构需要更改。在回调部分,需要进行此更改:

var userFound: Dictionary<String, Any>?             
findUser(searchKey: "email", searchValue: search) { (result) in
    print("Ok we got our first result")
    print(result)
    if result != nil {
        userFound = result!
    } 
   // this chunk of code is being called BEFORE the results closure
   if userFound == nil {
       print("Not found!")
   } else {
       print("Found!")
   }
}
// There should NOT be code after this to mimic a synchronous step of retrieving user --> loading!

【问题讨论】:

  • 当您说"my code below this function call is NOT waiting for this closure to be completed" 时,我能否澄清一下,这是指在findUser 回调内部(} 之前)还是外部(} 之后)?
  • 我的程序会首先声明一个用户“未找到!”然后找到一个用户并打印该用户。这有意义吗@George_E
  • 编辑有帮助。这是我的答案修复的确切解决方案,希望现在一切正常!
  • 这段代码if userFound == nil真的直接跟在findUser(searchKey后面吗?如果是这样,那就是问题所在,您已经绕过异步处理数据。代码比 Internet 更快,并且 findUser 中的代码需要一些时间才能运行,例如它依赖于 Firebase 从服务器返回的结果。只需将该代码移动到 findUser 闭包中即可。

标签: swift firebase firebase-realtime-database


【解决方案1】:

completionHandler 被调用时,这称为回调。例如,只要您调用completionHandler(["hello": "world"]),它就会运行您拥有print("Ok we got our first result") 的代码。

虽然回调内部的这段代码只有在工作完成后才会被调用,但外部的一切都会继续运行,不会有任何延迟。这类似于使用DispatchQueue时:

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    print("Delays by 1 second")
}

print("Instant")

解决方案是运行所有必须在回调内部等待的代码,如下:

if result != nil {
    userFound = result!
}

if userFound == nil {
    print("Not found!")
} else {
    print("Found!")
}

提示:除了上面的代码,为了更简洁的代码并减少由于强制展开导致的错误/崩溃风险,您可以这样做:

guard let result = result else { return }
print("Result:", result)

let userFound = result["user"] // I don't know what this variable is, but I can assume it comes from the result

if userFound == nil {
    print("Not found!")
} else {
    print("Found!")
}

【讨论】:

  • 感谢您的意见!我不确定我是否理解如何运行必须在语法上等待回调的代码。有没有机会给我举个例子?
  • @LeoLien 更新了我的答案,希望能反映代码应该去哪里。
【解决方案2】:

代码是非常接近的问题,您正在正确处理 Firebase 的异步性质,除了一件事:(Firebase) 闭包之后的代码将在闭包内的代码之前执行。

Firebase 返回结果需要时间,而且代码比互联网更快。因此,您需要在其闭包内(或在本例中的完成处理程序内)处理 Firebase 数据

解决方法是在数据可用时像这样处理数据

findUser(searchKey: "email", searchValue: search) { (result) in
    if result != nil {
        print("user was found")
        //go do something with the user
    } else {
        print("no user was found!")
    }
}
//any code here will execute before the code in the above closure

【讨论】:

  • 澄清一下:这是否意味着对于我的按钮功能,所有发布 Firebase 闭包的代码都必须在闭包本身内处理,否则它将以异步方式运行?
  • @LeoLien 是的,我想。让我重新陈述我的答案; firebase 闭包是异步的;从 Firebase 返回的数据仅在该闭包内有效。如果你看我的回答,findUser 调用了一个 Firebase 函数;该函数从 Firebase 获取一些数据,当该数据在闭包内从互联网返回时,它会传递给完成处理程序并返回给 findUser 作为结果。所以在结束之后}我有 //这里的任何代码将......意思是如果你用print("Hello, World")替换它然后你好,世界将在找到任何一个用户或没有找到用户之前打印
猜你喜欢
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2015-06-02
  • 2021-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多