From ad11c50c1bc4deffa0b369883050e197c96ee1b2 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 1 May 2017 14:10:53 -0400 Subject: [PATCH] Reworking observation of Contact and SignalAccount changes. // FREEBIE --- .../MessageComposeTableViewController.m | 7 +- .../ViewControllers/SignalsViewController.m | 18 ++- Signal/src/contact/OWSContactsManager.h | 6 - Signal/src/contact/OWSContactsManager.m | 147 ++++++++---------- Signal/src/util/OWSContactsSyncing.m | 22 ++- 5 files changed, 99 insertions(+), 101 deletions(-) diff --git a/Signal/src/ViewControllers/MessageComposeTableViewController.m b/Signal/src/ViewControllers/MessageComposeTableViewController.m index 853e97c3f..947c2e0f8 100644 --- a/Signal/src/ViewControllers/MessageComposeTableViewController.m +++ b/Signal/src/ViewControllers/MessageComposeTableViewController.m @@ -106,8 +106,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie - (void)observeNotifications { [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(signalRecipientsDidChange:) - name:OWSContactsManagerSignalRecipientsDidChangeNotification + selector:@selector(signalAccountsDidChange:) + name:OWSContactsManagerSignalAccountsDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(blockedPhoneNumbersDidChange:) @@ -120,7 +120,8 @@ NSString *const MessageComposeTableViewControllerCellContact = @"ContactTableVie [[NSNotificationCenter defaultCenter] removeObserver:self]; } -- (void)signalRecipientsDidChange:(NSNotification *)notification { +- (void)signalAccountsDidChange:(NSNotification *)notification +{ dispatch_async(dispatch_get_main_queue(), ^{ [self updateContacts]; }); diff --git a/Signal/src/ViewControllers/SignalsViewController.m b/Signal/src/ViewControllers/SignalsViewController.m index 6b07a2539..5a93a6f0d 100644 --- a/Signal/src/ViewControllers/SignalsViewController.m +++ b/Signal/src/ViewControllers/SignalsViewController.m @@ -93,6 +93,10 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS selector:@selector(blockedPhoneNumbersDidChange:) name:kNSNotificationName_BlockedPhoneNumbersDidChange object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(signalAccountsDidChange:) + name:OWSContactsManagerSignalAccountsDidChangeNotification + object:nil]; } - (void)dealloc @@ -109,6 +113,13 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS }); } +- (void)signalAccountsDidChange:(id)notification +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self.tableView reloadData]; + }); +} + - (void)awakeFromNib { [super awakeFromNib]; @@ -131,13 +142,6 @@ NSString *const SignalsViewControllerSegueShowIncomingCall = @"ShowIncomingCallS object:nil]; [self selectedInbox:self]; - __weak SignalsViewController *weakSelf = self; - [[[Environment getCurrent] contactsManager].getObservableContacts watchLatestValue:^(id latestValue) { - [weakSelf.tableView reloadData]; - } - onThread:[NSThread mainThread] - untilCancelled:nil]; - self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[ NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil), NSLocalizedString(@"ARCHIVE_NAV_BAR_TITLE", nil) diff --git a/Signal/src/contact/OWSContactsManager.h b/Signal/src/contact/OWSContactsManager.h index e8eff9494..500a0c094 100644 --- a/Signal/src/contact/OWSContactsManager.h +++ b/Signal/src/contact/OWSContactsManager.h @@ -8,14 +8,10 @@ #import #import "CollapsingFutures.h" #import "Contact.h" -#import "ObservableValue.h" NS_ASSUME_NONNULL_BEGIN extern NSString *const OWSContactsManagerSignalAccountsDidChangeNotification; -// TODO: Remove this. -// TODO: Remove observableContactsController. -extern NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification; @class UIFont; @class SignalAccount; @@ -33,8 +29,6 @@ extern NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification; @property (atomic, readonly) NSDictionary *signalAccountMap; @property (atomic, readonly) NSArray *signalAccounts; -- (nonnull ObservableValue *)getObservableContacts; - - (nullable SignalAccount *)signalAccountForRecipientId:(nullable NSString *)recipientId; - (Contact *)getOrBuildContactForPhoneIdentifier:(NSString *)identifier; diff --git a/Signal/src/contact/OWSContactsManager.m b/Signal/src/contact/OWSContactsManager.m index 84c46f1f4..7eb2395b3 100644 --- a/Signal/src/contact/OWSContactsManager.m +++ b/Signal/src/contact/OWSContactsManager.m @@ -15,16 +15,12 @@ typedef BOOL (^ContactSearchBlock)(id, NSUInteger, BOOL *); NSString *const OWSContactsManagerSignalAccountsDidChangeNotification = @"OWSContactsManagerSignalAccountsDidChangeNotification"; -NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification = - @"OWSContactsManagerSignalRecipientsDidChangeNotification"; @interface OWSContactsManager () @property (atomic, nullable) CNContactStore *contactStore; @property (atomic) id addressBookReference; @property (atomic) TOCFuture *futureAddressBook; -@property (atomic) ObservableValueController *observableContactsController; -@property (atomic) TOCCancelTokenSource *life; @property (nonatomic) BOOL isContactsUpdateInFlight; // This reflects the contents of the device phone book and includes // contacts that do not correspond to any signal account. @@ -37,18 +33,12 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification = @implementation OWSContactsManager -- (void)dealloc { - [_life cancel]; -} - - (id)init { self = [super init]; if (!self) { return self; } - _life = [TOCCancelTokenSource new]; - _observableContactsController = [ObservableValueController observableValueControllerWithInitialValue:nil]; _avatarCache = [NSCache new]; _allContacts = @[]; _signalAccountMap = @{}; @@ -74,14 +64,6 @@ NSString *const OWSContactsManagerSignalRecipientsDidChangeNotification = } [self setupAddressBookIfNecessary]; - - __weak OWSContactsManager *weakSelf = self; - [self.observableContactsController watchLatestValueOnArbitraryThread:^(NSArray *latestContacts) { - @synchronized(self) { - [weakSelf updateSignalAccounts:latestContacts]; - } - } - untilCancelled:_life.token]; } - (void)verifyABPermission { @@ -100,9 +82,8 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in - (void)handleAddressBookChanged { - [self pullLatestAddressBook]; - [self intersectContacts]; [self.avatarCache removeAllObjects]; + [self pullLatestAddressBook]; } #pragma mark - Setup @@ -155,7 +136,7 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in { void (^success)() = ^{ DDLogInfo(@"%@ Successfully intersected contacts.", self.tag); - [self fireSignalRecipientsDidChange]; + [self updateSignalAccounts]; }; void (^failure)(NSError *error) = ^(NSError *error) { if ([error.domain isEqualToString:OWSSignalServiceKitErrorDomain] @@ -179,70 +160,82 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in failure:failure]; } -- (void)fireSignalRecipientsDidChange -{ - AssertIsOnMainThread(); - - [[NSNotificationCenter defaultCenter] postNotificationName:OWSContactsManagerSignalRecipientsDidChangeNotification - object:nil]; -} - - (void)pullLatestAddressBook { - CFErrorRef creationError = nil; - ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError); - checkOperationDescribe(nil == creationError, [((__bridge NSError *)creationError)localizedDescription]); - ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { - if (!granted) { - [OWSContactsManager blockingContactDialog]; - } + dispatch_async(ADDRESSBOOK_QUEUE, ^{ + CFErrorRef creationError = nil; + ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &creationError); + checkOperationDescribe(nil == creationError, [((__bridge NSError *)creationError)localizedDescription]); + ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) { + if (!granted) { + [OWSContactsManager blockingContactDialog]; + } + }); + NSArray *contacts = [self getContactsFromAddressBook:addressBookRef]; + [self updateWithContacts:contacts]; }); - [self.observableContactsController updateValue:[self getContactsFromAddressBook:addressBookRef]]; } -- (void)updateSignalAccounts:(NSArray *)contacts +- (void)updateWithContacts:(NSArray *)contacts { - // This will happen off of the main thread. + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; - NSMutableArray *signalAccounts = [NSMutableArray new]; - NSMutableDictionary *allContactsMap = [NSMutableDictionary new]; - for (Contact *contact in contacts) { - for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { - NSString *phoneNumberE164 = phoneNumber.toE164; - if (phoneNumberE164.length > 0) { - allContactsMap[phoneNumberE164] = contact; + NSMutableDictionary *allContactsMap = [NSMutableDictionary new]; + for (Contact *contact in contacts) { + for (PhoneNumber *phoneNumber in contact.parsedPhoneNumbers) { + NSString *phoneNumberE164 = phoneNumber.toE164; + if (phoneNumberE164.length > 0) { + allContactsMap[phoneNumberE164] = contact; + } } } - NSArray *signalRecipients = contact.signalRecipients; - for (SignalRecipient *signalRecipient in contact.signalRecipients) { - for (NSString *recipientId in - [contact.textSecureIdentifiers sortedArrayUsingSelector:@selector(compare:)]) { - SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; - signalAccount.contact = contact; - if (signalRecipients.count > 1) { - signalAccount.isMultipleAccountContact = YES; - signalAccount.multipleAccountLabel = - [[self class] accountLabelForContact:contact recipientId:recipientId]; - } - if (signalAccountMap[signalAccount.recipientId]) { - DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); - continue; + dispatch_async(dispatch_get_main_queue(), ^{ + self.allContacts = contacts; + self.allContactsMap = [allContactsMap copy]; + + [self intersectContacts]; + + [self updateSignalAccounts]; + }); + }); +} + +- (void)updateSignalAccounts +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSMutableDictionary *signalAccountMap = [NSMutableDictionary new]; + NSMutableArray *signalAccounts = [NSMutableArray new]; + NSArray *contacts = self.allContacts; + [[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + for (Contact *contact in contacts) { + NSArray *signalRecipients = [contact signalRecipientsWithTransaction:transaction]; + for (SignalRecipient *signalRecipient in + [signalRecipients sortedArrayUsingSelector:@selector(compare:)]) { + SignalAccount *signalAccount = [[SignalAccount alloc] initWithSignalRecipient:signalRecipient]; + signalAccount.contact = contact; + if (signalRecipients.count > 1) { + signalAccount.isMultipleAccountContact = YES; + signalAccount.multipleAccountLabel = + [[self class] accountLabelForContact:contact recipientId:signalRecipient.recipientId]; + } + if (signalAccountMap[signalAccount.recipientId]) { + DDLogInfo(@"Ignoring duplicate contact: %@, %@", signalAccount.recipientId, contact.fullName); + continue; + } + signalAccountMap[signalAccount.recipientId] = signalAccount; + [signalAccounts addObject:signalAccount]; } - signalAccountMap[signalAccount.recipientId] = signalAccount; - [signalAccounts addObject:signalAccount]; } - } - } + }]; - dispatch_async(dispatch_get_main_queue(), ^{ - self.allContacts = contacts; - self.signalAccountMap = [signalAccountMap copy]; - self.signalAccounts = [signalAccounts copy]; - self.allContactsMap = [allContactsMap copy]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.signalAccountMap = [signalAccountMap copy]; + self.signalAccounts = [signalAccounts copy]; - [[NSNotificationCenter defaultCenter] postNotificationName:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + postNotificationName:OWSContactsManagerSignalAccountsDidChangeNotification + object:nil]; + }); }); } @@ -371,12 +364,6 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in } } -#pragma mark - Observables - -- (ObservableValue *)getObservableContacts { - return self.observableContactsController; -} - #pragma mark - Address Book utils + (TOCFuture *)asyncGetAddressBook { @@ -405,8 +392,10 @@ void onAddressBookChanged(ABAddressBookRef notifyAddressBook, CFDictionaryRef in return futureAddressBookSource.future; } -- (NSArray *)getContactsFromAddressBook:(ABAddressBookRef _Nonnull)addressBook { +- (NSArray *)getContactsFromAddressBook:(ABAddressBookRef _Nonnull)addressBook +{ CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(addressBook); + CFMutableArrayRef allPeopleMutable = CFArrayCreateMutableCopy(kCFAllocatorDefault, CFArrayGetCount(allPeople), allPeople); diff --git a/Signal/src/util/OWSContactsSyncing.m b/Signal/src/util/OWSContactsSyncing.m index 42c391f88..49fa6036d 100644 --- a/Signal/src/util/OWSContactsSyncing.m +++ b/Signal/src/util/OWSContactsSyncing.m @@ -44,16 +44,26 @@ NSString *const kTSStorageManagerOWSContactsSyncingLastMessageKey = OWSSingletonAssert(); - __weak OWSContactsSyncing *weakSelf = self; - [contactsManager.getObservableContacts watchLatestValue:^(id latestValue) { - [weakSelf sendSyncContactsMessageIfPossible]; - } - onThread:[NSThread mainThread] - untilCancelled:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(signalAccountsDidChange:) + name:OWSContactsManagerSignalAccountsDidChangeNotification + object:nil]; return self; } +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)signalAccountsDidChange:(id)notification +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self sendSyncContactsMessageIfPossible]; + }); +} + #pragma mark - Methods - (void)sendSyncContactsMessageIfNecessary