dispatch_get_main_queue()在从一个ViewController移动到另一个ViewControl



在我的应用程序中,我在后台执行长任务。所以我使用Grand Central Dispatch (GCD)并在主队列中更新UI。

我的代码

dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0), {
    // perform long task
    //update UI   
     dispatch_async(dispatch_get_main_queue(), {
           self.Label.text = "value changed"  // not work
           self.collectionView.reloadData() // work properly
        })    
})  

它会工作的很好。但是,当我从当前的ViewController移动到NextViewController并再次回到ViewController时,执行后台任务,但我的Label不会改变。

问题:请帮助我,所以我可以更新我的UI时,从另一个ViewController

注意:对于移动一个ViewController到另一个任务是在主队列中执行。

EDIT:这是@Yuri代码的输出

2015-06-08 14:34:19.565 myApp[7726:1481939]  before: self:Logic() `self.label:<myApp.ViewController: 0x15947e00>
2015-06-08 14:34:50.925 myApp[7726:1481925]  after: self:Logic() self.label:<myApp.ViewController: 0x15947e00>`  

Edit2这里是@Oyeoj

的输出
before: <UILabel: 0x16565c60; frame = (20 56; 104 18); text = 'Back up'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x16565eb0>>
after: <UILabel: 0x16565c60; frame = (20 56; 104 18); text = 'value changed'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x16565eb0>>

UI的更新必须在主线程中进行,很可能你在UI中的更新将无法工作。

试试这个:

dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0), {
    dispatch_async(dispatch_get_main_queue(), {
         println("before: (self.Label)")
         self.collectionView.reloadData() 
         self.Label.text = "value changed"
         self.Label.setNeedsDisplay() // don't forget this line..
         println("after: (self.Label)")
    })    
})  

编辑1

好吧,我被否决了,至少我能知道为什么吗?只是为了我的教诲,谢谢你…

从你的@edit2日志,似乎self.Label.text的值被更新,但你的UIViewController不是在主线程的控制。

,我将建议您使用NSNotificationCenter来触发ViewController

中的更新。

现在看起来是这样的:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "methodReceiver:", name:"NotificationIdentifier", object: nil)
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0), {
    //long task
    dispatch_async(dispatch_get_main_queue(), {
         // sends notification to `methodReceiver` 
        NSNotificationCenter.defaultCenter().postNotificationName("NotificationIdentifier", object: nil)
    })    
})
@objc func methodReceiver(notification: NSNotification){
    dispatch_async(dispatch_get_main_queue(), {
        self.collectionView.reloadData() 
        self.Label.text = "value changed"
        self.Label.setNeedsDisplay() // don't forget this line..
    })

    // in case you want to remove the Observer after notification was delivered 
    NSNotificationCenter.defaultCenter().removeObserver(self, name: "NotificationIdentifier", object: nil)
}

希望这对你有帮助。

编辑2

从评论

:this approach is work , but i want to know why my UIViewController is not in controll of main thread

dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0)

你正在后台处理(长任务),不会阻塞任何主线程活动…

然后你改变到AnotherUIViewControllerUI更新,现在你的主线程是在AnotherUIViewController的控制,而dispatch_async(dispatch_get_global_queue(仍在进行中,然后让我们说你回到UIViewController然后dispatch_async(dispatch_get_main_queue(), {被触发,但AnotherUIViewController内部的任务还没有完成,

,例如:

[self.navigationController popViewControllerAnimated:YES]; // -> (in objective-C code)

或任何其他当前正在进行的UI更新将在UIViewController再次控制主线程之前首先处理,因为所有调度队列都是FIFO.

我相信这就是它的工作原理。

有关更多信息,请参阅Grand Central Dispatch (GCD) Reference from apple.

检查指针是否相同?

我的be块从未调用?

NSLog(@"%s before: self:%@ self.label:%@", __PRETTY_FUNCTION__, self, self.Label);
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_BACKGROUND.value), 0), {
       // perform long task
       //update UI   
       dispatch_async(dispatch_get_main_queue(), {
          self.Label.text = "value changed"
          NSLog(@"%s after: self:%@ self.label:%@", ____PRETTY_FUNCTION__, self, self.Label);        
       })    
})