调度组在工作完成前通知

时间:2016-11-04 04:34:16

标签: ios swift multithreading

我是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()

    }

}

1 个答案:

答案 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()

    }

}

希望有意义,更重要的是,它有所帮助!