从另一个线程发送通知

时间:2013-07-27 19:31:06

标签: objective-c multithreading nsnotificationcenter

我的应用中有一个设置面板。每当用户按下按钮时,随着UI更新,对象在另一个线程上更新。我在主视图上有一个单独的标签,用于在对象完成更新时更新对象计数(无论设置面板是向上还是向下,我都希望发生这种情况)。我已经尝试过关注apple documentation regarding this very topic了,但它似乎并不适合我 - 也就是说,主视图控制器似乎从未因某种原因收到通知。有没有人有任何关于如何提醒主视图控制器传递给另一个线程的对象已完成更新的建议?这是我正在使用的代码(其中大部分是从该文档中复制的):

对象类:

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

主视图控制器

- (void)setUpThreadingSupport
{
    if (self.notifications) {
        return;
    }
    self.notifications = [[NSMutableArray alloc] init];
    self.notificationLock = [[NSLock alloc] init];
    self.notificationThread = [NSThread currentThread];

    self.notificationPort = [[NSMachPort alloc] init];
    [self.notificationPort setDelegate: self];
    [[NSRunLoop currentRunLoop] addPort: self.notificationPort
                            forMode: (NSString *)kCFRunLoopCommonModes];
}

- (void)handleMachMessage:(void *)msg
{
    [self.notificationLock lock];

    while ([self.notifications count]) {
        NSNotification *notification = [self.notifications objectAtIndex: 0];
        [self.notifications removeObjectAtIndex: 0];
        [self.notificationLock unlock];
        [self processNotification: notification];
        [self.notificationLock lock];
    };

    [self.notificationLock unlock];
}

- (void)processNotification:(NSNotification *)notification{

    if ([NSThread currentThread] != self.notificationThread) {
        // Forward the notification to the correct thread.
        [self.notificationLock lock];
        [self.notifications addObject: notification];
        [self.notificationLock unlock];
        [self.notificationPort sendBeforeDate: [NSDate date]
                                   components: nil
                                         from: nil
                                     reserved: 0];
    } else {
        [self updateScaleCount];
    }
}

- (void)updateScaleCount
{
    NSLog(@"[ScalesViewController - updateScaleCount]: Scales updated from notification center.");
    if([UserDefinedScales areScalesGrouped] == YES){
        self.groupCountLabel.text = [NSString stringWithFormat: @"Group Count: %i", [[UserDefinedScales sortedKeys] count]];
    } else {
        self.groupCountLabel.text = @"Group Count: 1";
    }
    self.scaleCountLabel.text = [NSString stringWithFormat: @"Scale Count: %i", [UserDefinedScales scaleCount]];
}

主视图控制器 - 查看已加载:

[self setUpThreadingSupport];
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(processNotification:)
                                                 name: @"ScaleCountUpdated"
                                               object: nil];

如果您对如何更改此代码以使其正常运行有任何建议,或者为实现此目的而提供其他解决方案,我们将不胜感激!谢谢。

2 个答案:

答案 0 :(得分:0)

在我看来,你正确地做到了,即注册通知并发送。

据我所知,从您的代码和您提供的信息中,您基本上可以完全忘记setupThreadingSupport。你应该在没有它的情况下进行测试。不确定你想要实现什么,但看起来有点过分可能只是一个简单的块就足够了。是否有令人信服的理由在后台线程上收听通知?为什么不让通知中心决定?

记录发送和接收通知 - addObserverpostNotification实际上所有这些机制都需要按预期工作。

答案 1 :(得分:0)

我会去更简单的实现。 NSNotificationCenter 已经提供了在您的应用中广播和接收消息所需的所有机制。

如果您从后台线程触发通知,则可以使用 GCD dispatch_async 使其在主线程上传递。

对象类

dispatch_async(dispatch_get_main_queue(), ^{
    //  You don't need to pass the object itself here as you are not using it later.     
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ScaleCountUpdated"];
}

<强> MainViewController

-(void)viewDidLoad
{
    [super viewDidLoad];
    //  Register your controller as an observer for a specific message name
    [[NSNotificationCenter defaultCenter] addObserver: self
                                             selector: @selector(updateScaleCount)
                                                 name: @"ScaleCountUpdated"
                                               object: nil];

}
- (void)updateScaleCount
{
    NSLog(@"[ScalesViewController - updateScaleCount]: Scales updated from notification center.");
    if([UserDefinedScales areScalesGrouped] == YES){
        self.groupCountLabel.text = [NSString stringWithFormat: @"Group Count: %i", [[UserDefinedScales sortedKeys] count]];
    } else {
        self.groupCountLabel.text = @"Group Count: 1";
    }
    self.scaleCountLabel.text = [NSString stringWithFormat: @"Scale Count: %i", [UserDefinedScales scaleCount]];
}