【问题标题】:Swift array showing up empty after using completion handler使用完成处理程序后 Swift 数组显示为空
【发布时间】:2020-09-02 06:47:48
【问题描述】:

我正在尝试从 Firebase 数据库中获取服务列表。这是我的参考:

let REF_SERVICES = DB_REF.child("services")

这是我的获取函数:

func fetchServices(completion: @escaping([Service]) -> Void) {
    var services = [Service]()
    REF_SERVICES.observe(.value) { (snapshot) in
        for child in snapshot.children.allObjects as! [DataSnapshot] {
            guard let dictionary = child.value as? [String : Any] else { return }
            let title = child.key
            let service = Service(title: title, dictionary: dictionary)
            services.append(service)
        }
    }
    completion(services)
}

这是 Service 结构:

enum ServiceStatus: Int {
    case available
    case busy
}

struct Service {
    let title: String
    var details: String?
    var location: CLLocation?
    var status: ServiceStatus!

    init(title: String, dictionary: [String: Any]) {
        self.title = title
        if let details = dictionary["details"] as? String {
            self.details = details
        }
        if let index = dictionary["status"] as? Int {
            self.status = ServiceStatus(rawValue: index)
        }
    }
}

我不太了解完成处理程序和异步调用是如何工作的,所以我不知道如何让它工作。

这是我在 ViewController 中调用此函数的地方:

private var services: [Service]? {
    didSet {
        let addServiceController = AddServiceController()
        addServiceController.services = self.services!
    }
}

func fetchServices() {
    Services.shared.fetchServices { (services) in
        self.services = services
    }
}

在两个 ViewController 中,数组都显示为空。我通过使用 print 语句来验证它是否正在获取数据,从而使用了调试的圣杯。

谢谢。

【问题讨论】:

  • 我确信@arturdev 的回答是正确的。顺便说一句,我只是想知道您的 ViewController 的 services 属性的 didSet 打算做什么? addServiceController 是在 didSet 中创建的,这看起来有点奇怪。 :-)
  • @KyokookHwang 我实例化它以访问该 ViewController 中的 services 数组。尽管最好将HomeController 中的那个设为静态以便能够在AddServiceController 中访问

标签: swift firebase swift5


【解决方案1】:

您需要将completion(services) 调用移到observe 方法的完成回调中。

func fetchServices(completion: @escaping([Service]) -> Void) {
    var services = [Service]()
    REF_SERVICES.observe(.value) { (snapshot) in
        for child in snapshot.children.allObjects as! [DataSnapshot] {
            guard let dictionary = child.value as? [String : Any] else { return }
            let title = child.key
            let service = Service(title: title, dictionary: dictionary)
            services.append(service)
        }
        completion(services) //<-- at this point services will contain the info you appended in for loop
    }
}

【讨论】:

    【解决方案2】:

    类似于arturdev上面所说的,你需要把completion放在observe方法里面。 Firebase 调用是异步代码,这基本上意味着代码尽可能快地执行,而不是从上到下。因此,在您的原始函数中,完成是在 REF_SERVICES 执行后立即调用的,而不是在 REF_SERVICES 函数中的代码之后。

    我相信你还需要包含一个循环计数器,否则完成只会在 1 个循环后执行(同样,异步将尽快执行)。

    最后一个提示是尽量避免使用“as!”在您的代码中,而是使用 if let 语句。如果由于某种原因,您的数据库中出现问题并且无法将数据转换为 [DataSnapshot],您的应用就会崩溃。

    下面的代码应该可以工作,但我还没有测试过。祝你好运!

    func fetchServices(completion: @escaping (_ [Service]?) -> ()) {
        REF_SERVICES.observe(.value) { (snapshot) in
            if let data = snapshot.children.allObjects as? [DataSnapshot] {
                var services = [Service]()
                var counter = 0
                for child in data {
                    let title = child.key
                    if let dictionary = child.value as? [String : Any] {
                        let service = Service(title: title, dictionary: dictionary)
                        services.append(service)
                        counter = counter + 1
                        if counter == data.count {
                            completion(services)
                        }
                    } else {
                        print("There was an error casting dictionary for \(title)")
                        counter = counter + 1
                        if counter == data.count {
                            completion(services)
                        }
                    }
                }
            } else {
                print("Could not cast data as [DataSnapshot]")
                return nil
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多