在NSOperationQueue非主队列上创建UI元素会导致奇怪的行为

时间:2012-07-10 20:15:08

标签: ios ios5 user-interface nsoperationqueue

我有一些代码通过UIView创建的队列创建并添加了[[NSOperationQueue alloc] init]子视图,这导致了奇怪的滞后行为。仅在异常长时间延迟后才添加子视图。

但后来我转而使用[NSOperationQueue mainQueue]这些部分,响应能力正常。

我只想解释一下我用第一种方法看到的滞后行为。

1 个答案:

答案 0 :(得分:2)

来自Apple doc

  

主题和您的用户界面

     

如果您的应用程序具有图形用户界面,建议您收到   用户相关事件并从您的帐户启动界面更新   应用程序的主要线程。 此方法有助于避免同步   与处理用户事件和绘图窗口相关的问题   内容。一些框架,如Cocoa,通常需要这样做   行为,但即使是那些不这样做的行为,保持这种行为   主线程具有简化管理逻辑的优点   你的用户界面。它有一些值得注意的例外   有利于从其他线程执行图形操作。对于   例如,QuickTime API包含许多可以执行的操作   从辅助线程执行,包括打开电影文件,   渲染电影文件,压缩电影文件,导入和   导出图像。同样,在Carbon和Cocoa中你可以使用二级   线程来创建和处理图像并执行其他与图像相关的操作   计算。使用辅助线程可以进行这些操作   提高性能。 如果您不确定特定的图形   虽然操作,计划从主线程

此外,根据thread programming guide,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
}