NSOperation,观察者和线程错误 [英] NSOperation, observer and thread error
问题描述
我遇到了 NSOperation
和观察者的问题。
I've got a problem with NSOperation
and observer.
我有 tabbarcontroller
和一个 splashController
。我想加载启动画面并下载文件,当文件下载时,屏幕上会显示 tabbarcontroller
。
I've a tabbarcontroller
and a splashController
. I want the splashscreen load and download the file and when the file is downloaded make the tabbarcontroller
appear to the screen.
问题是我有一个错误:
bool _WebTryThreadLock(bool),0x3d2fa90:试图获取网络锁
来自主线程或Web线程以外的线程。这可能是
是从辅助线程调用UIKit的结果。现在崩溃
...
bool _WebTryThreadLock(bool), 0x3d2fa90: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
这是我的代码:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
queue = [[NSOperationQueue alloc] init];
NSString *path = [NSString stringWithFormat:@"%@flux.xml",DOCPATH];
//Le fichier existe dans le repertoire des documents
if([[NSFileManager defaultManager] fileExistsAtPath:path])
[window addSubview:tabBarController.view];
else
{
splash = [[SplashController alloc] init];
[window addSubview:splash.view];
}
DataLoadOperation *operation = [[DataLoadOperation alloc] initWithURL:[NSURL URLWithString:@"http://sly.33.free.fr/flux.xml"]];
[self.queue addOperation:operation];
[operation addObserver:self forKeyPath:@"isFinished" options:NSKeyValueObservingOptionNew context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
NSLog(@"fini");
}
有人可以帮助我吗?
推荐答案
键值观察通知发生在更改被观察属性的同一线程上。 Apple在NSOperation类引用中提到以下警告:
Key-value observing notifications occur on the same thread in which the observed property was changed on. Apple mentions the following warning in the NSOperation class reference:
虽然您可以将观察者附加到这些属性,但您不应该使用Cocoa绑定将它们绑定到应用程序用户界面的元素。与用户界面相关的代码通常只能在应用程序的主线程中执行。因为操作可以在任何线程中执行,所以与该操作相关的任何KVO通知都可以在任何线程中发生。
"Although you can attach observers to these properties, you should not use Cocoa bindings to bind them to elements of your application’s user interface. Code associated with your user interface typically must execute only in your application’s main thread. Because an operation may execute in any thread, any KVO notifications associated with that operation may similarly occur in any thread."
在你的 observeValueForKeyPath:ofObject:change:context:
方法中,你应该在主线程上执行任何UIKit操作。由于你在那里执行了多个步骤,你可能真的想在你的观察类中创建一个名为 -dataLoadingFinished
的另一个方法,你可以从观察:...
。然后,您可以在其中包含所有UI调用,而不必为每个调用 performSelectorOnMainThread
:
In your observeValueForKeyPath:ofObject:change:context:
method, you should perform any UIKit operations on the main thread. Since you're performing multiple steps in there, you might actually want to create another method in your observing class called -dataLoadingFinished
which you can call on the main thread from inside observe:…
. You can then include all of your UI calls in there, rather than having to call performSelectorOnMainThread
for each one:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self performSelectorOnMainThread:@selector(dataLoadingFinished:) withObject:nil waitUntilDone:YES];
}
即使在线程不是问题的情况下,习惯上也要单独定义实际实现每个观察动作的方法,以防止观察:...
增长过大。
Even in cases where threading is not an issue, it is customary to define separate methods to actually implement each observation action, to prevent the observe:…
from growing too large.
另请注意即使您只观察一个属性,仍然更好的做法是验证您感兴趣的属性是提示更改通知的属性。请参阅Dave Dribin的文章正确的KVO用法最佳方式。
Also note that even though you are only observing one property, it is still better practice to validate that the property you are interested in is the one prompting the change notification. See Dave Dribin's article Proper KVO Usage for the best way in which to do this.
这篇关于NSOperation,观察者和线程错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!