2
0

Don't block the MOC lookup.

[IMPROVED]  Don't block when MOC is not yet ready, just return nil.
[IMPROVED]  Outdated tip links to info, icon links to site search.
[IMPROVED]  Minor improvements to error handling during import.
This commit is contained in:
Maarten Billemont 2012-08-04 10:16:58 +02:00
parent bc3aa3255e
commit 4cdeab4256
9 changed files with 100 additions and 72 deletions

3
.gitignore vendored
View File

@ -28,3 +28,6 @@ Press/MasterPassword_PressKit/MasterPassword_pressrelease_*.pdf
# IPA # IPA
/sendipa/* /sendipa/*
!/sendipa/sendipa.conf !/sendipa/sendipa.conf
# Java
MasterPassword/Java/**/target

@ -1 +1 @@
Subproject commit 1614e65222a543a75cdf4e5f757f06e39b5979aa Subproject commit a7b028ff80cd4768be686a9ef2067dfd31989ce0

View File

@ -20,9 +20,9 @@ typedef enum {
@interface MPAppDelegate_Shared (Store)<UbiquityStoreManagerDelegate> @interface MPAppDelegate_Shared (Store)<UbiquityStoreManagerDelegate>
+ (NSManagedObjectContext *)managedObjectContext; + (NSManagedObjectContext *)managedObjectContextIfReady;
+ (NSManagedObjectModel *)managedObjectModel; + (NSManagedObjectModel *)managedObjectModel;
- (NSManagedObjectContext *)managedObjectContext; - (NSManagedObjectContext *)managedObjectContextIfReady;
- (NSManagedObjectModel *)managedObjectModel; - (NSManagedObjectModel *)managedObjectModel;
- (UbiquityStoreManager *)storeManager; - (UbiquityStoreManager *)storeManager;

View File

@ -13,9 +13,9 @@
#pragma mark - Core Data setup #pragma mark - Core Data setup
+ (NSManagedObjectContext *)managedObjectContext { + (NSManagedObjectContext *)managedObjectContextIfReady {
return [[self get] managedObjectContext]; return [[self get] managedObjectContextIfReady];
} }
+ (NSManagedObjectModel *)managedObjectModel { + (NSManagedObjectModel *)managedObjectModel {
@ -33,7 +33,10 @@
return managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; return managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
} }
- (NSManagedObjectContext *)managedObjectContext { - (NSManagedObjectContext *)managedObjectContextIfReady {
if (![self storeManager].isReady)
return nil;
static NSManagedObjectContext *managedObjectContext = nil; static NSManagedObjectContext *managedObjectContext = nil;
if (managedObjectContext) if (managedObjectContext)
@ -41,25 +44,14 @@
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext performBlockAndWait:^{ [managedObjectContext performBlockAndWait:^{
managedObjectContext.persistentStoreCoordinator = [self persistentStoreCoordinator];
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
managedObjectContext.persistentStoreCoordinator = [self storeManager].persistentStoreCoordinator;
managedObjectContext.undoManager = [NSUndoManager new];
}]; }];
return managedObjectContext; return managedObjectContext;
} }
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// Start loading the store.
[self storeManager];
// Wait until the storeManager is ready.
while (![self storeManager].isReady)
[NSThread sleepForTimeInterval:0.1];
return [self storeManager].persistentStoreCoordinator;
}
- (UbiquityStoreManager *)storeManager { - (UbiquityStoreManager *)storeManager {
static UbiquityStoreManager *storeManager = nil; static UbiquityStoreManager *storeManager = nil;
@ -112,10 +104,10 @@
- (void)saveContext { - (void)saveContext {
[self.managedObjectContext performBlock:^{ [self.managedObjectContextIfReady performBlock:^{
NSError *error = nil; NSError *error = nil;
if ([self.managedObjectContext hasChanges]) if ([self.managedObjectContextIfReady hasChanges])
if (![self.managedObjectContext save:&error]) if (![self.managedObjectContextIfReady save:&error])
err(@"While saving context: %@", error); err(@"While saving context: %@", error);
}]; }];
} }
@ -124,7 +116,7 @@
- (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm { - (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm {
return self.managedObjectContext; return self.managedObjectContextIfReady;
} }
- (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message { - (void)ubiquityStoreManager:(UbiquityStoreManager *)manager log:(NSString *)message {
@ -197,18 +189,16 @@
inf(@"Importing sites."); inf(@"Importing sites.");
static NSRegularExpression *headerPattern, *sitePattern; static NSRegularExpression *headerPattern, *sitePattern;
__autoreleasing __block NSError *error; __block NSError *error = nil;
if (!headerPattern) { if (!headerPattern) {
headerPattern = [[NSRegularExpression alloc] headerPattern = [[NSRegularExpression alloc] initWithPattern:@"^#[[:space:]]*([^:]+): (.*)"
initWithPattern:@"^#[[:space:]]*([^:]+): (.*)" options:0 error:&error];
options:0 error:&error];
if (error) if (error)
err(@"Error loading the header pattern: %@", error); err(@"Error loading the header pattern: %@", error);
} }
if (!sitePattern) { if (!sitePattern) {
sitePattern = [[NSRegularExpression alloc] sitePattern = [[NSRegularExpression alloc] initWithPattern:@"^([^[:space:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)(:[[:digit:]]+)?[[:space:]]+([^\t]+)\t(.*)"
initWithPattern:@"^([^[:space:]]+)[[:space:]]+([[:digit:]]+)[[:space:]]+([[:digit:]]+)(:[[:digit:]]+)?[[:space:]]+([^\t]+)\t(.*)" options:0 error:&error];
options:0 error:&error];
if (error) if (error)
err(@"Error loading the site pattern: %@", error); err(@"Error loading the site pattern: %@", error);
} }
@ -252,9 +242,20 @@
NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])]; NSFetchRequest *userFetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", userName]; userFetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@", userName];
[self.managedObjectContext performBlockAndWait:^{ __block NSArray *users = nil;
user = [[self.managedObjectContext executeFetchRequest:userFetchRequest error:&error] lastObject]; [self.managedObjectContextIfReady performBlockAndWait:^{
users = [self.managedObjectContextIfReady executeFetchRequest:userFetchRequest error:&error];
}]; }];
if (!users) {
err(@"While looking for user: %@, error: %@", userName, error);
return MPImportResultInternalError;
}
if ([users count] > 1) {
err(@"While looking for user: %@, found more than one: %u", userName, [users count]);
return MPImportResultInternalError;
}
user = [users count]? [users lastObject]: nil;
dbg(@"Found user: %@", [user debugDescription]); dbg(@"Found user: %@", [user debugDescription]);
} }
if ([headerName isEqualToString:@"Key ID"]) if ([headerName isEqualToString:@"Key ID"])
@ -298,8 +299,8 @@
if (user) { if (user) {
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user]; fetchRequest.predicate = [NSPredicate predicateWithFormat:@"name == %@ AND user == %@", name, user];
__block NSArray *existingSites = nil; __block NSArray *existingSites = nil;
[self.managedObjectContext performBlockAndWait:^{ [self.managedObjectContextIfReady performBlockAndWait:^{
existingSites = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; existingSites = [self.managedObjectContextIfReady executeFetchRequest:fetchRequest error:&error];
}]; }];
if (!existingSites) { if (!existingSites) {
err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error); err(@"Lookup of existing sites failed for site: %@, user: %@, error: %@", name, user.userID, error);
@ -323,24 +324,24 @@
} }
BOOL success = NO; BOOL success = NO;
[self.managedObjectContext.undoManager beginUndoGrouping]; [self.managedObjectContextIfReady.undoManager beginUndoGrouping];
@try { @try {
// Delete existing sites. // Delete existing sites.
if (elementsToDelete.count) if (elementsToDelete.count)
[self.managedObjectContext performBlockAndWait:^{ [self.managedObjectContextIfReady performBlockAndWait:^{
[elementsToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) { [elementsToDelete enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
inf(@"Deleting site: %@, it will be replaced by an imported site.", [obj name]); inf(@"Deleting site: %@, it will be replaced by an imported site.", [obj name]);
dbg(@"Deleted Element: %@", [obj debugDescription]); dbg(@"Deleted Element: %@", [obj debugDescription]);
[self.managedObjectContext deleteObject:obj]; [self.managedObjectContextIfReady deleteObject:obj];
}]; }];
}]; }];
// Import new sites. // Import new sites.
if (!user) { if (!user) {
[self.managedObjectContext performBlockAndWait:^{ [self.managedObjectContextIfReady performBlockAndWait:^{
user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class]) user = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
inManagedObjectContext:self.managedObjectContext]; inManagedObjectContext:self.managedObjectContextIfReady];
user.name = userName; user.name = userName;
user.keyID = [keyIDHex decodeHex]; user.keyID = [keyIDHex decodeHex];
}]; }];
@ -355,9 +356,9 @@
NSString *exportContent = [siteElements objectAtIndex:5]; NSString *exportContent = [siteElements objectAtIndex:5];
// Create new site. // Create new site.
[self.managedObjectContext performBlockAndWait:^{ [self.managedObjectContextIfReady performBlockAndWait:^{
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[key.algorithm classNameOfType:type] MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[key.algorithm classNameOfType:type]
inManagedObjectContext:self.managedObjectContext]; inManagedObjectContext:self.managedObjectContextIfReady];
element.name = name; element.name = name;
element.user = user; element.user = user;
element.type = type; element.type = type;
@ -385,10 +386,10 @@
return MPImportResultSuccess; return MPImportResultSuccess;
} }
@finally { @finally {
[self.managedObjectContext.undoManager endUndoGrouping]; [self.managedObjectContextIfReady.undoManager endUndoGrouping];
if (!success) if (!success)
[self.managedObjectContext.undoManager undoNestedGroup]; [self.managedObjectContextIfReady.undoManager undoNestedGroup];
} }
} }

View File

@ -60,6 +60,7 @@
- (IBAction)upgradePassword; - (IBAction)upgradePassword;
- (IBAction)action:(UIBarButtonItem *)sender; - (IBAction)action:(UIBarButtonItem *)sender;
- (IBAction)toggleUser; - (IBAction)toggleUser;
- (IBAction)searchOutdatedElements;
- (IBAction)closeOutdatedAlert; - (IBAction)closeOutdatedAlert;
- (IBAction)infoOutdatedAlert; - (IBAction)infoOutdatedAlert;

View File

@ -86,7 +86,7 @@
action:@selector(editUserName:)]]; action:@selector(editUserName:)]];
[self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName:)]]; [self.userNameContainer addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(copyUserName:)]];
[self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self [self.outdatedAlertBack addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(searchOutdatedElements:)]]; action:@selector(infoOutdatedAlert)]];
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]]; self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"ui_background"]];
@ -137,12 +137,13 @@
[self updateAnimated:animated]; [self updateAnimated:animated];
if ([MPAppDelegate get].activeUser) if ([MPAppDelegate get].activeUser)
[[MPAppDelegate get].managedObjectContext performBlock:^void() { [[MPAppDelegate get].managedObjectContextIfReady performBlock:^void() {
NSError *error = nil; NSError *error = nil;
NSFetchRequest *migrationRequest = [NSFetchRequest NSFetchRequest *migrationRequest = [NSFetchRequest
fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])]; fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d", MPAlgorithmDefaultVersion]; migrationRequest.predicate = [NSPredicate predicateWithFormat:@"version_ < %d", MPAlgorithmDefaultVersion];
NSArray *migrationElements = [[MPAppDelegate get].managedObjectContext executeFetchRequest:migrationRequest error:&error]; NSArray *migrationElements = [[MPAppDelegate get].managedObjectContextIfReady executeFetchRequest:migrationRequest
error:&error];
if (!migrationElements) { if (!migrationElements) {
err(@"While looking for elements to migrate: %@", error); err(@"While looking for elements to migrate: %@", error);
return; return;
@ -652,7 +653,7 @@
}]; }];
} }
- (IBAction)searchOutdatedElements:(UITapGestureRecognizer *)sender { - (IBAction)searchOutdatedElements {
self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated; self.searchDisplayController.searchBar.selectedScopeButtonIndex = MPSearchScopeOutdated;
self.searchDisplayController.searchBar.searchResultsButtonSelected = YES; self.searchDisplayController.searchBar.searchResultsButtonSelected = YES;
@ -824,16 +825,16 @@
// Update password type. // Update password type.
if ([self.activeElement.algorithm classOfType:type] != self.activeElement.typeClass) if ([self.activeElement.algorithm classOfType:type] != self.activeElement.typeClass)
// Type requires a different class of element. Recreate the element. // Type requires a different class of element. Recreate the element.
[[MPAppDelegate managedObjectContext] performBlockAndWait:^{ [[MPAppDelegate managedObjectContextIfReady] performBlockAndWait:^{
MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:[self.activeElement.algorithm classNameOfType:type] MPElementEntity *newElement = [NSEntityDescription insertNewObjectForEntityForName:[self.activeElement.algorithm classNameOfType:type]
inManagedObjectContext:[MPAppDelegate managedObjectContext]]; inManagedObjectContext:[MPAppDelegate managedObjectContextIfReady]];
newElement.name = self.activeElement.name; newElement.name = self.activeElement.name;
newElement.user = self.activeElement.user; newElement.user = self.activeElement.user;
newElement.uses = self.activeElement.uses; newElement.uses = self.activeElement.uses;
newElement.lastUsed = self.activeElement.lastUsed; newElement.lastUsed = self.activeElement.lastUsed;
newElement.version = self.activeElement.version; newElement.version = self.activeElement.version;
[[MPAppDelegate managedObjectContext] deleteObject:self.activeElement]; [[MPAppDelegate managedObjectContextIfReady] deleteObject:self.activeElement];
self.activeElement = newElement; self.activeElement = newElement;
}]; }];
@ -941,7 +942,7 @@
if (navigationType == UIWebViewNavigationTypeLinkClicked) { if (navigationType == UIWebViewNavigationTypeLinkClicked) {
if ([[[request URL] query] isEqualToString:@"outdated"]) { if ([[[request URL] query] isEqualToString:@"outdated"]) {
[self searchOutdatedElements:nil]; [self searchOutdatedElements];
return NO; return NO;
} }

View File

@ -38,7 +38,7 @@
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPElementEntity class])];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]]; fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"uses_" ascending:NO]];
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:[MPAppDelegate managedObjectContext] managedObjectContext:[MPAppDelegate managedObjectContextIfReady]
sectionNameKeyPath:nil cacheName:nil]; sectionNameKeyPath:nil cacheName:nil];
self.fetchedResultsController.delegate = self; self.fetchedResultsController.delegate = self;

View File

@ -44,7 +44,7 @@
@synthesize wordList = _wordList; @synthesize wordList = _wordList;
- (void)initAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user { - (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(12, 30, 260, 150)]; UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(12, 30, 260, 150)];
alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite; alertAvatarScrollView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
@ -88,7 +88,7 @@
[alertAvatarScrollView setContentOffset:selectedOffset animated:YES]; [alertAvatarScrollView setContentOffset:selectedOffset animated:YES];
} }
- (void)initConfirmationAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user { - (void)initializeConfirmationAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user {
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(12, 70, 260, 110)]; UIView *container = [[UIView alloc] initWithFrame:CGRectMake(12, 70, 260, 110)];
[alert addSubview:container]; [alert addSubview:container];
@ -145,6 +145,15 @@
[self initializeWordLabel:wordLabel]; [self initializeWordLabel:wordLabel];
} recurse:NO]; } recurse:NO];
[[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidChange object:nil queue:nil usingBlock:
^(NSNotification *note) {
[self updateUsers];
}];
[[NSNotificationCenter defaultCenter] addObserverForName:PersistentStoreDidMergeChanges object:nil queue:nil usingBlock:
^(NSNotification *note) {
[self updateUsers];
}];
[super viewDidLoad]; [super viewDidLoad];
} }
@ -195,7 +204,7 @@
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass([MPUserEntity class])];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]]; fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"lastUsed" ascending:NO]];
NSArray *users = [[MPAppDelegate managedObjectContext] executeFetchRequest:fetchRequest error:nil]; NSArray *users = [[MPAppDelegate managedObjectContextIfReady] executeFetchRequest:fetchRequest error:nil];
// Clean up avatars. // Clean up avatars.
for (UIView *subview in [self.avatarsView subviews]) for (UIView *subview in [self.avatarsView subviews])
@ -276,16 +285,16 @@
- (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar { - (void)didSelectNewUserAvatar:(UIButton *)newUserAvatar {
__block MPUserEntity *newUser = nil; __block MPUserEntity *newUser = nil;
[[MPAppDelegate managedObjectContext] performBlockAndWait:^{ [[MPAppDelegate managedObjectContextIfReady] performBlockAndWait:^{
newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class]) newUser = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPUserEntity class])
inManagedObjectContext:[MPAppDelegate managedObjectContext]]; inManagedObjectContext:[MPAppDelegate managedObjectContextIfReady]];
}]; }];
[self showNewUserNameAlertFor:newUser completion:^(BOOL finished) { [self showNewUserNameAlertFor:newUser completion:^(BOOL finished) {
newUserAvatar.selected = NO; newUserAvatar.selected = NO;
if (!finished) if (!finished)
[[MPAppDelegate managedObjectContext] performBlock:^{ [[MPAppDelegate managedObjectContextIfReady] performBlock:^{
[[MPAppDelegate managedObjectContext] deleteObject:newUser]; [[MPAppDelegate managedObjectContextIfReady] deleteObject:newUser];
}]; }];
}]; }];
} }
@ -318,7 +327,7 @@
[PearlAlert showAlertWithTitle:@"Choose Your Avatar" [PearlAlert showAlertWithTitle:@"Choose Your Avatar"
message:@"\n\n\n\n\n\n" viewStyle:UIAlertViewStyleDefault message:@"\n\n\n\n\n\n" viewStyle:UIAlertViewStyleDefault
initAlert:^(UIAlertView *_alert, UITextField *_firstField) { initAlert:^(UIAlertView *_alert, UITextField *_firstField) {
[self initAvatarAlert:_alert forUser:newUser]; [self initializeAvatarAlert:_alert forUser:newUser];
} }
tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) { tappedButtonBlock:^(UIAlertView *_alert, NSInteger _buttonIndex) {
@ -335,7 +344,7 @@
@"\n\n\n\n\n\n" @"\n\n\n\n\n\n"
viewStyle:UIAlertViewStyleDefault viewStyle:UIAlertViewStyleDefault
initAlert:^void(UIAlertView *__alert, UITextField *__firstField) { initAlert:^void(UIAlertView *__alert, UITextField *__firstField) {
[self initConfirmationAlert:__alert forUser:newUser]; [self initializeConfirmationAlert:__alert forUser:newUser];
} }
tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) { tappedButtonBlock:^void(UIAlertView *__alert, NSInteger __buttonIndex) {
if (__buttonIndex == [__alert cancelButtonIndex]) { if (__buttonIndex == [__alert cancelButtonIndex]) {
@ -720,8 +729,8 @@
return; return;
if (buttonIndex == [sheet destructiveButtonIndex]) { if (buttonIndex == [sheet destructiveButtonIndex]) {
[[MPAppDelegate get].managedObjectContext performBlockAndWait:^{ [[MPAppDelegate get].managedObjectContextIfReady performBlockAndWait:^{
[[MPAppDelegate get].managedObjectContext deleteObject:targetedUser]; [[MPAppDelegate get].managedObjectContextIfReady deleteObject:targetedUser];
}]; }];
[[MPAppDelegate get] saveContext]; [[MPAppDelegate get] saveContext];
[self updateUsers]; [self updateUsers];

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="2549" systemVersion="12A269" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="2.0" toolsVersion="2549" systemVersion="12A269" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="KZF-fe-y9n">
<dependencies> <dependencies>
<deployment defaultVersion="1296" identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1498"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="1498"/>
</dependencies> </dependencies>
<scenes> <scenes>
@ -564,7 +563,7 @@ Your passwords will be AES-encrypted with your master password.</string>
<rect key="frame" x="20" y="94" width="280" height="31"/> <rect key="frame" x="20" y="94" width="280" height="31"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<subviews> <subviews>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap and hold to save a user name." textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="tj6-Ot-Fuh"> <textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Tap and hold to save a login name." textAlignment="center" minimumFontSize="17" clearButtonMode="whileEditing" id="tj6-Ot-Fuh">
<rect key="frame" x="0.0" y="0.0" width="280" height="31"/> <rect key="frame" x="0.0" y="0.0" width="280" height="31"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -814,9 +813,9 @@ L4m3P4sSw0rD</string>
<rect key="frame" x="20" y="60" width="260" height="130"/> <rect key="frame" x="20" y="60" width="260" height="130"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<string key="text">Some of your sites have outdated passwords. Tap this alert to see them. <string key="text">Some of your sites have outdated passwords. Tap this alert for more info or to find them.
You should upgrade these sites and update their account's passwords as soon as convenient.</string> You should upgrade these sites and update their account's passwords as soon as is convenient.</string>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/> <fontDescription key="fontDescription" type="system" pointSize="12"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
@ -842,7 +841,7 @@ You should upgrade these sites and update their account's passwords as soon as c
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/> <accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_info.png"> <state key="normal" image="icon_find.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/> <color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/> <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state> </state>
@ -850,7 +849,23 @@ You should upgrade these sites and update their account's passwords as soon as c
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/> <color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state> </state>
<connections> <connections>
<action selector="infoOutdatedAlert" destination="PQa-Xl-A3x" eventType="touchUpInside" id="U2G-GA-wT2"/> <action selector="searchOutdatedElements" destination="PQa-Xl-A3x" eventType="touchUpInside" id="7Wz-49-RQe"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Sfy-hx-kVU">
<rect key="frame" x="184" y="81" width="22" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<accessibility key="accessibilityConfiguration" hint="" label="Close"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="15"/>
<state key="normal" image="icon_find.png">
<color key="titleColor" red="0.19607843459999999" green="0.30980393290000002" blue="0.52156865600000002" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="highlighted">
<color key="titleColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="searchOutdatedElements" destination="PQa-Xl-A3x" eventType="touchUpInside" id="4jj-PA-b0I"/>
</connections> </connections>
</button> </button>
</subviews> </subviews>
@ -1798,7 +1813,7 @@ You could use the word wall for inspiration in finding a memorable master passw
<image name="icon_action.png" width="32" height="32"/> <image name="icon_action.png" width="32" height="32"/>
<image name="icon_cancel.png" width="32" height="32"/> <image name="icon_cancel.png" width="32" height="32"/>
<image name="icon_edit.png" width="32" height="32"/> <image name="icon_edit.png" width="32" height="32"/>
<image name="icon_info.png" width="32" height="32"/> <image name="icon_find.png" width="32" height="32"/>
<image name="icon_person.png" width="32" height="32"/> <image name="icon_person.png" width="32" height="32"/>
<image name="icon_plus.png" width="32" height="32"/> <image name="icon_plus.png" width="32" height="32"/>
<image name="icon_up.png" width="32" height="32"/> <image name="icon_up.png" width="32" height="32"/>
@ -1833,13 +1848,11 @@ You could use the word wall for inspiration in finding a memorable master passw
<relationship kind="action" name="closeAlert"/> <relationship kind="action" name="closeAlert"/>
<relationship kind="action" name="closeOutdatedAlert"/> <relationship kind="action" name="closeOutdatedAlert"/>
<relationship kind="action" name="copyContent"/> <relationship kind="action" name="copyContent"/>
<relationship kind="action" name="copyUserName:" candidateClass="UITapGestureRecognizer"/>
<relationship kind="action" name="editPassword"/> <relationship kind="action" name="editPassword"/>
<relationship kind="action" name="editUserName:" candidateClass="UILongPressGestureRecognizer"/> <relationship kind="action" name="editUserName:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="incrementPasswordCounter"/> <relationship kind="action" name="incrementPasswordCounter"/>
<relationship kind="action" name="infoOutdatedAlert"/> <relationship kind="action" name="infoOutdatedAlert"/>
<relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/> <relationship kind="action" name="resetPasswordCounter:" candidateClass="UILongPressGestureRecognizer"/>
<relationship kind="action" name="searchOutdatedElements:" candidateClass="UITapGestureRecognizer"/>
<relationship kind="action" name="toggleUser"/> <relationship kind="action" name="toggleUser"/>
<relationship kind="action" name="upgradePassword"/> <relationship kind="action" name="upgradePassword"/>
<relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/> <relationship kind="outlet" name="actionsTipContainer" candidateClass="UIView"/>