More reliable monitoring of changes using NSFetchedResultsController.
This commit is contained in:
		@@ -29,6 +29,8 @@
 | 
				
			|||||||
    if ([self hasChanges])
 | 
					    if ([self hasChanges])
 | 
				
			||||||
        [self performBlockAndWait:^{
 | 
					        [self performBlockAndWait:^{
 | 
				
			||||||
            @try {
 | 
					            @try {
 | 
				
			||||||
 | 
					                [self processPendingChanges];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                NSError *error = nil;
 | 
					                NSError *error = nil;
 | 
				
			||||||
                if (!(success = [self save:&error]))
 | 
					                if (!(success = [self save:&error]))
 | 
				
			||||||
                    MPError( error, @"While saving." );
 | 
					                    MPError( error, @"While saving." );
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,7 +48,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
 | 
				
			|||||||
            MPActiveUserStateMinimized,
 | 
					            MPActiveUserStateMinimized,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@interface MPUsersViewController()
 | 
					@interface MPUsersViewController()<NSFetchedResultsControllerDelegate>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@property(nonatomic) MPActiveUserState activeUserState;
 | 
					@property(nonatomic) MPActiveUserState activeUserState;
 | 
				
			||||||
@property(nonatomic, strong) NSArray *userIDs;
 | 
					@property(nonatomic, strong) NSArray *userIDs;
 | 
				
			||||||
@@ -58,6 +58,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
 | 
				
			|||||||
@property(nonatomic, copy) NSString *masterPasswordChoice;
 | 
					@property(nonatomic, copy) NSString *masterPasswordChoice;
 | 
				
			||||||
@property(nonatomic, strong) NSOperationQueue *afterUpdates;
 | 
					@property(nonatomic, strong) NSOperationQueue *afterUpdates;
 | 
				
			||||||
@property(nonatomic, weak) id contextChangedObserver;
 | 
					@property(nonatomic, weak) id contextChangedObserver;
 | 
				
			||||||
 | 
					@property(nonatomic, strong) NSFetchedResultsController *userResultsController;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@end
 | 
					@end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,6 +92,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
 | 
				
			|||||||
    [super viewWillAppear:animated];
 | 
					    [super viewWillAppear:animated];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    self.userSelectionContainer.visible = NO;
 | 
					    self.userSelectionContainer.visible = NO;
 | 
				
			||||||
 | 
					    [self.storeLoadingActivity startAnimating];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)viewDidAppear:(BOOL)animated {
 | 
					- (void)viewDidAppear:(BOOL)animated {
 | 
				
			||||||
@@ -674,24 +676,6 @@ referenceSizeForFooterInSection:(NSInteger)section {
 | 
				
			|||||||
                [self.keyboardHeightConstraint updateConstant:keyboardHeight];
 | 
					                [self.keyboardHeightConstraint updateConstant:keyboardHeight];
 | 
				
			||||||
            } );
 | 
					            } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((self.contextChangedObserver
 | 
					 | 
				
			||||||
            = [[MPiOSAppDelegate get] managedObjectContextChanged:^(NSDictionary<NSManagedObjectID *, NSString *> *affectedObjects) {
 | 
					 | 
				
			||||||
                if ([[[affectedObjects allKeys] filteredArrayUsingPredicate:
 | 
					 | 
				
			||||||
                        [NSPredicate predicateWithBlock:^BOOL(NSManagedObjectID *objectID, NSDictionary *bindings) {
 | 
					 | 
				
			||||||
                            return [objectID.entity.name isEqualToString:NSStringFromClass( [MPUserEntity class] )];
 | 
					 | 
				
			||||||
                        }]] count])
 | 
					 | 
				
			||||||
                    [self reloadUsers];
 | 
					 | 
				
			||||||
            }]))
 | 
					 | 
				
			||||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
					 | 
				
			||||||
            self.avatarCollectionView.visible = YES;
 | 
					 | 
				
			||||||
            [self.storeLoadingActivity stopAnimating];
 | 
					 | 
				
			||||||
        }];
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        [UIView animateWithDuration:0.3f animations:^{
 | 
					 | 
				
			||||||
            self.avatarCollectionView.visible = NO;
 | 
					 | 
				
			||||||
            [self.storeLoadingActivity startAnimating];
 | 
					 | 
				
			||||||
        }];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, [MPiOSAppDelegate get].storeCoordinator, nil,
 | 
					    PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, [MPiOSAppDelegate get].storeCoordinator, nil,
 | 
				
			||||||
            ^(MPUsersViewController *self, NSNotification *note) {
 | 
					            ^(MPUsersViewController *self, NSNotification *note) {
 | 
				
			||||||
                self.userIDs = nil;
 | 
					                self.userIDs = nil;
 | 
				
			||||||
@@ -703,32 +687,54 @@ referenceSizeForFooterInSection:(NSInteger)section {
 | 
				
			|||||||
                    [self reloadUsers];
 | 
					                    [self reloadUsers];
 | 
				
			||||||
                } );
 | 
					                } );
 | 
				
			||||||
            } );
 | 
					            } );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [UIView animateWithDuration:0.3f animations:^{
 | 
				
			||||||
 | 
					        self.avatarCollectionView.visible = YES;
 | 
				
			||||||
 | 
					        [self.storeLoadingActivity stopAnimating];
 | 
				
			||||||
 | 
					    }];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)reloadUsers {
 | 
					- (void)reloadUsers {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    [self afterUpdatesMainQueue:^{
 | 
					    [self afterUpdatesMainQueue:^{
 | 
				
			||||||
        if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
 | 
					        if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
 | 
				
			||||||
            NSError *error = nil;
 | 
					 | 
				
			||||||
            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
 | 
					            NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
 | 
				
			||||||
            fetchRequest.sortDescriptors = @[
 | 
					            fetchRequest.sortDescriptors = @[
 | 
				
			||||||
                    [NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
 | 
					                    [NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO]
 | 
				
			||||||
            ];
 | 
					            ];
 | 
				
			||||||
            NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error];
 | 
					            self.userResultsController = [[NSFetchedResultsController alloc]
 | 
				
			||||||
            if (!users) {
 | 
					                                          initWithFetchRequest:fetchRequest managedObjectContext:mainContext
 | 
				
			||||||
                MPError( error, @"Failed to load users." );
 | 
					                                          sectionNameKeyPath:nil cacheName:nil];
 | 
				
			||||||
                self.userIDs = nil;
 | 
					            self.userResultsController.delegate = self;
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
 | 
					            NSError *error = nil;
 | 
				
			||||||
            for (MPUserEntity *user in users)
 | 
					            if (![self.userResultsController performFetch:&error])
 | 
				
			||||||
                [userIDs addObject:user.permanentObjectID];
 | 
					                MPError( error, @"Failed to load users." );
 | 
				
			||||||
            self.userIDs = userIDs;
 | 
					
 | 
				
			||||||
 | 
					            [self updateUsers];
 | 
				
			||||||
        }])
 | 
					        }])
 | 
				
			||||||
            self.userIDs = nil;
 | 
					            self.userIDs = nil;
 | 
				
			||||||
    }];
 | 
					    }];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)updateUsers {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self.userResultsController.managedObjectContext performBlock:^{
 | 
				
			||||||
 | 
					        NSArray *users = self.userResultsController.fetchedObjects;
 | 
				
			||||||
 | 
					        NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]];
 | 
				
			||||||
 | 
					        for (MPUserEntity *user in users)
 | 
				
			||||||
 | 
					            [userIDs addObject:user.permanentObjectID];
 | 
				
			||||||
 | 
					        self.userIDs = userIDs;
 | 
				
			||||||
 | 
					    }];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma mark - NSFetchedResultsControllerDelegate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [self updateUsers];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#pragma mark - Properties
 | 
					#pragma mark - Properties
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- (void)setActive:(BOOL)active animated:(BOOL)animated {
 | 
					- (void)setActive:(BOOL)active animated:(BOOL)animated {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user