2
0

More reliable monitoring of changes using NSFetchedResultsController.

This commit is contained in:
Maarten Billemont 2020-07-05 20:24:18 -04:00
parent 7368b1be90
commit 9e91f0a9d6
2 changed files with 37 additions and 29 deletions

View File

@ -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." );

View File

@ -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 {