2016-11-04 47 views
1

我是苹果公司的GCD新手,并且与DispatchGroup存在问题。 因此,我试图在帖子完全初始化后将帖子附加到地图上。在post.init内部,有一个URLSession从url下载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() 

    } 

} 

回答

2

init(值:)中的完成处理程序只会在任务完成时触发,无论何时可能。但是,在调用.resume()代码执行后,将继续执行,这意味着init将退出并且您的group.notify块将立即被调用。

你可以用各种方式处理这个问题。一种方法是为Post类设置一个委托协议,并将ViewController设置为该委托。在你完成处理程序中,你可以调用一个函数 - 为了参数调用它didFinish() - 它会告诉视图控制器该任务已经完成。你可以在你的函数中包装你的通知。

这样做的事情,但是,我会从初始化函数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() 

    } 

} 

希望是有道理的,更重要的是,它可以帮助!

+0

感谢您的回复,但取出通知将是一个问题,因为我现在无法从'didFinish'访问变量'post'和'location'。对此有何建议? –

+0

其实我做到了!我通过委托方法传递了变量。谢谢! –