Realm-cocoa: Allow controlling the runloop mode used for notifications

Created on 11 Feb 2016  Â·  6Comments  Â·  Source: realm/realm-cocoa

Notification blocks added via -addNotificationBlock: won't get called when there is an open NSMenu eating events.

Is this normal behavior ? Can we get around this ?

O-Community P-2-Expected T-Enhancement

Most helpful comment

@tgoyne: As you proposed that we would need to expose another API here, I promoted this issue to an enhancement. Alternatively we might want to create a new issue instead which goes in place of that and describes what would be needed to do here.

All 6 comments

I reproduced the problem in a simple project.

The test class :

@interface TestObject : RLMObject

@property (nonatomic) NSInteger ID;
@property (nonatomic) NSInteger counter;

@end

@implementation TestObject

+(NSString *)primaryKey {
    return @"ID";
}

@end

Then, in a view controller :

@interface ViewController ()

@property (strong) RLMNotificationToken *counterToken;
@property (strong) NSTimer *timer;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Do any additional setup after loading the view.
}

- (void)viewWillAppear {
    self.counterToken = [[TestObject objectsWhere:@"ID = 3"] addNotificationBlock:^(RLMResults * _Nullable results, NSError * _Nullable error) {
        self.textFieldCounter.stringValue = [NSString stringWithFormat:@"%lu", [results.firstObject counter]];
    }];
}

- (void)viewWillDisappear {
    [self.counterToken stop];
    self.counterToken = nil;
}

- (IBAction)startStop:(id)sender {
    if (self.timer) {
        [self.timer invalidate];
        self.timer = nil;
    } else {
        NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:@selector(incrementCounter:) userInfo:nil repeats:YES];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
        self.timer = timer;
    }
}

- (void)incrementCounter:(NSTimer *)timer {
    TestObject *testObjectWithID3 = [TestObject objectsWhere:@"ID = 3"].firstObject;

    RLMRealm *realm = [RLMRealm defaultRealm];
    [realm transactionWithBlock:^{
        testObjectWithID3.counter++;
        [realm addOrUpdateObject:testObjectWithID3];
        NSLog(@"%@", testObjectWithID3);
        NSLog(@"%@", [TestObject objectsWhere:@"ID = 3"].firstObject);
    }];
}

@end

A button fires the timer, and a label displays the counter.
As soon as the main menu is opened, notification blocks aren't called anymore.

I can send the test project if you need it.

@tgoyne Any news about this ?
I wonder if this behavior is expected, or if I do something wrong here ?

This is kinda working as intended. NSMenu switches the run loop into NSEventTrackingRunLoopMode, specifically so that things like our change notifications aren't delivered while the menu is open. I suppose we need to expose the ability to control the runloop mode used for our notifications, but unfortunately it'd need to be a per-Realm thing rather than a per-notification thing.

@tgoyne Thanks for replying.

I suppose we need to expose the ability to control the runloop mode used for our notifications

That would be very helpful indeed. As of now, with this limitation, I subscribe for NSMenuDidEndTrackingNotification notification. But I ultimately would be notified while the menu is open.

@tgoyne: As you proposed that we would need to expose another API here, I promoted this issue to an enhancement. Alternatively we might want to create a new issue instead which goes in place of that and describes what would be needed to do here.

➤ Unito Sync Bot commented:

Transition made by Unito

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matteodanelli picture matteodanelli  Â·  3Comments

javierjulio picture javierjulio  Â·  3Comments

dennisgec picture dennisgec  Â·  3Comments

Bogidon picture Bogidon  Â·  3Comments

jpsim picture jpsim  Â·  3Comments