iRSSの日記

はてなダイアリーiRSSの日記の続き

NSOperationのThreadから、MainThreadにNotificationを送りUIを更新したい

NSBlockOperationのブロック内からpostNotificationNameしてみる
ViewController側で、このNotificationを受けてUIを変更しても、変化が画面に反映しない。

NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
   [[NSNotificationCenter defaultCenter] postNotificationName:@"issueStatusUpdated" 
                                                        object:nil 
                                                      userInfo:nil]];
}];
[self.queue addOperation:theOp];

postNotificationNameを、メインスレッドで実行する必要がある。

答えは、以下にありました。

NSOperation and NSNotificationCenter on the main thread


Following notnoop's answer, here's some infrastructure you can use to safely post your notifications on the main thread *without* waiting for them to finish. Hopefully someone will find this helpful!


NSNotificationCenter+Utils.h:

    @interface NSNotificationCenter (Utils)
    
    -(void)postNotificationOnMainThread:(NSNotification *)notification;
    -(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject;
    -(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
    
    @end

NSNotificationCenter+Utils.m:

    @interface NSNotificationCenter (Utils_Impl) {
    }
    
    -(void)postNotificationOnMainThreadImpl:(NSNotification*)notification;
    -(void)postNotificationNameOnMainThreadImpl:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo;
    
    @end
    
    @implementation NSNotificationCenter (Utils)
   
    -(void)postNotificationOnMainThread:(NSNotification *)notification {
        [notification retain];
        [notification.object retain];
        [self performSelectorOnMainThread:@selector(postNotificationOnMainThreadImpl:) 
                               withObject:notification
                            waitUntilDone:NO];
    }
    
    -(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject {
        [self postNotificationNameOnMainThread:aName object:anObject userInfo:nil];
    }
    
    -(void)postNotificationNameOnMainThread:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo {
        [aName retain];
        [anObject retain];
        [aUserInfo retain];
        
        SEL sel = @selector(postNotificationNameOnMainThreadImpl:object:userInfo:);
        NSMethodSignature* sig = [self methodSignatureForSelector:sel];
        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:sig];
        [invocation setTarget:self];
        [invocation setSelector:sel];
        [invocation setArgument:&aName atIndex:2];
        [invocation setArgument:&anObject atIndex:3];
        [invocation setArgument:&aUserInfo atIndex:4];
        [invocation invokeOnMainThreadWaitUntilDone:NO];
    }
    
    @end

    
    @implementation NSNotificationCenter (Utils_Impl)
    
    -(void)postNotificationOnMainThreadImpl:(NSNotification*)notification {
        [self postNotification:notification];
        [notification.object release];
        [notification release];
    }
    
    -(void)postNotificationNameOnMainThreadImpl:(NSString *)aName object:(id)anObject userInfo:(NSDictionary *)aUserInfo {
        [self postNotificationName:aName object:anObject userInfo:aUserInfo];
        [aName release];
        [anObject release];
        [aUserInfo release];
    }
    
    @end

NSInvocation+Utils.h:

    @interface NSInvocation (Utils)
    
    -(void)invokeOnMainThreadWaitUntilDone:(BOOL)wait;
    
    @end

NSInvocation+Utils.m:

    @implementation NSInvocation (Utils)
    
    -(void)invokeOnMainThreadWaitUntilDone:(BOOL)wait
    {
        [self performSelectorOnMainThread:@selector(invoke)
                               withObject:nil
                            waitUntilDone:wait];
    }
        
    @end