我是Apple的GCD的新手并且遇到DispatchGroup
的问题。
所以,我试图在帖子完全初始化后将帖子附加到地图上。在post.init
内,有URLSession
从网址下载UIImage
。但即使在下载完成之前,group.notify
也会被解雇。我真的找不到原因。下面是代码。我真的很感激任何建议或帮助!感谢。
// ViewController.swift
let group = DispatchGroup
...
...
group.enter()
DispatchQueue.global(qos: .userInitiated).async {
post = Post(values: post)
self.posts[postId] = post
group.leave()
}
group.notify(queue: DispatchQueue.main, execute: {
print("notify:: \(post?.picture)") // This prints out nil, when it shouldn't.
self.addPostToMap(post!, at: location!)
})
// Post.swift
class Post {
var picture: UIImage?
var thumbnail: UIImage?
init(values: [String: Any]) {
...
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
DispatchQueue.main.async {
self.picture = UIImage(data: data!)
self.thumbnail = Util.resizeImage(image: self.picture!, targetSize: CGSize(width: 50, height: 50))
}
}).resume()
}
}
答案 0 :(得分:2)
init(values :)中的完成处理程序只有在任务完成时才会被触发。但是,在调用.resume()代码后,代码执行将继续,这意味着init将退出,并且您的group.notify块将立即被调用。
您可以通过各种方式处理此问题。一种方法是为Post类设置委托协议,并将ViewController设置为该委托。在你的完成处理程序中,你可以调用一个函数 - 为了参数调用它的didFinish() - 它将告诉视图控制器任务已经完成。您可以将通知包装在该功能中。
然而,这样做,我会从init函数中取出dataTask。这样做的原因是委托通常被声明为隐式解包的选项,并从创建类设置。因此,当您初始化类时,当您调用委托回调时,委托可能不会引用任何内容。
所以结构如下:
// ViewController.swift
class ViewController : UIViewController, PostDelegate {
let group = DispatchGroup
...
...
group.enter()
DispatchQueue.global(qos: .userInitiated).async {
post = Post(values: post)
post.delegate = self
post.getImage() // New function
self.posts[postId] = post
group.leave()
}
....
func didFinish() -> Void {
group.notify(queue: DispatchQueue.main, execute: {
print("notify:: \(post?.picture)")
self.addPostToMap(post!, at: location!)
})
....
Protocol PostDelegate {
func didFinish() -> Void
}
// Post.swift
class Post {
var delegate : PostDelegate!
var picture: UIImage?
var thumbnail: UIImage?
init(values: [String: Any]) {
...
}
func getImage() -> Void {
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in
DispatchQueue.main.async {
self.picture = UIImage(data: data!)
self.thumbnail = Util.resizeImage(image: self.picture!, targetSize: CGSize(width: 50, height: 50))
if delegate != nil {
delegate.didFinish() // Tell the delegate you are done
}
}
}).resume()
}
}
希望有意义,更重要的是,它有所帮助!