dispatch_get_main_queue() 在从一个 ViewController 移动到另一个 ViewController 并再次返回时不更新 UI
dispatch_get_main_queue() not update UI when move from oneViewController to another ViewController and back again
在我的应用程序中,我在后台执行长任务。所以我使用 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
不会改变。
问题:请帮助我,这样我就可以在从另一个 ViewController
回来时更新我的 UI
注意: 将一个 ViewController 移动到另一个任务在主队列中执行。
编辑: 这是@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>>
查看指针,是否相同?
我的 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);
})
})
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)
您正在后台处理(长任务)并且不会阻塞任何主线程activity...
然后您更改为 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..
在我的应用程序中,我在后台执行长任务。所以我使用 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
不会改变。
问题:请帮助我,这样我就可以在从另一个 ViewController
回来时更新我的 UI注意: 将一个 ViewController 移动到另一个任务在主队列中执行。
编辑: 这是@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>>
查看指针,是否相同?
我的 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);
})
})
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)
您正在后台处理(长任务)并且不会阻塞任何主线程activity...
然后您更改为 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..