栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

从功能返回之前,等待Firebase加载

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

从功能返回之前,等待Firebase加载

(关于此问题的变化经常出现在SO上。我永远找不到一个好的,全面的答案,因此下面尝试提供这样的答案)

你不能那样做。Firebase是异步的。其功能采用完成处理程序并立即返回。您需要重写loadFromFirebase函数以获取完成处理程序。

我在Github上有一个名为 Async_demo
(link)的示例项目,它是一个正在运行的(Swift 3)应用程序,说明了该技术。

其中的关键部分是function

downloadFileAtURL
,它需要一个完成处理程序并进行异步下载:

typealias DataClosure = (Data?, Error?) -> Voidclass DownloadManager: NSObject {  static var downloadManager = DownloadManager()  private lazy var session: URLSession = {    return URLSession.shared  }()          func downloadFileAtURL(_ url: URL, completion: @escaping DataClosure) {        //We create a URLRequest that does not allow caching so you can see the download take place        let request = URLRequest(url: url,cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,timeoutInterval: 30.0)        let dataTask = URLSession.shared.dataTask(with: request) {          //------------------------------------------          //This is the completion handler, which runs LATER,          //after downloadFileAtURL has returned.          data, response, error in          //Perform the completion handler on the main thread          DispatchQueue.main.async() { //Call the copmletion handler that was passed to us completion(data, error)          }          //------------------------------------------        }        dataTask.resume()        //When we get here the data task will NOT have completed yet!      }    }

上面的代码使用Apple的

URLSession
类从异步服务器异步下载数据。创建时
dataTask
,您传入一个完成处理程序,该处理程序在数据任务完成(或失败)时被调用。但是请注意:您的完成处理程序在后台线程上被调用。

很好,因为如果您需要执行诸如解析大型JSON或XML结构之类的耗时的处理,则可以在完成处理程序中进行处理而不会导致应用程序的UI冻结。但是,结果是,如果不将这些UI调用发送到主线程,就无法在数据任务完成处理程序中进行UI调用。上面的代码使用调用在主线程上调用了整个完成处理程序

DispatchQueue.main.async(){}

返回OP的代码:

我发现以闭包作为参数的函数很难读取,因此我通常将闭包定义为类型别名。

通过@ Raghav7890的答案重做代码以使用typealias:

typealias SongArrayClosure = (Array<Song>?) -> Voidfunc loadFromFirebase(completionHandler: @escaping SongArrayClosure) {    ref.observe(.value, with: { snapshot in        var songArray:Array<Song> = []        //Put pre here to load songArray from the Firebase returned data        if songArray.isEmpty { completionHandler(nil)        }else { completionHandler(songArray)        }    })}

我已经很久没有使用Firebase了(然后只修改了别人的Firebase项目),所以我不记得它是在主线程还是在后台线程上调用它的完成处理程序。如果它在后台线程上调用完成处理程序,那么您可能希望将对完成处理程序的调用包装在对主线程的GCD调用中。


编辑:

根据 这个SO问题的答案,听起来Firebase确实在后台线程上进行网络调用,但是在主线程上调用了侦听器。

在那种情况下,您可以忽略以下有关Firebase的代码,但是对于那些阅读此线程以寻求其他种类的异步代码帮助的人,可以按照以下方法重写代码以在主线程上调用完成处理程序:

typealias SongArrayClosure = (Array<Song>?) -> Voidfunc loadFromFirebase(completionHandler:@escaping SongArrayClosure) {    ref.observe(.value, with: { snapshot in        var songArray:Array<Song> = []        //Put pre here to load songArray from the Firebase returned data        //Pass songArray to the completion handler on the main thread.        DispatchQueue.main.async() {          if songArray.isEmpty { completionHandler(nil)          }else { completionHandler(songArray)          }        }    })}


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/367970.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号