diff --git a/External/Pearl b/External/Pearl index fb7562df..c4620ded 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit fb7562df9c3a59e8ac21e492b8eac0abcf5aa46e +Subproject commit c4620deda26475ae4320d9af5b2df4ff96c9093e diff --git a/MasterPassword/ObjC/MPAppDelegate_Store.m b/MasterPassword/ObjC/MPAppDelegate_Store.m index 74a00de8..c38413db 100644 --- a/MasterPassword/ObjC/MPAppDelegate_Store.m +++ b/MasterPassword/ObjC/MPAppDelegate_Store.m @@ -192,22 +192,19 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext }]; #if TARGET_OS_IPHONE - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:UIApp - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self.mainManagedObjectContext saveToStore]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:UIApp - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self.mainManagedObjectContext saveToStore]; - }]; + PearlAddNotificationObserver( UIApplicationWillTerminateNotification, UIApp, [NSOperationQueue mainQueue], + ^(MPAppDelegate_Shared *self, NSNotification *note) { + [self.mainManagedObjectContext saveToStore]; + } ); + PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, UIApp, [NSOperationQueue mainQueue], + ^(MPAppDelegate_Shared *self, NSNotification *note) { + [self.mainManagedObjectContext saveToStore]; + } ); #else - [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:NSApp - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - [self.mainManagedObjectContext saveToStore]; - }]; + PearlAddNotificationObserver( NSApplicationWillTerminateNotification, NSApp, [NSOperationQueue mainQueue], + ^(MPAppDelegate_Shared *self, NSNotification *note) { + [self.mainManagedObjectContext saveToStore]; + } ); #endif // Perform a data sanity check on the newly loaded store to find and fix any issues. @@ -528,7 +525,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext return MPImportResultMalformedInput; } NSTextCheckingResult *headerSites = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0 - range:NSMakeRange( 0, [importedSiteLine length] )] lastObject]; + range:NSMakeRange( 0, [importedSiteLine length] )] lastObject]; NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]]; NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]]; if ([headerName isEqualToString:@"User Name"]) { diff --git a/MasterPassword/ObjC/MPStoredSiteEntity.h b/MasterPassword/ObjC/MPStoredSiteEntity.h index 20348ff6..32d166a6 100644 --- a/MasterPassword/ObjC/MPStoredSiteEntity.h +++ b/MasterPassword/ObjC/MPStoredSiteEntity.h @@ -13,6 +13,6 @@ @interface MPStoredSiteEntity : MPSiteEntity -@property (nonatomic, retain) id contentObject; +@property (nonatomic, retain) NSData *contentObject; @end diff --git a/MasterPassword/ObjC/iOS/MPAnswersViewController.m b/MasterPassword/ObjC/iOS/MPAnswersViewController.m index a161f917..c09265c1 100644 --- a/MasterPassword/ObjC/iOS/MPAnswersViewController.m +++ b/MasterPassword/ObjC/iOS/MPAnswersViewController.m @@ -14,6 +14,7 @@ #import "MPPasswordsViewController.h" #import "MPCoachmarkViewController.h" #import "MPSiteQuestionEntity.h" +#import "MPOverlayViewController.h" @interface MPAnswersViewController() @@ -35,6 +36,25 @@ self.view.backgroundColor = [UIColor clearColor]; } +- (void)viewWillAppear:(BOOL)animated { + + [super viewWillAppear:animated]; + + PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) { + if (![note.userInfo[@"animated"] boolValue]) + [UIView setAnimationsEnabled:NO]; + [[MPOverlaySegue dismissViewController:self] perform]; + [UIView setAnimationsEnabled:YES]; + } ); +} + +- (void)viewWillDisappear:(BOOL)animated { + + [super viewWillDisappear:animated]; + + PearlRemoveNotificationObservers(); +} + - (UIStatusBarStyle)preferredStatusBarStyle { return UIStatusBarStyleLightContent; @@ -147,7 +167,10 @@ [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { MPSiteEntity *site_ = [self siteInContext:context]; - [site_ removeQuestions:site_.questions]; + NSOrderedSet *questions = [site_.questions copy]; + for (MPSiteQuestionEntity *question in questions) + [context deleteObject:question]; + [site_ removeQuestions:questions]; [context saveToStore]; [self setMultiple:NO animated:YES]; }]; diff --git a/MasterPassword/ObjC/iOS/MPCombinedViewController.m b/MasterPassword/ObjC/iOS/MPCombinedViewController.m index 2f131875..9fe6685f 100644 --- a/MasterPassword/ObjC/iOS/MPCombinedViewController.m +++ b/MasterPassword/ObjC/iOS/MPCombinedViewController.m @@ -22,9 +22,7 @@ #import "MPEmergencyViewController.h" #import "MPPasswordsSegue.h" -@implementation MPCombinedViewController { - NSArray *_notificationObservers; -} +@implementation MPCombinedViewController #pragma mark - Life @@ -47,14 +45,22 @@ [super viewDidAppear:animated]; - [self registerObservers]; + Weakify( self ); + PearlAddNotificationObserver( MPSignedInNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) { + Strongify( self ); + [self setMode:MPCombinedModePasswordSelection]; + } ); + PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) { + Strongify( self ); + [self setMode:MPCombinedModeUserSelection animated:[note.userInfo[@"animated"] boolValue]]; + } ); } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; - [self removeObservers]; + PearlRemoveNotificationObservers(); } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { @@ -142,35 +148,4 @@ #pragma mark - Private -- (void)registerObservers { - - if ([_notificationObservers count]) - return; - - Weakify( self ); - _notificationObservers = @[ - [[NSNotificationCenter defaultCenter] - addObserverForName:MPSignedInNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [self setMode:MPCombinedModePasswordSelection]; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:MPSignedOutNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [self setMode:MPCombinedModeUserSelection animated:[note.userInfo[@"animated"] boolValue]]; - }], - ]; -} - -- (void)removeObservers { - - for (id observer in _notificationObservers) - [[NSNotificationCenter defaultCenter] removeObserver:observer]; - _notificationObservers = nil; -} - @end diff --git a/MasterPassword/ObjC/iOS/MPEmergencyViewController.m b/MasterPassword/ObjC/iOS/MPEmergencyViewController.m index 6384789c..8d4f4c9f 100644 --- a/MasterPassword/ObjC/iOS/MPEmergencyViewController.m +++ b/MasterPassword/ObjC/iOS/MPEmergencyViewController.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPCombinedViewController.h @@ -23,7 +23,6 @@ MPKey *_key; NSOperationQueue *_emergencyKeyQueue; NSOperationQueue *_emergencyPasswordQueue; - NSArray *_notificationObservers; } - (void)viewDidLoad { @@ -42,14 +41,17 @@ [super viewWillAppear:animated]; [self reset]; - [self registerObservers]; + PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, nil, [NSOperationQueue mainQueue], + ^(MPEmergencyViewController *self, NSNotification *note) { + [self performSegueWithIdentifier:@"unwind-popover" sender:self]; + } ); } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; - [self removeObservers]; + PearlRemoveNotificationObservers(); [self reset]; } @@ -154,7 +156,7 @@ case 5: return MPSiteTypeGeneratedPIN; default: - Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex); + Throw( @"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex ); } } @@ -168,28 +170,4 @@ [self updateKey]; } -- (void)registerObservers { - - if ([_notificationObservers count]) - return; - - Weakify(self); - _notificationObservers = @[ - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationWillResignActiveNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify(self); - - [self performSegueWithIdentifier:@"unwind-popover" sender:self]; - }], - ]; -} - -- (void)removeObservers { - - for (id observer in _notificationObservers) - [[NSNotificationCenter defaultCenter] removeObserver:observer]; - _notificationObservers = nil; -} - @end diff --git a/MasterPassword/ObjC/iOS/MPLogsViewController.m b/MasterPassword/ObjC/iOS/MPLogsViewController.m index 58473015..e1418adc 100644 --- a/MasterPassword/ObjC/iOS/MPLogsViewController.m +++ b/MasterPassword/ObjC/iOS/MPLogsViewController.m @@ -1,12 +1,12 @@ /** - * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) - * - * See the enclosed file LICENSE for license information (LGPLv3). If you did - * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt - * - * @author Maarten Billemont - * @license http://www.gnu.org/licenses/lgpl-3.0.txt - */ +* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) +* +* See the enclosed file LICENSE for license information (LGPLv3). If you did +* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt +* +* @author Maarten Billemont +* @license http://www.gnu.org/licenses/lgpl-3.0.txt +*/ // // MPLogsViewController.h @@ -27,18 +27,17 @@ [super viewDidLoad]; self.view.backgroundColor = [UIColor clearColor]; - - [[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock: - ^(NSNotification *note) { - self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0; - }]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, [NSOperationQueue mainQueue], + ^(MPLogsViewController *self, NSNotification *note) { + self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0; + } ); + self.logView.contentInset = UIEdgeInsetsMake( 64, 0, 93, 0 ); [self refresh:nil]; @@ -46,13 +45,20 @@ self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0; } +- (void)viewWillDisappear:(BOOL)animated { + + [super viewWillDisappear:animated]; + + PearlRemoveNotificationObservers(); +} + - (IBAction)toggleLevelControl:(UISegmentedControl *)sender { BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex; if (traceEnabled) { [PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message: - @"Trace mode will log the internal operation of the application.\n" - @"Unless you're looking for the cause of a problem, you should leave this off to save memory." + @"Trace mode will log the internal operation of the application.\n" + @"Unless you're looking for the cause of a problem, you should leave this off to save memory." viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { if (buttonIndex == [alert cancelButtonIndex]) @@ -74,8 +80,8 @@ if ([[MPiOSConfig get].traceMode boolValue]) { [PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message: - @"Trace-level log messages will not be mailed. " - @"These messages contain sensitive and personal information." + @"Trace-level log messages will not be mailed. " + @"These messages contain sensitive and personal information." viewStyle:UIAlertViewStyleDefault initAlert:nil tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self]; diff --git a/MasterPassword/ObjC/iOS/MPOverlayViewController.h b/MasterPassword/ObjC/iOS/MPOverlayViewController.h index 5f2090d7..8f8d7b36 100644 --- a/MasterPassword/ObjC/iOS/MPOverlayViewController.h +++ b/MasterPassword/ObjC/iOS/MPOverlayViewController.h @@ -23,4 +23,7 @@ @end @interface MPOverlaySegue : UIStoryboardSegue + ++ (instancetype)dismissViewController:(UIViewController *)viewController; + @end diff --git a/MasterPassword/ObjC/iOS/MPOverlayViewController.m b/MasterPassword/ObjC/iOS/MPOverlayViewController.m index 3e141278..a67b7fcd 100644 --- a/MasterPassword/ObjC/iOS/MPOverlayViewController.m +++ b/MasterPassword/ObjC/iOS/MPOverlayViewController.m @@ -52,17 +52,20 @@ return [[MPOverlaySegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; } -- (void)addDismissButtonForSegue:(MPOverlaySegue *)segue { +- (UIView *)addDismissButtonForSegue:(MPOverlaySegue *)segue { UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom]; [dismissButton addTarget:self action:@selector( dismissOverlay: ) forControlEvents:UIControlEventTouchUpInside]; - dismissButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3f]; + dismissButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5f]; + dismissButton.alpha = 0; dismissButton.frame = self.view.bounds; dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _dismissSegueByButton[[NSValue valueWithNonretainedObject:dismissButton]] = [[MPOverlaySegue alloc] initWithIdentifier:@"dismiss-overlay" source:segue.destinationViewController destination:segue.sourceViewController]; + [self.view addSubview:dismissButton]; + return dismissButton; } - (void)dismissOverlay:(UIButton *)dismissButton { @@ -96,6 +99,11 @@ @implementation MPOverlaySegue ++ (instancetype)dismissViewController:(UIViewController *)viewController { + + return [[self alloc] initWithIdentifier:nil source:viewController destination:viewController]; +} + - (void)perform { UIViewController *sourceViewController = self.sourceViewController; @@ -109,6 +117,7 @@ if (!destinationViewController.parentViewController) { // Winding [containerViewController addChildViewController:destinationViewController]; + UIView *dismissButton = [containerViewController addDismissButtonForSegue:self]; destinationViewController.view.frame = containerViewController.view.bounds; destinationViewController.view.translatesAutoresizingMaskIntoConstraints = YES; @@ -125,6 +134,7 @@ destinationViewController.view.transform = CGAffineTransformIdentity; CGRectSetY( destinationViewController.view.frame, 0 ); destinationViewController.view.alpha = 1; + dismissButton.alpha = 1; } completion:^(BOOL finished) { [destinationViewController didMoveToParentViewController:containerViewController]; [containerViewController setNeedsStatusBarAppearanceUpdate]; diff --git a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m index f710e5f4..b0dc155f 100644 --- a/MasterPassword/ObjC/iOS/MPPasswordsViewController.m +++ b/MasterPassword/ObjC/iOS/MPPasswordsViewController.m @@ -22,7 +22,6 @@ #import "MPPopdownSegue.h" #import "MPAppDelegate_Key.h" #import "MPPasswordCell.h" -#import "UICollectionView+PearlReloadFromArray.h" #import "MPAnswersViewController.h" @interface MPPasswordsViewController() @@ -33,10 +32,6 @@ @end @implementation MPPasswordsViewController { - __weak id _storeChangingObserver; - __weak id _storeChangedObserver; - __weak id _mocObserver; - NSArray *_notificationObservers; __weak UITapGestureRecognizer *_passwordsDismissRecognizer; NSFetchedResultsController *_fetchedResultsController; UIColor *_backgroundColor; @@ -69,7 +64,6 @@ [super viewWillAppear:animated]; [self registerObservers]; - [self observeStore]; [self updateConfigKey:nil]; [self updatePasswords]; } @@ -90,8 +84,7 @@ [super viewWillDisappear:animated]; - [self removeObservers]; - [self stopObservingStore]; + PearlRemoveNotificationObservers(); } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { @@ -280,97 +273,49 @@ referenceSizeForHeaderInSection:(NSInteger)section { - (void)registerObservers { - if ([_notificationObservers count]) - return; - - Weakify( self ); - _notificationObservers = @[ - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - self.passwordSelectionContainer.alpha = 0; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationWillEnterForegroundNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [self updatePasswords]; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationDidBecomeActiveNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [UIView animateWithDuration:0.7f animations:^{ - self.passwordSelectionContainer.alpha = 1; - }]; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:MPSignedOutNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - _fetchedResultsController = nil; - self.passwordsSearchBar.text = nil; - [self.passwordCollectionView reloadData]; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:MPCheckConfigNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - [self updateConfigKey:note.object]; - }], - ]; -} - -- (void)removeObservers { - - for (id observer in _notificationObservers) - [[NSNotificationCenter defaultCenter] removeObserver:observer]; - _notificationObservers = nil; -} - -- (void)observeStore { - - Weakify( self ); + PearlRemoveNotificationObservers(); + PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue], + ^(MPPasswordsViewController *self, NSNotification *note) { + self.passwordSelectionContainer.alpha = 0; + } ); + PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue], + ^(MPPasswordsViewController *self, NSNotification *note) { + [self updatePasswords]; + } ); + PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue], + ^(MPPasswordsViewController *self, NSNotification *note) { + [UIView animateWithDuration:0.7f animations:^{ + self.passwordSelectionContainer.alpha = 1; + }]; + } ); + PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue], + ^(MPPasswordsViewController *self, NSNotification *note) { + _fetchedResultsController = nil; + self.passwordsSearchBar.text = nil; + [self.passwordCollectionView reloadData]; + } ); + PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue], + ^(MPPasswordsViewController *self, NSNotification *note) { + [self updateConfigKey:note.object]; + } ); + PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, nil, + ^(MPPasswordsViewController *self, NSNotification *note) { + self->_fetchedResultsController = nil; + [self.passwordCollectionView reloadData]; + } ); + PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, nil, nil, + ^(MPPasswordsViewController *self, NSNotification *note) { + [self updatePasswords]; + [self registerObservers]; + } ); NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; - if (!_mocObserver && mainContext) - _mocObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSManagedObjectContextDidSaveNotification object:mainContext - queue:nil usingBlock:^(NSNotification *note) { - if (![[MPiOSAppDelegate get] activeUserInContext:mainContext]) + if (mainContext) + PearlAddNotificationObserver( NSManagedObjectContextDidSaveNotification, mainContext, nil, + ^(MPPasswordsViewController *self, NSNotification *note) { + if (![[MPiOSAppDelegate get] activeUserInContext:note.object]) [[MPiOSAppDelegate get] signOutAnimated:YES]; - }]; - if (!_storeChangingObserver) - _storeChangingObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil - queue:nil usingBlock:^(NSNotification *note) { - Strongify( self ); - self->_fetchedResultsController = nil; - if (self->_mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver]; - [self.passwordCollectionView reloadData]; - }]; - if (!_storeChangedObserver) - _storeChangedObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil - queue:nil usingBlock:^(NSNotification *note) { - Strongify( self ); - [self updatePasswords]; - }]; -} - -- (void)stopObservingStore { - - if (_mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_mocObserver]; - if (_storeChangingObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_storeChangingObserver]; - if (_storeChangedObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_storeChangedObserver]; + } ); } - (void)updateConfigKey:(NSString *)key { @@ -454,7 +399,7 @@ referenceSizeForHeaderInSection:(NSInteger)section { initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil]; _fetchedResultsController.delegate = self; }]; - [self observeStore]; + [self registerObservers]; } return _fetchedResultsController; diff --git a/MasterPassword/ObjC/iOS/MPStoreViewController.m b/MasterPassword/ObjC/iOS/MPStoreViewController.m index aeae342d..d9858213 100644 --- a/MasterPassword/ObjC/iOS/MPStoreViewController.m +++ b/MasterPassword/ObjC/iOS/MPStoreViewController.m @@ -50,15 +50,22 @@ PearlEnum( MPDevelopmentFuelConsumption, } }]; - [[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, [NSOperationQueue mainQueue], + ^(MPStoreViewController *self, NSNotification *note) { [self updateProducts]; [self updateFuel]; - }]; + } ); [[MPiOSAppDelegate get] registerProductsObserver:self]; [self updateFuel]; } +- (void)viewWillDisappear:(BOOL)animated { + + [super viewWillDisappear:animated]; + + PearlRemoveNotificationObservers(); +} + #pragma mark - UITableViewDelegate - (MPStoreProductCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -221,7 +228,7 @@ PearlEnum( MPDevelopmentFuelConsumption, } CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuel / weeklyFuelConsumption; /* x weeks worth of fuel left */ - [self.fuelMeterConstraint updateConstant:MIN(0.5f, fuelRatio - 0.5f) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */ + [self.fuelMeterConstraint updateConstant:MIN( 0.5f, fuelRatio - 0.5f ) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */ } - (CGFloat)weeklyFuelConsumption { diff --git a/MasterPassword/ObjC/iOS/MPUsersViewController.m b/MasterPassword/ObjC/iOS/MPUsersViewController.m index 3c0a091b..18e645ea 100644 --- a/MasterPassword/ObjC/iOS/MPUsersViewController.m +++ b/MasterPassword/ObjC/iOS/MPUsersViewController.m @@ -22,9 +22,7 @@ #import "MPiOSAppDelegate.h" #import "MPAppDelegate_Store.h" #import "MPAppDelegate_Key.h" -#import "PearlSizedTextView.h" #import "MPWebViewController.h" -#import "UIView+FontScale.h" typedef NS_ENUM( NSUInteger, MPActiveUserState ) { /** The users are all inactive */ @@ -51,10 +49,6 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { @end @implementation MPUsersViewController { - __weak id _storeChangingObserver; - __weak id _storeChangedObserver; - __weak id _mocObserver; - NSArray *_notificationObservers; NSString *_masterPasswordChoice; NSOperationQueue *_afterUpdates; } @@ -89,8 +83,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { [super viewWillDisappear:animated]; - [self removeObservers]; - [self stopObservingStore]; + PearlRemoveNotificationObservers(); [self.marqueeTipTimer invalidate]; } @@ -99,7 +92,6 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) { [super viewDidAppear:animated]; - [self observeStore]; [self registerObservers]; [self reloadUsers]; @@ -475,15 +467,15 @@ referenceSizeForFooterInSection:(NSInteger)section { if ([nextMarqueeString isEqualToString:[self.marqueeButton titleForState:UIControlStateNormal]]) return; - [UIView animateWithDuration:timer? 0.5: 0 animations:^{ + [UIView animateWithDuration:timer? 0.5f: 0 animations:^{ self.marqueeButton.alpha = 0; } completion:^(BOOL finished) { if (!finished) return; [self.marqueeButton setTitle:nextMarqueeString forState:UIControlStateNormal]; - [UIView animateWithDuration:timer? 0.5: 0 animations:^{ - self.marqueeButton.alpha = 0.5; + [UIView animateWithDuration:timer? 0.5f: 0 animations:^{ + self.marqueeButton.alpha = 0.5f; }]; }]; } @@ -586,54 +578,27 @@ referenceSizeForFooterInSection:(NSInteger)section { - (void)registerObservers { - if ([_notificationObservers count]) - return; - - Weakify( self ); - _notificationObservers = @[ - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - self.userSelectionContainer.alpha = 0; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationWillEnterForegroundNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [self reloadUsers]; - }], - [[NSNotificationCenter defaultCenter] - addObserverForName:UIApplicationDidBecomeActiveNotification object:nil - queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { - Strongify( self ); - - [UIView animateWithDuration:0.7f animations:^{ - self.userSelectionContainer.alpha = 1; - }]; - }], - ]; - + [self removeKeyPathObservers]; [self observeKeyPath:@"avatarCollectionView.contentOffset" withBlock: ^(id from, id to, NSKeyValueChange cause, MPUsersViewController *_self) { [_self updateAvatarVisibility]; }]; -} -- (void)removeObservers { - - for (id observer in _notificationObservers) - [[NSNotificationCenter defaultCenter] removeObserver:observer]; - _notificationObservers = nil; - - [self removeKeyPathObservers]; -} - -- (void)observeStore { - - Weakify( self ); + PearlRemoveNotificationObservers(); + PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + self.userSelectionContainer.alpha = 0; + } ); + PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + [self reloadUsers]; + } ); + PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + [UIView animateWithDuration:0.5f animations:^{ + self.userSelectionContainer.alpha = 1; + }]; + } ); NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; [UIView animateWithDuration:0.3f animations:^{ @@ -644,51 +609,31 @@ referenceSizeForFooterInSection:(NSInteger)section { if (!mainContext && !self.storeLoadingActivity.isAnimating) [self.storeLoadingActivity startAnimating]; - if (!_mocObserver && mainContext) - _mocObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext - queue:nil usingBlock:^(NSNotification *note) { - Strongify( self ); - NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey]; - NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey]; - if ([[NSSetUnion( insertedObjects, deletedObjects ) - filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { - return [evaluatedObject isKindOfClass:[MPUserEntity class]]; - }]] count]) - [self reloadUsers]; - }]; - if (!_storeChangingObserver) - _storeChangingObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil - queue:nil usingBlock:^(NSNotification *note) { - Strongify( self ); - if (self->_mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver]; - self.userIDs = nil; - }]; - if (!_storeChangedObserver) - _storeChangedObserver = [[NSNotificationCenter defaultCenter] - addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil - queue:nil usingBlock:^(NSNotification *note) { - Strongify( self ); + if (mainContext) + PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, mainContext, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey]; + NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey]; + if ([[NSSetUnion( insertedObjects, deletedObjects ) + filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + return [evaluatedObject isKindOfClass:[MPUserEntity class]]; + }]] count]) [self reloadUsers]; - }]; -} - -- (void)stopObservingStore { - - if (_mocObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_mocObserver]; - if (_storeChangingObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_storeChangingObserver]; - if (_storeChangedObserver) - [[NSNotificationCenter defaultCenter] removeObserver:_storeChangedObserver]; + } ); + PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + self.userIDs = nil; + } ); + PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, nil, [NSOperationQueue mainQueue], + ^(MPUsersViewController *self, NSNotification *note) { + [self registerObservers]; + [self reloadUsers]; + } ); } - (void)reloadUsers { [self afterUpdatesMainQueue:^{ - [self observeStore]; if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { NSError *error = nil; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; diff --git a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m index cabe7a47..a210f051 100644 --- a/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m +++ b/MasterPassword/ObjC/iOS/MPiOSAppDelegate.m @@ -69,18 +69,15 @@ err( @"During Analytics Setup: %@", exception ); } @try { - [[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification *note) { - [self updateConfigKey:note.object]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil usingBlock: - ^(NSNotification *note) { - [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object]; - }]; - [[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil queue:nil usingBlock: - ^(NSNotification *note) { - [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil]; - }]; + PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) { + [self updateConfigKey:note.object]; + } ); + PearlAddNotificationObserver( kIASKAppSettingChanged, nil, nil, ^(id self, NSNotification *note) { + [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object]; + } ); + PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) { + [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil]; + } ); #ifdef ADHOC [PearlAlert showAlertWithTitle:@"Welcome, tester!" message: @@ -106,28 +103,27 @@ @try { inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] ); - [[NSNotificationCenter defaultCenter] addObserverForName:MPFoundInconsistenciesNotification object:nil queue:nil usingBlock: - ^(NSNotification *note) { - switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) { + PearlAddNotificationObserver( MPFoundInconsistenciesNotification, nil, nil, ^(id self, NSNotification *note) { + switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) { - case MPFixableResultNoProblems: - break; - case MPFixableResultProblemsFixed: - [PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message: - @"Some inconsistencies were detected in your sites.\n" - @"All issues were fixed." - viewStyle:UIAlertViewStyleDefault initAlert:nil - tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; - break; - case MPFixableResultProblemsNotFixed: - [PearlAlert showAlertWithTitle:@"Inconsistencies Found" message: - @"Some inconsistencies were detected in your sites.\n" - @"Not all issues could be fixed. Try signing in to each user or checking the logs." - viewStyle:UIAlertViewStyleDefault initAlert:nil - tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; - break; - } - }]; + case MPFixableResultNoProblems: + break; + case MPFixableResultProblemsFixed: + [PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message: + @"Some inconsistencies were detected in your sites.\n" + @"All issues were fixed." + viewStyle:UIAlertViewStyleDefault initAlert:nil + tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; + break; + case MPFixableResultProblemsNotFixed: + [PearlAlert showAlertWithTitle:@"Inconsistencies Found" message: + @"Some inconsistencies were detected in your sites.\n" + @"Not all issues could be fixed. Try signing in to each user or checking the logs." + viewStyle:UIAlertViewStyleDefault initAlert:nil + tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; + break; + } + } ); PearlMainQueue( ^{ if ([[MPiOSConfig get].showSetup boolValue]) diff --git a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj index e4f8f7ba..6ab120dc 100644 --- a/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword/ObjC/iOS/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -433,6 +433,7 @@ 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSizedTextView.m; sourceTree = ""; }; 93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = ""; }; 93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = ""; }; + 93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = ""; }; 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadFromArray.h"; sourceTree = ""; }; 93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = ""; }; 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = ""; }; @@ -2632,6 +2633,7 @@ DAFE45F915039823003ABA7C /* Resources */, 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */, 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */, + 93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */, ); path = Pearl; sourceTree = "";