NSOperation blocks UI painting?

青春壹個敷衍的年華 提交于 2019-12-02 23:35:19

The method in the observer that is performed in response to your notification is not being performed on the main thread.

So, in that method, you can force another method to run on the main thread using performSelectorOnMainThread:withObject:waitUntilDone:.

For example:

MyOperation.m

- (void)main {
    for (int i = 1; i <= 5; i++) {
        sleep(1);
        [[NSNotificationCenter defaultCenter] postNotificationName:@"GTCNotification" object:[NSNumber numberWithInteger:i]];
    }
}

MyViewController.m

- (void)setupOperation {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myNotificationResponse:) name:@"GTCNotification" object:nil];

    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init];
    MyOperation *myOp = [[MyOperation alloc] init];

    [opQueue addOperation:myOp];

    [myOp release];
    [opQueue release];
}

- (void)myNotificationResponse:(NSNotification*)note {
    NSNumber *count = [note object];
    [self performSelectorOnMainThread:@selector(updateView:) withObject:count waitUntilDone:YES];
}

- (void)updateView:(NSNumber*)count {
    countLabel.text = count.stringValue;
}

Most people know that any display-related task must be done on the main thread. However, as a direct consequence of that, any change to a Cocoa bindings property that may affect the drawing must also be modified on the main thread (because the KVO triggers will be handled on the thread from which they are triggered). This is a surprise to most people: in particular, it is not safe to call [self setNeedsDisplay] from a thread other than the main thread.

As mentioned by gerry, your NSNotification is not processed on the main thread, it is processed on the thread from which it is sent. Hence in your NSNotification handler, you must send your commands back to the main thread if they are display-related or if they affect Cocoa bindings. @performSelector works, but with queues, I have found an easier and more readable method:

[ [ NSOperationQueue mainQueue] addOperationWithBlock:^(void) {
    /* Your main-thread code here */ }];

It avoids the definition of a secondary helper function whose only purpose is to be called from the main thread. mainQueue was defined only in >10.6.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!