From 98080ceb51cd28982e6d39f98945f290e2329d44 Mon Sep 17 00:00:00 2001 From: Maarten Billemont Date: Mon, 7 May 2012 01:15:19 +0200 Subject: [PATCH] Persistence fixes and improvements. [UPDATED] Pearl to ARC. [FIXED] Crash related to persistence changes that caused UI updates while other UI changes were ongoing. [IMPROVED] Real description of MPElementEntities and use content whenever the password is requested. [IMPROVED] iOS: Handling of search result fetching and table reloading. --- External/Pearl | 2 +- MasterPassword-iOS.xcodeproj/project.pbxproj | 17 ++--- .../MasterPassword (Development).xcscheme | 9 +++ MasterPassword/MPAppDelegate_Key.m | 3 +- MasterPassword/MPElementEntity.m | 2 +- .../Mac/MPPasswordWindowController.m | 4 +- MasterPassword/iOS/MPAppDelegate.m | 2 +- MasterPassword/iOS/MPMainViewController.m | 8 +- MasterPassword/iOS/MPSearchDelegate.m | 73 +++++++++---------- 9 files changed, 61 insertions(+), 59 deletions(-) diff --git a/External/Pearl b/External/Pearl index e23abc67..9336e50d 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit e23abc67cd80ec03543eed48ffd97b30439b5c84 +Subproject commit 9336e50d3b896bac1478fe4ac8313387a85114c2 diff --git a/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword-iOS.xcodeproj/project.pbxproj index 8c9e5ebf..1d636af4 100644 --- a/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -770,8 +770,6 @@ DAFE4A2E15039824003ABA7C /* PearlStrings.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45F315039823003ABA7C /* PearlStrings.m */; }; DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45F415039823003ABA7C /* PearlStringUtils.h */; }; DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45F515039823003ABA7C /* PearlStringUtils.m */; }; - DAFE4A3115039824003ABA7C /* PearlWebUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45F615039823003ABA7C /* PearlWebUtils.h */; }; - DAFE4A3215039824003ABA7C /* PearlWebUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45F715039823003ABA7C /* PearlWebUtils.m */; }; DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */; }; DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = DAFE45FE15039823003ABA7C /* PearlCryptUtils.h */; }; DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = DAFE45FF15039823003ABA7C /* PearlCryptUtils.m */; }; @@ -1634,8 +1632,6 @@ DAFE45F315039823003ABA7C /* PearlStrings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStrings.m; sourceTree = ""; }; DAFE45F415039823003ABA7C /* PearlStringUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlStringUtils.h; sourceTree = ""; }; DAFE45F515039823003ABA7C /* PearlStringUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStringUtils.m; sourceTree = ""; }; - DAFE45F615039823003ABA7C /* PearlWebUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlWebUtils.h; sourceTree = ""; }; - DAFE45F715039823003ABA7C /* PearlWebUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlWebUtils.m; sourceTree = ""; }; DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = ""; }; DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = ""; }; DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-Crypto.h"; sourceTree = ""; }; @@ -2782,8 +2778,6 @@ DAFE45F315039823003ABA7C /* PearlStrings.m */, DAFE45F415039823003ABA7C /* PearlStringUtils.h */, DAFE45F515039823003ABA7C /* PearlStringUtils.m */, - DAFE45F615039823003ABA7C /* PearlWebUtils.h */, - DAFE45F715039823003ABA7C /* PearlWebUtils.m */, DAFE45F815039823003ABA7C /* README */, DAFE45F915039823003ABA7C /* Resources */, ); @@ -2927,7 +2921,6 @@ DAFE4A2C15039824003ABA7C /* PearlResettable.h in Headers */, DAFE4A2D15039824003ABA7C /* PearlStrings.h in Headers */, DAFE4A2F15039824003ABA7C /* PearlStringUtils.h in Headers */, - DAFE4A3115039824003ABA7C /* PearlWebUtils.h in Headers */, DAFE4A3315039824003ABA7C /* Pearl-Crypto.h in Headers */, DAFE4A3415039824003ABA7C /* PearlCryptUtils.h in Headers */, DAFE4A3615039824003ABA7C /* PearlKeyChain.h in Headers */, @@ -3910,7 +3903,6 @@ DAFE4A2B15039824003ABA7C /* PearlObjectUtils.m in Sources */, DAFE4A2E15039824003ABA7C /* PearlStrings.m in Sources */, DAFE4A3015039824003ABA7C /* PearlStringUtils.m in Sources */, - DAFE4A3215039824003ABA7C /* PearlWebUtils.m in Sources */, DAFE4A3515039824003ABA7C /* PearlCryptUtils.m in Sources */, DAFE4A3715039824003ABA7C /* PearlKeyChain.m in Sources */, DAFE4A3915039824003ABA7C /* PearlRSAKey.m in Sources */, @@ -3987,6 +3979,7 @@ CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -4043,6 +4036,7 @@ CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; @@ -4158,6 +4152,7 @@ CLANG_WARN_CXX0X_EXTENSIONS = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; + CLANG_WARN_OBJCPP_ARC_ABI = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; @@ -4228,7 +4223,7 @@ DA95D60B14DF3F3B008D1B94 /* AppStore */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_ARC = YES; DSTROOT = /tmp/Pearl.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Pearl/Pearl-Prefix.pch"; @@ -4325,7 +4320,7 @@ DAC77CB5148291A600BCF976 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_ARC = YES; DSTROOT = /tmp/Pearl.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Pearl/Pearl-Prefix.pch"; @@ -4339,7 +4334,7 @@ DAC77CB6148291A600BCF976 /* AdHoc */ = { isa = XCBuildConfiguration; buildSettings = { - CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_ARC = YES; DSTROOT = /tmp/Pearl.dst; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Pearl/Pearl-Prefix.pch"; diff --git a/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword (Development).xcscheme b/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword (Development).xcscheme index 5f32e1c0..0d791d74 100644 --- a/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword (Development).xcscheme +++ b/MasterPassword-iOS.xcodeproj/xcshareddata/xcschemes/MasterPassword (Development).xcscheme @@ -77,6 +77,15 @@ useCustomWorkingDirectory = "NO" buildConfiguration = "AdHoc" debugDocumentVersioning = "YES"> + + + + diff --git a/MasterPassword/MPAppDelegate_Key.m b/MasterPassword/MPAppDelegate_Key.m index d1b1d31b..76042b4d 100644 --- a/MasterPassword/MPAppDelegate_Key.m +++ b/MasterPassword/MPAppDelegate_Key.m @@ -81,7 +81,8 @@ static NSDictionary *keyHashQuery() { NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; if (coordinator) { - _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + // Put concurrency type on main queue, because otherwise updates break updating the search table UI. + _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType/*NSPrivateQueueConcurrencyType*/]; _managedObjectContext.persistentStoreCoordinator = coordinator; [[NSNotificationCenter defaultCenter] addObserverForName:NSPersistentStoreDidImportUbiquitousContentChangesNotification diff --git a/MasterPassword/MPElementEntity.m b/MasterPassword/MPElementEntity.m index b8fe7f84..e5f9a4e6 100644 --- a/MasterPassword/MPElementEntity.m +++ b/MasterPassword/MPElementEntity.m @@ -30,7 +30,7 @@ - (NSString *)description { - return [[self content] description]; + return str(@"%@:%@", [self class], [self name]); } - (NSString *)debugDescription { diff --git a/MasterPassword/Mac/MPPasswordWindowController.m b/MasterPassword/Mac/MPPasswordWindowController.m index 404fc7be..f0e7f334 100644 --- a/MasterPassword/Mac/MPPasswordWindowController.m +++ b/MasterPassword/Mac/MPPasswordWindowController.m @@ -121,7 +121,7 @@ } dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - NSString *description = [result description]; + NSString *description = [result.content description]; [result use]; dispatch_async(dispatch_get_main_queue(), ^{ @@ -143,7 +143,7 @@ element.name = siteName; element.mpHashHex = [MPAppDelegate get].keyHashHex; - NSString *description = [element description]; + NSString *description = [element.content description]; [element use]; dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/MasterPassword/iOS/MPAppDelegate.m b/MasterPassword/iOS/MPAppDelegate.m index 74daf888..ec98c0c9 100644 --- a/MasterPassword/iOS/MPAppDelegate.m +++ b/MasterPassword/iOS/MPAppDelegate.m @@ -45,7 +45,7 @@ #ifdef DEBUG [PearlLogger get].autoprintLevel = PearlLogLevelDebug; - // [NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")]; + //[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")]; #endif } diff --git a/MasterPassword/iOS/MPMainViewController.m b/MasterPassword/iOS/MPMainViewController.m index 8a70a97d..7bb1d84e 100644 --- a/MasterPassword/iOS/MPMainViewController.m +++ b/MasterPassword/iOS/MPMainViewController.m @@ -177,7 +177,7 @@ self.contentField.text = @""; if (self.activeElement.name && ![self.activeElement isDeleted]) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ - NSString *description = [self.activeElement description]; + NSString *description = [self.activeElement.content description]; dispatch_async(dispatch_get_main_queue(), ^{ self.contentField.text = description; @@ -343,9 +343,9 @@ - (void)changeElementWithoutWarningDo:(void (^)(void))task; { // Update element, keeping track of the old password. - NSString *oldPassword = self.activeElement.description; + NSString *oldPassword = [self.activeElement.content description]; task(); - NSString *newPassword = self.activeElement.description; + NSString *newPassword = [self.activeElement.content description]; [self updateAnimated:YES]; // Show new and old password. @@ -461,7 +461,7 @@ [TestFlight passCheckpoint:[NSString stringWithFormat:MPTestFlightCheckpointSelectType, NSStringFromMPElementType(type)]]; - if (type & MPElementTypeClassStored && ![self.activeElement.description length]) + if (type & MPElementTypeClassStored && ![[self.activeElement.content description] length]) [self showContentTip:@"Tap to set a password." withIcon:self.contentTipEditIcon]; }]; } diff --git a/MasterPassword/iOS/MPSearchDelegate.m b/MasterPassword/iOS/MPSearchDelegate.m index 92c2f29a..39446b77 100644 --- a/MasterPassword/iOS/MPSearchDelegate.m +++ b/MasterPassword/iOS/MPSearchDelegate.m @@ -31,10 +31,16 @@ return nil; self.dateFormatter = [NSDateFormatter new]; - self.dateFormatter.timeStyle = NSDateFormatterNoStyle; self.dateFormatter.dateStyle = NSDateFormatterShortStyle; self.query = @""; + NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])]; + fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]; + self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest + managedObjectContext:[MPAppDelegate managedObjectContext] + sectionNameKeyPath:nil cacheName:nil]; + self.fetchedResultsController.delegate = self; + return self; } @@ -101,31 +107,21 @@ [self update]; - return YES; + return NO; } - (void)update { assert(self.query); assert([MPAppDelegate get].keyHashHex); - NSFetchRequest *fetchRequest = [[MPAppDelegate get].managedObjectModel - fetchRequestFromTemplateWithName:@"MPElements" - substitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys: - self.query, @"query", - [MPAppDelegate get].keyHashHex, @"mpHashHex", - nil]]; - [fetchRequest setSortDescriptors: - [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses" ascending:NO]]]; - self.fetchedResultsController.delegate = nil; - self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest - managedObjectContext:[MPAppDelegate managedObjectContext] - sectionNameKeyPath:nil cacheName:nil]; - self.fetchedResultsController.delegate = self; + self.fetchedResultsController.fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(%@ == '' OR name BEGINSWITH[cd] %@) AND mpHashHex == %@", + self.query, self.query, [MPAppDelegate get].keyHashHex]; NSError *error; if (![self.fetchedResultsController performFetch:&error]) err(@"Couldn't fetch elements: %@", error); + [self.searchDisplayController.searchResultsTableView reloadData]; } - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller { @@ -192,8 +188,9 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section < (signed)[[self.fetchedResultsController sections] count]) - return (signed)[[[self.fetchedResultsController sections] objectAtIndex:(unsigned)section] numberOfObjects]; + NSArray *sections = [self.fetchedResultsController sections]; + if (section < (signed)[sections count]) + return (signed)[[sections objectAtIndex:(unsigned)section] numberOfObjects]; return 1; } @@ -250,28 +247,28 @@ // "New" section. NSString *siteName = self.query; [PearlAlert showAlertWithTitle:@"New Site" - message:l(@"Do you want to create a new site named:\n%@", siteName) - viewStyle:UIAlertViewStyleDefault - tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { - [tableView deselectRowAtIndexPath:indexPath animated:YES]; - - if (buttonIndex == [alert cancelButtonIndex]) - return; - - [self.fetchedResultsController.managedObjectContext performBlock:^{ - MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class]) + message:l(@"Do you want to create a new site named:\n%@", siteName) + viewStyle:UIAlertViewStyleDefault + tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (buttonIndex == [alert cancelButtonIndex]) + return; + + [self.fetchedResultsController.managedObjectContext performBlock:^{ + MPElementGeneratedEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class]) inManagedObjectContext:self.fetchedResultsController.managedObjectContext]; - assert([element isKindOfClass:ClassFromMPElementType((unsigned)element.type)]); - assert([MPAppDelegate get].keyHashHex); - - element.name = siteName; - element.mpHashHex = [MPAppDelegate get].keyHashHex; - - dispatch_async(dispatch_get_main_queue(), ^{ - [self.delegate didSelectElement:element]; - }); - }]; - } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; + assert([element isKindOfClass:ClassFromMPElementType((unsigned)element.type)]); + assert([MPAppDelegate get].keyHashHex); + + element.name = siteName; + element.mpHashHex = [MPAppDelegate get].keyHashHex; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate didSelectElement:element]; + }); + }]; + } cancelTitle:[PearlStrings get].commonButtonCancel otherTitles:[PearlStrings get].commonButtonYes, nil]; } }