我有一些代码UIView
通过创建的队列创建和添加子视图[[NSOperationQueue alloc] init]
,这导致了奇怪的滞后行为。仅在异常长时间延迟后才添加子视图。
但后来我转而使用[NSOperationQueue mainQueue]
这些部件,响应变得正常。
我只想解释我使用第一种方法看到的滞后行为。
我有一些代码UIView
通过创建的队列创建和添加子视图[[NSOperationQueue alloc] init]
,这导致了奇怪的滞后行为。仅在异常长时间延迟后才添加子视图。
但后来我转而使用[NSOperationQueue mainQueue]
这些部件,响应变得正常。
我只想解释我使用第一种方法看到的滞后行为。
来自苹果文档
线程和您的用户界面
如果您的应用程序具有图形用户界面,建议您接收与用户相关的事件并从应用程序的主线程启动界面更新。这种方法有助于避免与处理用户事件和绘制窗口内容相关的同步问题。一些框架,例如 Cocoa,通常需要这种行为,但即使对于那些不需要这种行为的框架,将这种行为保留在主线程上具有简化管理用户界面的逻辑的优点。有一些值得注意的例外情况是从其他线程执行图形操作是有利的。例如,QuickTime API 包括许多可以从辅助线程执行的操作,包括打开电影文件、渲染电影文件、压缩电影文件以及导入和导出图像。同样,在 Carbon 和 Cocoa 中,您可以使用辅助线程来创建和处理图像并执行其他与图像相关的计算。对这些操作使用辅助线程可以大大提高性能。但是,如果您不确定特定的图形操作,请计划从主线程执行
此外,根据线程编程指南,UI 类不是线程安全的。
因此,请避免从与主线程不同的线程更新 UI。
如果您运行NSOperation
(在队列中),您可以更新您的 UI(例如,在下载了应用程序生命周期所需的一些数据之后)在主线程中执行如下方法:
-(void)main {
// e.g the delegate could be the controller that has the view that you want to update
if (delegate) {
NSURL *url = [delegate urlForDownloadOperation:self];
if ( nil == url ) return;
self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
// e.g. rather than invoking processImage directly on the delegate, ensure that the method draw the image on the main thread
[delegate performSelectorOnMainThread:@selector(processImage:)
withObject:self waitUntilDone:YES];
}
}
或者,您可以向需要更新 UI 的组件发送通知,例如:
- (void)main {
NSURL *url = [delegate urlForDownloadOperation:self];
if ( nil == url ) return;
self.downloadedImage = [[NSImage alloc] initWithContentsOfURL:url];
// e.g. send a notificatio to inform some components that it is ready to update the UI with some content
[[NSNotificationCenter defaultCenter] postNotificationName:@"importData" object:self];
}
需要更新 UI 的组件将注册该通知,例如
- (void)processImage:(NSNotification*)notification
{
if (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(processImage:) withObject:notification waitUntilDone:YES];
return;
}
// update the UI here, you are running on the main thread
}