From 9e91f0a9d688e18bd88c312d67a2eb833aac2c62 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Sun, 5 Jul 2020 20:24:18 -0400 Subject: [PATCH] More reliable monitoring of changes using NSFetchedResultsController. --- platform-darwin/Source/MPEntities.m | 2 + .../Source/iOS/MPUsersViewController.m | 64 ++++++++++--------- 2 files changed, 37 insertions(+), 29 deletions(-) diff --git a/platform-darwin/Source/MPEntities.m b/platform-darwin/Source/MPEntities.m index b6a73777..8e67831a 100644 --- a/platform-darwin/Source/MPEntities.m +++ b/platform-darwin/Source/MPEntities.m @@ -29,6 +29,8 @@ if ([self hasChanges]) [self performBlockAndWait:^{ @try { + [self processPendingChanges]; + NSError *error = nil; if (!(success = [self save:&error])) MPError( error, @"While saving." ); diff --git a/platform-darwin/Source/iOS/MPUsersViewController.m b/platform-darwin/Source/iOS/MPUsersViewController.m index 6f659f9c..108b2d33 100644 --- a/platform-darwin/Source/iOS/MPUsersViewController.m +++ b/platform-darwin/Source/iOS/MPUsersViewController.m @@ -48,7 +48,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { MPActiveUserStateMinimized, }; -@interface MPUsersViewController() +@interface MPUsersViewController() @property(nonatomic) MPActiveUserState activeUserState; @property(nonatomic, strong) NSArray *userIDs; @@ -58,6 +58,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { @property(nonatomic, copy) NSString *masterPasswordChoice; @property(nonatomic, strong) NSOperationQueue *afterUpdates; @property(nonatomic, weak) id contextChangedObserver; +@property(nonatomic, strong) NSFetchedResultsController *userResultsController; @end @@ -91,6 +92,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { [super viewWillAppear:animated]; self.userSelectionContainer.visible = NO; + [self.storeLoadingActivity startAnimating]; } - (void)viewDidAppear:(BOOL)animated { @@ -674,24 +676,6 @@ referenceSizeForFooterInSection:(NSInteger)section { [self.keyboardHeightConstraint updateConstant:keyboardHeight]; } ); - if ((self.contextChangedObserver - = [[MPiOSAppDelegate get] managedObjectContextChanged:^(NSDictionary *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, ^(MPUsersViewController *self, NSNotification *note) { self.userIDs = nil; @@ -703,32 +687,54 @@ referenceSizeForFooterInSection:(NSInteger)section { [self reloadUsers]; } ); } ); + + [UIView animateWithDuration:0.3f animations:^{ + self.avatarCollectionView.visible = YES; + [self.storeLoadingActivity stopAnimating]; + }]; } - (void)reloadUsers { [self afterUpdatesMainQueue:^{ if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { - NSError *error = nil; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; fetchRequest.sortDescriptors = @[ [NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO] ]; - NSArray *users = [mainContext executeFetchRequest:fetchRequest error:&error]; - if (!users) { - MPError( error, @"Failed to load users." ); - self.userIDs = nil; - } + self.userResultsController = [[NSFetchedResultsController alloc] + initWithFetchRequest:fetchRequest managedObjectContext:mainContext + sectionNameKeyPath:nil cacheName:nil]; + self.userResultsController.delegate = self; - NSMutableArray *userIDs = [NSMutableArray arrayWithCapacity:[users count]]; - for (MPUserEntity *user in users) - [userIDs addObject:user.permanentObjectID]; - self.userIDs = userIDs; + NSError *error = nil; + if (![self.userResultsController performFetch:&error]) + MPError( error, @"Failed to load users." ); + + [self updateUsers]; }]) 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 - (void)setActive:(BOOL)active animated:(BOOL)animated {