0

我现在正在快速学习并且很难理解多线程问题..

我遇到的具体问题是我正在从互联网加载数据并尝试在使用 dispatch_async 时返回包含此数据的数组(“广播”)。

我的问题是空数组的返回执行发生在数组填充数据之前(这一行“println(broadcasts)”发生但数组返回空..)

这是我的代码:

import UIKit

public class BroadcastRequest {

    func requestNewBroadcasts() -> [BroadcastModel] {
        var broadcasts = [BroadcastModel]()
        var sectionsOfBroadcasts = [[BroadcastModel]]()
        DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                let json = JSON(data: youTubeData)

                if let broadcastsArray = json["result"].array {

                    for broadcastDict in broadcastsArray{
                        var broadcastID: String? = broadcastDict["id"].string
                        var broadcastURL: String? = broadcastDict["broadcast"].string

                        DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
                            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                                let json2 = JSON(data: youTubeData)
                                if let broadcastDetailsDict = json2["result"].dictionary {

                                    var cover: String! = broadcastDetailsDict["cover"]!.string
                                    var caption: String! = broadcastDetailsDict["caption"]!.string
                                    var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
                                    broadcasts.append(broadcast)
                                    **println(broadcasts)**
                                }
                            }
                        }
                    }
                }
            }
        }
        **return broadcasts**
    }
}

查看答案后,我将代码更改为:

import UIKit

public class BroadcastRequest {

    func requestNewBroadcasts() {
        var broadcasts = [BroadcastModel]()
        var sectionsOfBroadcasts = [[BroadcastModel]]()
        DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                let json = JSON(data: youTubeData)

                if let broadcastsArray = json["result"].array {

                    for broadcastDict in broadcastsArray{
                        var broadcastID: String? = broadcastDict["id"].string
                        var broadcastURL: String? = broadcastDict["broadcast"].string

                        DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
                            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                                let json2 = JSON(data: youTubeData)
                                if let broadcastDetailsDict = json2["result"].dictionary {

                                    var cover: String! = broadcastDetailsDict["cover"]!.string
                                    var caption: String! = broadcastDetailsDict["caption"]!.string
                                    var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
                                    broadcasts.append(broadcast)
                                    println(broadcasts)
                                }
                            }
                        }
                    }
                }
            }
        }
        **TableViewController.requestFinished(broadcasts)**
    }
}

在类 TableViewController-

public class TableViewController: UITableViewController {

...
...


    public func requestFinished(requestedBroadcasts: [BroadcastModel]) {
       self.broadcasts = requestedBroadcasts
       self.tableView.reloadData()
    }

现在我收到错误:无法使用“([(BroadcastModel)])”类型的参数列表调用“requestFinished”

4

2 回答 2

2

你的代码是错误的。在闭包中的代码甚至开始执行之前,对像 dispatch_async 这样的 GCD 函数的调用会立即返回。这就是并发编程的本质。

您不能编写异步代码来拨打电话,然后在下一行得到答案。相反,您需要更改逻辑,以便调用调度异步,然后返回并忘记请求,直到块完成。然后将处理结果的代码放入闭包中。您可以在闭包内添加一个调用,在主线程上调用您的应用程序,以通知它处理已完成。

编辑:

您的新代码有多个问题:

您对 dispatch_async 的调用正在使用主队列,它是主线程上的一个队列。如果您的目标是让此代码在后台运行,则此代码无法做到这一点。

调用到TableViewController.requestFinished(broadcasts)仍然在错误的地方。在获取数据后,它需要在块内。它还需要在主线程上执行。

调用TableViewController.requestFinished(broadcasts)似乎是向 TableViewController 类发送消息,而不是向 TableViewController 类的实例发送消息,这是错误的。除非您的块有权访问要将消息发送到的 TableViewController 实例,否则您无法解决此问题。

您可能应该重构您的 requestNewBroadcasts 方法,如下所示:

  • 让它不返回任何东西。(无论如何,直到异步块完成后,结果才可用。)
  • 使 requestNewBroadcasts 接受一个完成块(或者更确切地说是一个闭包,因为它们在 Swift 中被调用)。完全摆脱TableViewController.requestFinished(broadcasts)调用,而是让您的网络代码在网络请求完成后调用完成块。
  • 使您对 dispatch_async 的调用使用后台队列而不是主队列,以便您的任务实际上在后台运行。
  • 使您的 requestNewBroadcasts 方法调用主线程上的完成块。

这些步骤中的每一个都需要您进行工作和研究。

弄清楚如何将闭包作为参数添加将需要挖掘。(参见 Swift Programming Language iBook。它解释得很好。)

弄清楚如何获得后台队列将需要工作。(请参阅 GCD 上的 Xcode 文档文档。特别是查看 dispatch_get_global_queue)

弄清楚如何从后台线程调用主线程将需要研究(再次参见 GCD 上的 Xcode 文档。提示:您当前对 dispatch_async 的调用正在将您的块发送到主线程上的队列。)。

于 2015-04-29T11:19:58.510 回答
1

return broadcasts由于' 的关闭,在将数据附加到数组的循环之前执行。DataManager.getBroadcastsFromTweeterWithSuccess

于 2015-04-29T10:54:18.583 回答