diff --git a/platform-darwin/Source/MPAppDelegate_Store.m b/platform-darwin/Source/MPAppDelegate_Store.m index 7dae61f7..2f880df5 100644 --- a/platform-darwin/Source/MPAppDelegate_Store.m +++ b/platform-darwin/Source/MPAppDelegate_Store.m @@ -183,12 +183,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted ); } ); // Do nothing if already fully set up, otherwise (re-)load the store. - if (self.storeCoordinator && self.mainManagedObjectContext && self.privateManagedObjectContext) + if (self.mainManagedObjectContext && self.privateManagedObjectContext) return; [self.storeQueue addOperationWithBlock:^{ // Do nothing if already fully set up, otherwise (re-)load the store. - if (self.storeCoordinator && self.mainManagedObjectContext && self.privateManagedObjectContext) + if (self.mainManagedObjectContext && self.privateManagedObjectContext) return; // Unregister any existing observers and contexts. @@ -201,6 +201,12 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted ); [self.privateManagedObjectContext reset]; self.privateManagedObjectContext = nil; }]; + NSError *error = nil; + for (NSPersistentStore *store in self.storeCoordinator.persistentStores) + if (![self.storeCoordinator removePersistentStore:store error:&error] || error) { + MPError( error, @"Couldn't remove persistence store from coordinator." ); + return; + } // Don't load when the store is corrupted. if ([self.storeCorrupted boolValue]) @@ -209,33 +215,7 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted ); // Check if migration is necessary. [self migrateStore]; - // Install managed object contexts and observers. - self.privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; - [self.privateManagedObjectContext performBlockAndWait:^{ - self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; - self.privateManagedObjectContext.persistentStoreCoordinator = self.storeCoordinator; - }]; - - self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; - self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext; - if (@available( iOS 10.0, macOS 10.12, * )) - self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES; - else - // When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext. - PearlAddNotificationObserverTo( self.mainManagedObjectContext, NSManagedObjectContextDidSaveNotification, - self.privateManagedObjectContext, nil, ^(NSManagedObjectContext *mainContext, NSNotification *note) { - [mainContext performBlock:^{ - @try { - [mainContext mergeChangesFromContextDidSaveNotification:note]; - } - @catch (NSException *exception) { - err( @"While merging changes:\n%@", [exception fullDescription] ); - } - }]; - } ); - // Create a new store coordinator. - NSError *error = nil; NSURL *localStoreURL = [self localStoreURL]; if (![[NSFileManager defaultManager] createDirectoryAtURL:[localStoreURL URLByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:&error]) { @@ -261,6 +241,29 @@ PearlAssociatedObjectProperty( NSNumber*, StoreCorrupted, storeCorrupted ); } self.storeCorrupted = @NO; + // Install managed object contexts and observers. + self.privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + self.privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; + self.privateManagedObjectContext.persistentStoreCoordinator = self.storeCoordinator; + + self.mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + self.mainManagedObjectContext.parentContext = self.privateManagedObjectContext; + if (@available( iOS 10.0, macOS 10.12, * )) + self.mainManagedObjectContext.automaticallyMergesChangesFromParent = YES; + else + // When privateManagedObjectContext is saved, import the changes into mainManagedObjectContext. + PearlAddNotificationObserverTo( self.mainManagedObjectContext, NSManagedObjectContextDidSaveNotification, + self.privateManagedObjectContext, nil, ^(NSManagedObjectContext *mainContext, NSNotification *note) { + [mainContext performBlock:^{ + @try { + [mainContext mergeChangesFromContextDidSaveNotification:note]; + } + @catch (NSException *exception) { + err( @"While merging changes:\n%@", [exception fullDescription] ); + } + }]; + } ); + #if TARGET_OS_IPHONE PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, UIApp, [NSOperationQueue mainQueue], ^(MPAppDelegate_Shared *self, NSNotification *note) { diff --git a/platform-darwin/Source/iOS/MPSitesViewController.m b/platform-darwin/Source/iOS/MPSitesViewController.m index e73ae203..41b269d3 100644 --- a/platform-darwin/Source/iOS/MPSitesViewController.m +++ b/platform-darwin/Source/iOS/MPSitesViewController.m @@ -199,11 +199,7 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) { - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { if (controller == self.fetchedResultsController) - PearlMainQueue( ^{ - [self.collectionView updateDataSource:self.dataSource - toSections:[self createDataSource] - reloadItems:nil completion:nil]; - } ); + [self updateSites]; } #pragma mark - UISearchBarDelegate @@ -385,20 +381,25 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) { NSError *error = nil; self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name LIKE[cd] %@ AND user == %@", queryPattern, [MPiOSAppDelegate get].activeUserOID]; - if (![self.fetchedResultsController performFetch:&error]) + if (![self.fetchedResultsController performFetch:&error] || error) MPError( error, @"Couldn't fetch sites." ); - PearlMainQueue( ^{ - [self.collectionView updateDataSource:self.dataSource - toSections:[self createDataSource] - reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) { - for (MPSiteCell *cell in self.collectionView.visibleCells) - [cell setQueryGroups:self.queryGroups]; - }]; - } ); + [self updateSites]; }]; } +- (void)updateSites { + + PearlMainQueue( ^{ + [self.collectionView updateDataSource:self.dataSource + toSections:[self createDataSource] + reloadItems:@[ MPTransientPasswordItem ] completion:^(BOOL finished) { + for (MPSiteCell *cell in self.collectionView.visibleCells) + [cell setQueryGroups:self.queryGroups]; + }]; + } ); +} + #pragma mark - Properties - (NSString *)query { @@ -416,14 +417,19 @@ typedef NS_OPTIONS( NSUInteger, MPPasswordsTips ) { if (!_fetchedResultsController) { [MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { - NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPSiteEntity class] )]; + NSFetchRequest *fetchRequest = [MPSiteEntity fetchRequest]; fetchRequest.sortDescriptors = @[ [[NSSortDescriptor alloc] initWithKey:NSStringFromSelector( @selector( lastUsed ) ) ascending:NO] ]; - fetchRequest.fetchBatchSize = 10; + (self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil]).delegate = self; + + NSError *error = nil; + if (![self.fetchedResultsController performFetch:&error] || error) + MPError( error, @"Couldn't fetch sites." ); + [self updateSites]; }]; [self registerObservers]; }