Roobiq / RBQFetchedResultsController

Drop-in replacement for NSFetchedResultsController backed by Realm.
MIT License
476 stars 70 forks source link

Don't release delegate #102

Open smolskyaleksey opened 8 years ago

smolskyaleksey commented 8 years ago

testbatch.zip Hi everyone

// Register the change notification from RBQRealmNotificationManager
// Is no-op if the change notifications are already registered
- (void)registerChangeNotifications
{
    typeof(self) __weak weakSelf = self;

    // Setup run loop
    if (!self.notificationRunLoop) {
        dispatch_semaphore_t sem = dispatch_semaphore_create(0);

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

            CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^{
                weakSelf.notificationRunLoop = [NSRunLoop currentRunLoop];

                dispatch_semaphore_signal(sem);
            });

            CFRunLoopRun();

        });

        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    }

    CFRunLoopPerformBlock(weakSelf.notificationRunLoop.getCFRunLoop, kCFRunLoopDefaultMode, ^{
        if (weakSelf.notificationToken) {
            [weakSelf.notificationToken stop];
            weakSelf.notificationToken = nil;
            weakSelf.notificationCollection = nil;
        }

        weakSelf.notificationCollection = weakSelf.fetchRequest.fetchObjects;
        weakSelf.notificationToken = [weakSelf.notificationCollection
                                      addNotificationBlock:^(id<RLMCollection>  _Nullable collection,
                                                             RLMCollectionChange * _Nullable change,
                                                             NSError * _Nullable error) {
                                          if (!error &&
                                              change) {
                                              // Create the change sets
                                              NSSet *addedSafeObjects = [weakSelf safeObjectsFromChanges:change.insertions withCollection:collection isInsertion:YES];
                                              NSSet *deletedSafeObjects = [weakSelf safeObjectsFromChanges:change.deletions withCollection:collection isInsertion:NO];
                                              NSSet *changedSafeObjects = [weakSelf safeObjectsFromChanges:change.modifications withCollection:collection isInsertion:NO];

                                              [weakSelf calculateChangesWithAddedSafeObjects:addedSafeObjects
                                                                          deletedSafeObjects:deletedSafeObjects
                                                                          changedSafeObjects:changedSafeObjects
                                                                                       realm:collection.realm];
                                          }
                                      }];
    });

    CFRunLoopWakeUp(self.notificationRunLoop.getCFRunLoop);
}

Could you explain why do you use here manipulation with runloop. Now we have problem that delegate doesn't release and we have strong link. If i comment all code with runloop, it will work fine. Could you fix it or delete this strange code because RBQRealmNotificationManager not used in this project. Also i provided project with it. It's very easy to reproduce.

bigfish24 commented 8 years ago

I will look at your test project but you can't comment this code out and expect RBQFRC to work. What is going is that you cannot add a Realm notification block to a thread that doesn't have a run loop. This means background threads via a dispatch queue will not support Realm notifications unless you start a run loop on that thread. This code starts a run loop on the background thread and then registers a notification block so that RBQFRC can process all changes from Realm on a background thread.

smolskyaleksey commented 8 years ago

YES, you absolutely is right . I don't use background thread and i think you should check if it call on main thread,because when I call it on main thread it stops working.

smolskyaleksey commented 8 years ago

Can we use something like this for main theard

 // Setup run loop
    if (!self.notificationRunLoop) {
        dispatch_semaphore_t sem = dispatch_semaphore_create(0);
        if (![NSThread isMainThread]) {

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, ^{
                    weakSelf.notificationRunLoop = [NSRunLoop currentRunLoop];

                    dispatch_semaphore_signal(sem);
                });

                CFRunLoopRun();
            });

        } else {
            weakSelf.notificationRunLoop = [NSRunLoop currentRunLoop];
            dispatch_semaphore_signal(sem);
        }

        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    }

but it still does not release delegate for bg thread

smolskyaleksey commented 8 years ago

Steps to reproduce: 1) run app 2)press button "Press me' 3) Press plus button on top right corner 4)press back button

Act: Delegate don't release Exp: Delegate should be released

smolskyaleksey commented 8 years ago

Do you have some news?