Swift,带有完成处理程序的网络调用不起作用

Posted

技术标签:

【中文标题】Swift,带有完成处理程序的网络调用不起作用【英文标题】:Swift, Network call with Completion Handler not working 【发布时间】:2020-05-13 07:49:19 【问题描述】:

我正在从 Firebase 读取数据,并希望使用闭包来了解调用何时完成。我的代码如下所示:

func fetchGameTexts(gameType : String, completion: @escaping ([String]) -> ())
    var fetchedArray = [String]()

    ref.child("GameTexts").child("JagHarAldrig").observe(.childAdded)  (snapshot, error) in
        if let userDict = snapshot.value as? [String:Any] 
            let userDictValue = userDict.values
            fetchedArray.append("\(userDictValue.first!)")

        
        completion(fetchedArray)
    


调用函数:

let FetchGameText = FetchGameTexts()
    FetchGameText.fetchGameTexts(gameType : "JagHarAldrig")  fetchedArray in
        print("inside completion handler : \(fetchedArray)")
    

现在网络调用按预期工作,但完成处理程序不工作,完成处理程序一次又一次地打印数组,而不是在调用完成时。

我试图将“completion(fetchedArray)”移动到 if let 块内以及 ref 调用之外。也没有工作。

感谢所有帮助。

编辑:

将调用的方法更改如下,回调有效,但输出打印出我不想要的键、值和额外信息。我只需要这些值。有什么想法吗?

func fetchGameTexts(gameType : String, completion: @escaping ([String]) -> ())
    var fetchedArray = [String]()

    ref.child("GameTexts").child(gameType).observe(.value)  (snapshot, error) in

        for child in snapshot.children 
            fetchedArray.append("\(child)")
        
        completion(fetchedArray)
    

【问题讨论】:

尝试使用等待调用完成并在完成时通知的调度队列。 这个fetchedArray.append("\(child)") 会将每个子快照附加到数组中(作为字符串?),这就是为什么您要获取每个子快照的所有数据。您的问题是“价值”;这很容易做到,但我们需要了解提出的价值和准确的解决方案。您能否包含您的 firebase 结构的 sn-p(请作为文本,没有图像)并指出您要获取的数据?此外,虽然 .value “有效”,但随着节点的增长,它可能包含大量数据,这可能会使设备不堪重负,因此应该避免这种情况。我有两个选择。 另外,你对数据做了什么?照原样,您将所有这些都转换为一个巨大的字符串数组,这并没有使它非常有用 - 也许它对您的用例有用? 【参考方案1】:

您实现完成和 Firebase 调用的方式似乎没有任何问题。每当更改父级时,都会多次调用完成块(或者如果我的记忆正确,它将为您当前在开始时拥有的每个子级触发),因为您正在收听.childAdded。它将继续这样做,直到您从 ref 中删除侦听器。

我的假设是您正在尝试获取所有孩子,因此您需要使用 .value 才能一次获取所有孩子。

为此,这也可能有所帮助: https://firebase.google.com/docs/database/ios/lists-of-data

【讨论】:

谢谢,我通读了文档并提出了这个,这使得完成处理程序工作,但是现在输出不是我想要的。我只想要输出中的值而不是键,请检查我的编辑。 你差不多明白了,child 可能是Dictionary,所以你可以通过手工挑选来获得所需的物品。这是另一个假设,您还应该打印 child 并分享其中的实际内容。 @olle 这是正确的,因为 .childAdded 最初一次遍历所有子节点,但之后仅在添加新子节点时触发。但是,.value 可能很危险,因为它每次发生任何类型的更改时都会加载节点中的所有数据。这会推动大量数据,如果它是一个大节点,可能会压倒设备内存。对于较小的数据集或不会增长的节点,这很好,除此之外,应该避免使用更精细的函数,如 .childAdded、.childChanged 和 .childRemoved。 @Jay 引用 Firebase 本身的话,“当您想在单个操作中获取列表的所有子项而不是侦听其他添加的子项事件时,此模式 (.value) 会很有用。”但我同意你的看法,除非价值观察是单个事件,这里应该是这样。 是的,没错,但请阅读上面的部分,将 FIRDataEventTypeValue 观察器附加到数据列表将返回整个数据列表,如果节点很大。换句话说, .childAdded 在添加孩子时触发。 .value 事件在添加孩子时触发,以及任何其他更改。如果您查看问题中的代码,任何时候 anything 更改整个节点都会重新加载。最重要的是,所有的数据都被塞进了一个字符串,这使得它不是很有用。

以上是关于Swift,带有完成处理程序的网络调用不起作用的主要内容,如果未能解决你的问题,请参考以下文章

单击按钮的Swift重新加载集合视图不起作用

Swift URL 会话和 URL 请求不起作用

带有约束的 UIViewAnimation 在 Swift 中不起作用

带有圆角和阴影的 Swift uiview 不起作用

使用委托包装异常处理时,Web-API 调用不起作用

带有结构的 C++ 向量不起作用?