سؤال

لدي nsoperation. عند الانتهاء ، أقوم بإطلاق النار على nsnotificationcenter لإعلام البرنامج أن nsoperation قد انتهى وتحديث واجهة المستخدم الرسومية.

لن يتم تشغيل المستمعين إلى NSNotification على الخيط الرئيسي لأن nsoperation ليس على الخيط الرئيسي.

كيف يمكنني أن أجعله حتى يركض المستمعون على الخيط الرئيسي عندما أطلق النار على هذا الحدث؟

[[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
هل كانت مفيدة؟

المحلول

يمكنك استخدام performSelectorOnMainThread:withObject:waitUntilDone: مع استخدام طريقة المساعد ، بطريقة مماثلة للمثال التالي.

.....
[self performSelectorOnMainThread:@selector(fireNotification) withObject:nil waitUntilDone:YES];
...

- (void)fireNotification {
  [[NSNotificationCenter defaultCenter] postNotificationName:@"myEventName" object:self]; 
}

إذا لم تنتظر حتى الانتهاء ، فستحتاج إلى النظر في الحالات التي قد تشير فيها مؤشرات الترابط الأخرى إلى الكائن الذي يمكن تنظيفه بالفعل قبل استدعاء الخيط الرئيسي.

نصائح أخرى

استكمال: قوائم الإرسال تجعل نشر إشعار على الموضوع الرئيسي سهل للغاية.

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

لانتظار الانتهاء من معالجات الإخطار ، ما عليك سوى استبدال dispatch_async بـ Dispatch_sync.


بعد إجابة Notnoop ، إليك بعض البنية التحتية التي يمكنك استخدامها لنشر إخطاراتك بأمان على الخيط الرئيسي بدون في انتظارهم لإنهاء. نأمل أن يجد شخص ما هذا مفيدًا!

nsnotificale+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

nsnotificale+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

إذا كنت في الساعة 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 ، هذه المقالة كان مفيدًا للغاية. لقد وجدت GCD & SetCompletionBlock أسهل في القراءة من NSNotification. تحذير واحد ، حسناً ، إنه يعمل فقط في 10.6!

للتوسع في إجابة Danra ، إليك النسخة المتوافقة مع ARC من الفئة التي وضعتها معًا:

nsnotificalcenter+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

nsnotificalcenter+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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top