使用 Grand Central Dispatch 的问题 IOS Swift Xcode 6.3.1
problems using Grand Central Dispatch IOS Swift Xcode 6.3.1
我正在学习 swift,但很难理解多线程问题..
我遇到的具体问题是我正在从互联网加载数据并且
在使用 dispatch_async 时尝试 return 包含此数据的数组 ("broadcasts")。
我的问题是空数组的 return 执行发生在
数组中填满了数据(这一行 "println(broadcasts)" 发生但数组 return 为空..)
这是我的代码:
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)**
}
}
并且在 class TableViewController-
public class TableViewController: UITableViewController {
...
...
public func requestFinished(requestedBroadcasts: [BroadcastModel]) {
self.broadcasts = requestedBroadcasts
self.tableView.reloadData()
}
现在我得到错误:
无法使用类型为“([(BroadcastModel)])”
的参数列表调用 'requestFinished'
由于 DataManager.getBroadcastsFromTweeterWithSuccess
的关闭,return broadcasts
在 之前 执行了将数据附加到数组的循环。
您的代码有误。在闭包中的代码甚至还没有开始执行之前,立即调用 dispatch_async returns 这样的 GCD 函数。这就是并发编程的本质。
您不能编写发出调用然后在下一行得到答案的异步代码。相反,您需要更改逻辑,以便调用分派异步,然后调用 return 并在块完成之前忘记请求。然后将处理结果的代码放在闭包中。您可以在闭包中添加一个调用,在主线程上调用您的应用程序以通知它处理已完成。
编辑:
您的新代码有多个问题:
您对 dispatch_async 的调用正在使用主队列,这是主线程上的一个队列。如果您的目标是让此代码在后台达到 运行,则此代码无法做到这一点。
对TableViewController.requestFinished(broadcasts)
的调用还是在错误的地方。在获取数据后,它需要位于块内。它也需要在主线程上执行。
对 TableViewController.requestFinished(broadcasts)
的调用似乎是向 TableViewController class 而不是向 TableViewController class 的实例发送消息,这是错误的。除非您的块有权访问您要将消息发送到的 TableViewController 实例,否则您无法解决此问题。
您或许应该重构您的 requestNewBroadcasts 方法,如下所示:
- 不要return任何东西。 (在异步块完成之前,结果将不可用。)
- 让 requestNewBroadcasts 接受一个完成块(或者更确切地说是一个闭包,因为它们在 Swift 中被调用)。完全摆脱
TableViewController.requestFinished(broadcasts)
调用,而是让您的网络代码在网络请求完成后调用完成块。
- 调用 dispatch_async 使用后台队列而不是主队列,这样您的任务实际上 运行 秒在后台。
- 让您的 requestNewBroadcasts 方法调用主线程上的完成块。
其中的每一个步骤都需要您的工作和研究。
弄清楚如何将闭包添加为参数需要深入挖掘。 (参见 Swift Programming Language iBook。解释得很好。)
弄清楚如何获得后台队列需要花功夫。 (请参阅 GCD 上的 Xcode docs 文档。特别是 dispatch_get_global_queue)
弄清楚如何从后台线程调用主线程需要研究(再次参见 GCD 上的 Xcode 文档。提示:您当前对 dispatch_async 的调用正在发送您的阻塞到主线程上的队列。)。
我正在学习 swift,但很难理解多线程问题..
我遇到的具体问题是我正在从互联网加载数据并且 在使用 dispatch_async 时尝试 return 包含此数据的数组 ("broadcasts")。
我的问题是空数组的 return 执行发生在 数组中填满了数据(这一行 "println(broadcasts)" 发生但数组 return 为空..)
这是我的代码:
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)**
}
}
并且在 class TableViewController-
public class TableViewController: UITableViewController {
...
...
public func requestFinished(requestedBroadcasts: [BroadcastModel]) {
self.broadcasts = requestedBroadcasts
self.tableView.reloadData()
}
现在我得到错误: 无法使用类型为“([(BroadcastModel)])”
的参数列表调用 'requestFinished'DataManager.getBroadcastsFromTweeterWithSuccess
的关闭,return broadcasts
在 之前 执行了将数据附加到数组的循环。
您的代码有误。在闭包中的代码甚至还没有开始执行之前,立即调用 dispatch_async returns 这样的 GCD 函数。这就是并发编程的本质。
您不能编写发出调用然后在下一行得到答案的异步代码。相反,您需要更改逻辑,以便调用分派异步,然后调用 return 并在块完成之前忘记请求。然后将处理结果的代码放在闭包中。您可以在闭包中添加一个调用,在主线程上调用您的应用程序以通知它处理已完成。
编辑:
您的新代码有多个问题:
您对 dispatch_async 的调用正在使用主队列,这是主线程上的一个队列。如果您的目标是让此代码在后台达到 运行,则此代码无法做到这一点。
对TableViewController.requestFinished(broadcasts)
的调用还是在错误的地方。在获取数据后,它需要位于块内。它也需要在主线程上执行。
对 TableViewController.requestFinished(broadcasts)
的调用似乎是向 TableViewController class 而不是向 TableViewController class 的实例发送消息,这是错误的。除非您的块有权访问您要将消息发送到的 TableViewController 实例,否则您无法解决此问题。
您或许应该重构您的 requestNewBroadcasts 方法,如下所示:
- 不要return任何东西。 (在异步块完成之前,结果将不可用。)
- 让 requestNewBroadcasts 接受一个完成块(或者更确切地说是一个闭包,因为它们在 Swift 中被调用)。完全摆脱
TableViewController.requestFinished(broadcasts)
调用,而是让您的网络代码在网络请求完成后调用完成块。 - 调用 dispatch_async 使用后台队列而不是主队列,这样您的任务实际上 运行 秒在后台。
- 让您的 requestNewBroadcasts 方法调用主线程上的完成块。
其中的每一个步骤都需要您的工作和研究。
弄清楚如何将闭包添加为参数需要深入挖掘。 (参见 Swift Programming Language iBook。解释得很好。)
弄清楚如何获得后台队列需要花功夫。 (请参阅 GCD 上的 Xcode docs 文档。特别是 dispatch_get_global_queue)
弄清楚如何从后台线程调用主线程需要研究(再次参见 GCD 上的 Xcode 文档。提示:您当前对 dispatch_async 的调用正在发送您的阻塞到主线程上的队列。)。