在我的应用程序中,我在后台执行长任务。所以我使用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)
你正在后台处理(长任务),不会阻塞任何主线程活动…
然后你改变到AnotherUIViewController
有UI
更新,现在你的主线程是在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);
})
})