热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Swift:在返回函数之前等待Firebase加载-Swift:WaitforFirebasetoloadbeforereturnafunction

Ihaveasimplefunctionloadingdatefromfirebase.我有一个来自firebase的简单函数加载日期。funcloadFromFireBase

I have a simple function loading date from firebase.

我有一个来自firebase的简单函数加载日期。

func loadFromFireBase() -> Array? {
    var songArray:Array = []

    ref.observe(.value, with: { snapshot in
        //Load songArray
    })

    if songArray.isEmpty {
        return nil
    }
    return songArray
}

Currently this function returns nil always even though there is data to load. It does this because it doesn't ever get to the perform the completion block where it loads the array before the function returns. I'm looking for a way to make the function only return once the completion block has been called but I can't put return in the completion block.

目前,即使有要加载的数据,此函数也会返回nil。它这样做是因为它不会在函数返回之前执行完成块,它会加载数组。我正在寻找一种方法,只有在调用完成块后才能返回该函数,但我无法在完成块中返回。

2 个解决方案

#1


11  

(Variations on this question come up constantly on SO. I can never find a good, comprehensive answer, so below is an attempt to provide such an answer)

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

You can't do that. Firebase is asynchronous. Its functions take a completion handler and return immediately. You need to rewrite your loadFromFirebase function to take a completion handler.

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

I have a sample project on Github called Async_demo (link) that is a working (Swift 3) app illustrating this technique.

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

The key part of that is the function downloadFileAtURL, which takes a completion handler and does an async download:

关键部分是函数downloadFileAtURL,它接受一个完成处理程序并执行异步下载:

typealias DataClosure = (Data?, Error?) -> Void

/**
 This class is a trivial example of a class that handles async processing. It offers a single function, `downloadFileAtURL()`
 */
class DownloadManager: NSObject {

  static var downloadManager = DownloadManager()

  private lazy var session: URLSession = {
    return URLSession.shared
  }()

    /**
     This function demonstrates handling an async task.
     - Parameter url The url to download
     - Parameter completion: A completion handler to execute once the download is finished
     */

      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!
      }
    }

The code above uses Apple's URLSession class to download data from a remote server asynchronously. When you create a dataTask, you pass in a completion handler that gets invoked when the data task has completed (or failed.) Beware, though: Your completion handler gets invoked on a background thread.

上面的代码使用Apple的URLSession类以异步方式从远程服务器下载数据。当您创建dataTask时,您传入一个完成处理程序,该处理程序在数据任务完成(或失败)时被调用。但要注意:您的完成处理程序在后台线程上被调用。

That's good, because if you need to do time-consuming processing like parsing large JSON or XML structures, you can do it in the completion handler without causing your app's UI to freeze. However, as a result you can't do UI calls in the data task completion handler without sending those UI calls to the main thread. The code above invokes the entire completion handler on the main thread, using a call to DispatchQueue.main.async() {}.

这很好,因为如果您需要执行耗时的处理(如解析大型JSON或XML结构),您可以在完成处理程序中执行此操作,而不会导致应用程序的UI冻结。但是,因此,如果不将这些UI调用发送到主线程,则无法在数据任务完成处理程序中执行UI调用。上面的代码使用对DispatchQueue.main.async(){}的调用来调用主线程上的整个完成处理程序。

Back to the OP's code:

回到OP的代码:

I find that a function with a closure as a parameter is hard to read, so I usually define the closure as a typealias.

我发现一个带闭包作为参数的函数很难读,因此我通常将闭包定义为一个类型。

Reworking the code from @Raghav7890's answer to use a typealias:

从@ Raghav7890的答案重新编写代码以使用类型:

typealias SOngArrayClosure= (Array?) -> Void

func loadFromFireBase(completionHandler: @escaping SongArrayClosure) {
    ref.observe(.value, with: { snapshot in
        var songArray:Array = []
        //Put code here to load songArray from the FireBase returned data

        if songArray.isEmpty {
            completionHandler(nil)
        }else {
            completionHandler(songArray)
        }
    })
}

I haven't used Firebase in a long time (and then only modified somebody else's Firebase project), so I don't remember if it invokes it's completion handlers on the main thread or on a background thread. If it invokes completion handlers on a background thread then you may want to wrap the call to your completion handler in a GCD call to the main thread.

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


Edit:

Based on the answers to this SO question, it sounds like Firebase does it's networking calls on a background thread but invokes it's listeners on the main thread.

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

In that case you can ignore the code below for Firebase, but for those reading this thread for help with other sorts of async code, here's how you would rewrite the code to invoke the completion handler on the main thread:

在这种情况下,您可以忽略Firebase下面的代码,但对于那些阅读此线程以获取其他种类异步代码的帮助的人,以下是如何重写代码以调用主线程上的完成处理程序:

typealias SOngArrayClosure= (Array?) -> Void

func loadFromFireBase(completionHandler:@escaping SongArrayClosure) {
    ref.observe(.value, with: { snapshot in
        var songArray:Array = []
        //Put code 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)
          }
        }
    })
}

#2


2  

Making Duncan answer more precise. You can make the function like this

让邓肯的回答更精确。你可以做这样的功能

func loadFromFireBase(completionHandler:@escaping (_ songArray: [Song]?)->()) {
    ref.observe(.value) { snapshot in
        var songArray: [Song] = []
        //Load songArray
        if songArray.isEmpty {
            completionHandler(nil)
        }else {
            completionHandler(songArray)
        }
    }
}

You can return the songArray in a completion handler block.

您可以在完成处理程序块中返回songArray。


推荐阅读
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 在尝试对 QQmlPropertyMap 类进行测试驱动开发时,发现其派生类中无法正常调用槽函数或 Q_INVOKABLE 方法。这可能是由于 QQmlPropertyMap 的内部实现机制导致的,需要进一步研究以找到解决方案。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 本指南介绍了如何在ASP.NET Web应用程序中利用C#和JavaScript实现基于指纹识别的登录系统。通过集成指纹识别技术,用户无需输入传统的登录ID即可完成身份验证,从而提升用户体验和安全性。我们将详细探讨如何配置和部署这一功能,确保系统的稳定性和可靠性。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • 微信小程序实现类似微博的无限回复功能,内置云开发数据库支持
    本文详细介绍了如何利用微信小程序实现类似于微博的无限回复功能,并充分利用了微信云开发的数据库支持。文中不仅提供了关键代码片段,还包含了完整的页面代码,方便开发者按需使用。此外,HTML页面中包含了一些示例图片,开发者可以根据个人喜好进行替换。文章还将展示详细的数据库结构设计,帮助读者更好地理解和实现这一功能。 ... [详细]
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • FastDFS Nginx 扩展模块的源代码解析与技术剖析
    FastDFS Nginx 扩展模块的源代码解析与技术剖析 ... [详细]
  • 在Bugku Web CTF实战演练中,通过细致的源代码检查,我们发现了一个隐藏的滑稽笑脸图标,进一步分析后成功找到了flag。此外,还探讨了如何利用计算器功能进行安全测试,提升了对Web漏洞的识别和利用技巧。 ... [详细]
  • Python爬虫入门:深入解析HTTP协议与Requests库的应用
    Python爬虫入门:深入解析HTTP协议与Requests库的应用 ... [详细]
  • 本文介绍了一种利用PHP cURL库高效提取Sohu邮箱联系人列表的方法。通过设置错误报告级别、定义Cookie文件路径等关键步骤,确保了代码的稳定性和可靠性。经过实际测试,该方法在2012年3月24日被验证为有效,能够快速准确地获取联系人信息。此外,文章还提供了详细的代码示例和注意事项,帮助开发者更好地理解和应用这一技术。 ... [详细]
  • 在进行网络编程时,准确获取本地主机的IP地址是一项基本但重要的任务。Winsock作为20世纪90年代初由Microsoft与多家公司共同制定的Windows平台网络编程接口,为开发者提供了一套高效且易用的工具。通过Winsock,开发者可以轻松实现网络通信功能,并准确获取本地主机的IP地址,从而确保应用程序在网络环境中的稳定运行。此外,了解Winsock的工作原理及其API函数的使用方法,有助于提高开发效率和代码质量。 ... [详细]
  • Android 图像色彩处理技术详解
    本文详细探讨了 Android 平台上的图像色彩处理技术,重点介绍了如何通过模仿美图秀秀的交互方式,利用 SeekBar 实现对图片颜色的精细调整。文章展示了具体的布局设计和代码实现,帮助开发者更好地理解和应用图像处理技术。 ... [详细]
  • 深入解析Gradle中的Project核心组件
    在Gradle构建系统中,`Project` 是一个核心组件,扮演着至关重要的角色。通过使用 `./gradlew projects` 命令,可以清晰地列出当前项目结构中包含的所有子项目,这有助于开发者更好地理解和管理复杂的多模块项目。此外,`Project` 对象还提供了丰富的配置选项和生命周期管理功能,使得构建过程更加灵活高效。 ... [详细]
  • 在编译 PHP7 的 PDO MySQL 扩展时,可能会遇到 `[mysql_driver.lo]` 错误 1。该问题通常出现在 `pdo_mysql_fetch_error_func` 函数中。本文详细介绍了导致这一错误的常见原因,包括依赖库版本不匹配、编译选项设置不当等,并提供了具体的解决步骤和调试方法,帮助开发者快速定位并解决问题。 ... [详细]
author-avatar
再体验初体验g_154
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有