- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == targetObject && [keyPath isEqualToString:@"targetKeyPath"]) { if (targetObject.targetKeyPath == targetValue) { // self is a pointer of UIViewController [self.view setBackgroundColor:[UIColor blackColor]]; NSLog(@"UI Update Here!!!"); } } }
It turns out the background color does not change as planned but the log is printed. I am sure the UIViewController is the top view controller so it is not view-controller-is-not-top-view-controller-problem as some Google results teach me. I was frustrated and tried my best to Google for a few hours without luck. Finally, an example in iOS Developer Library gave me a huge hint. In that example, its author put this line of code inside observeValueForKeyPath function, just before lines which will update a table view.
assert([NSThread isMainThread]);
I placed this line in my code and the assertion failed. I couldn't help but think: Is there any relationship between "Updating UI" and "Main Thread"? It turns out to be a huge YES. Check out this paragraph in UIView Class Reference.
At this point, the root cause of the problem becomes clear:Threading Considerations
Manipulations to your application’s user interface must occur on the main thread. Thus, you should always call the methods of the UIView class from code running in the main thread of your application. The only time this may not be strictly necessary is when creating the view object itself but all other manipulations should occur on the main thread.
- The observeValueForKeyPath function does not run in main thread. (Maybe it does run on the main thread sometimes, but we have no control anyway)
- Any UI manipulations must occur on the main thread
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if (object == targetObject && [keyPath isEqualToString:@"targetKeyPath"]) { if (targetObject.targetKeyPath == targetValue) { // self is a pointer of UIViewController [self.view performSelectorOnMainThread:@selector(setBackgroundColor:) withObject:[UIColor blackColor] waitUntilDone:NO]; NSLog(@"UI Update Here!!!"); } } }
Finally it works like magic :)
No comments:
Post a Comment