2
0

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.
This commit is contained in:
Maarten Billemont 2012-05-07 01:15:19 +02:00
parent f5d9334b06
commit 98080ceb51
9 changed files with 61 additions and 59 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit e23abc67cd80ec03543eed48ffd97b30439b5c84
Subproject commit 9336e50d3b896bac1478fe4ac8313387a85114c2

View File

@ -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 = "<group>"; };
DAFE45F415039823003ABA7C /* PearlStringUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlStringUtils.h; sourceTree = "<group>"; };
DAFE45F515039823003ABA7C /* PearlStringUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlStringUtils.m; sourceTree = "<group>"; };
DAFE45F615039823003ABA7C /* PearlWebUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PearlWebUtils.h; sourceTree = "<group>"; };
DAFE45F715039823003ABA7C /* PearlWebUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlWebUtils.m; sourceTree = "<group>"; };
DAFE45F815039823003ABA7C /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
DAFE45FB15039823003ABA7C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Pearl.strings; sourceTree = "<group>"; };
DAFE45FD15039823003ABA7C /* Pearl-Crypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Pearl-Crypto.h"; sourceTree = "<group>"; };
@ -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";

View File

@ -77,6 +77,15 @@
useCustomWorkingDirectory = "NO"
buildConfiguration = "AdHoc"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DA5BFA43147E415C00F98B1E"
BuildableName = "MasterPassword.app"
BlueprintName = "MasterPassword"
ReferencedContainer = "container:MasterPassword-iOS.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

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

View File

@ -30,7 +30,7 @@
- (NSString *)description {
return [[self content] description];
return str(@"%@:%@", [self class], [self name]);
}
- (NSString *)debugDescription {

View File

@ -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(), ^{

View File

@ -45,7 +45,7 @@
#ifdef DEBUG
[PearlLogger get].autoprintLevel = PearlLogLevelDebug;
// [NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
//[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
#endif
}

View File

@ -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];
}];
}

View File

@ -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];
}
}