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:
parent
f5d9334b06
commit
98080ceb51
2
External/Pearl
vendored
2
External/Pearl
vendored
@ -1 +1 @@
|
||||
Subproject commit e23abc67cd80ec03543eed48ffd97b30439b5c84
|
||||
Subproject commit 9336e50d3b896bac1478fe4ac8313387a85114c2
|
@ -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";
|
||||
|
@ -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">
|
||||
|
@ -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
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
- (NSString *)description {
|
||||
|
||||
return [[self content] description];
|
||||
return str(@"%@:%@", [self class], [self name]);
|
||||
}
|
||||
|
||||
- (NSString *)debugDescription {
|
||||
|
@ -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(), ^{
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
#ifdef DEBUG
|
||||
[PearlLogger get].autoprintLevel = PearlLogLevelDebug;
|
||||
// [NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
|
||||
//[NSClassFromString(@"WebView") performSelector:NSSelectorFromString(@"_enableRemoteInspector")];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
}];
|
||||
}
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user