【问题标题】:NSOperation and NSNotificationCenter on the main thread主线程上的 NSOperation 和 NSNotificationCenter
【发布时间】:2009-12-29 05:44:29
【问题描述】:

我有一个 NSOperation。完成后,我触发 NSNotificationCenter 让程序知道 NSoperation 已完成并更新 gui。

据我了解,NSNotification 的侦听器不会在主线程上运行,因为 NSOperation 不在主线程上。

当我触发我的事件时,如何让监听器在主线程上运行?

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 

【问题讨论】:

    标签: iphone objective-c cocoa nsoperation nsnotificationcenter


    【解决方案1】:

    更新: 调度队列使得在主线程上发布通知变得非常容易。

    dispatch_async(dispatch_get_main_queue(),^{
       [[NSNotificationCenter defaultCenter] postNotification...];
    });
    

    要等待通知处理程序完成,只需将 dispatch_async 替换为 dispatch_sync。


    根据 notnoop 的回答,这里有一些基础设施,您可以使用这些基础设施将通知安全地发布到主线程,而无需等待它们完成。希望有人会觉得这很有帮助!

    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
    

    【讨论】:

      【解决方案2】:

      您可以将performSelectorOnMainThread:withObject:waitUntilDone: 与辅助方法一起使用,与以下示例类似。

      .....
      [self performSelectorOnMainThread:@selector(fireNotification) withObject:nil waitUntilDone:YES];
      ...
      
      - (void)fireNotification {
        [[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
      }
      

      如果您不等到完成,您将需要考虑其他线程可能引用在调用主线程之前可能已经清理的对象的情况。

      【讨论】:

        【解决方案3】:

        如果您使用的是 10.6,也可以使用 setCompletionBlock:。 它是这样使用的:

        NSOperation*op= .... ;
        [op setCompletionBlock:^{
            dispatch_async(dispatch_get_main_queue(),^{
                code to be run on the main thread after the operation is finished.
            });
        }];
        

        对于块和 GCD 的一般介绍,this article 非常有帮助。我发现 GCD 和 setCompletionBlock 比 NSNotification 更容易阅读。需要注意的是,它只能在 10.6 上运行!

        【讨论】:

        • 如果使用了“iPhone”标签,那么提问者可能不在10.6上。
        【解决方案4】:

        为了扩展 Danra 的答案,这里是我整理的类别的 ARC 兼容版本:

        NSNotificationCenter+Threads.h

        @interface NSNotificationCenter (Threads)
        
        -(void)postNotificationOnMainThread:(NSNotification *)notification;
        -(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object;
        -(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo;
        
        @end
        

        NSNotificationCenter+Threads.m

        @implementation NSNotificationCenter (Threads)
        
        -(void)postNotificationOnMainThread:(NSNotification *)notification
        {
            [self performSelectorOnMainThread:@selector(postNotification:) withObject:notification waitUntilDone:NO];
        }
        
        -(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object
        {
            [self postNotificationNameOnMainThread:name object:object userInfo:nil];
        }
        
        -(void)postNotificationNameOnMainThread:(NSString *)name object:(id)object userInfo:(NSDictionary *)userInfo
        {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self postNotificationName:name object:object userInfo:userInfo];
            });
        }
        
        @end
        

        【讨论】:

          猜你喜欢
          • 2016-12-19
          • 2013-11-03
          • 1970-01-01
          • 2012-11-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多