diff --git a/Signal/src/Profiles/OWSProfileManager.m b/Signal/src/Profiles/OWSProfileManager.m index 7fb262e736..9c46b8aa1e 100644 --- a/Signal/src/Profiles/OWSProfileManager.m +++ b/Signal/src/Profiles/OWSProfileManager.m @@ -10,6 +10,7 @@ #import #import #import +#import #import #import #import @@ -249,22 +250,23 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; messageSender:self.messageSender profileManager:self]; - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_LocalProfileDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:kNSNotificationName_LocalProfileDidChange + object:nil + userInfo:nil]; } else { [[NSNotificationCenter defaultCenter] - postNotificationName:kNSNotificationName_OtherUsersProfileWillChange - object:nil - userInfo:@{ - kNSNotificationKey_ProfileRecipientId : userProfile.recipientId, - }]; + postNotificationNameAsync:kNSNotificationName_OtherUsersProfileWillChange + object:nil + userInfo:@{ + kNSNotificationKey_ProfileRecipientId : userProfile.recipientId, + }]; [[NSNotificationCenter defaultCenter] - postNotificationName:kNSNotificationName_OtherUsersProfileDidChange - object:nil - userInfo:@{ - kNSNotificationKey_ProfileRecipientId : userProfile.recipientId, - }]; + postNotificationNameAsync:kNSNotificationName_OtherUsersProfileDidChange + object:nil + userInfo:@{ + kNSNotificationKey_ProfileRecipientId : userProfile.recipientId, + }]; } }); } @@ -773,13 +775,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; [self.dbConnection setBool:YES forKey:recipientId inCollection:kOWSProfileManager_UserWhitelistCollection]; } - dispatch_async(dispatch_get_main_queue(), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_ProfileWhitelistDidChange - object:nil - userInfo:@{ - kNSNotificationKey_ProfileRecipientId : recipientId, - }]; - }); + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_ProfileWhitelistDidChange + object:nil + userInfo:@{ + kNSNotificationKey_ProfileRecipientId : recipientId, + }]; }); } @@ -812,16 +812,14 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; }]; } - dispatch_async(dispatch_get_main_queue(), ^{ for (NSString *recipientId in newRecipientIds) { [[NSNotificationCenter defaultCenter] - postNotificationName:kNSNotificationName_ProfileWhitelistDidChange - object:nil - userInfo:@{ - kNSNotificationKey_ProfileRecipientId : recipientId, - }]; + postNotificationNameAsync:kNSNotificationName_ProfileWhitelistDidChange + object:nil + userInfo:@{ + kNSNotificationKey_ProfileRecipientId : recipientId, + }]; } - }); }); } @@ -859,13 +857,12 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640; [self.dbConnection setBool:YES forKey:groupIdKey inCollection:kOWSProfileManager_GroupWhitelistCollection]; self.groupProfileWhitelistCache[groupIdKey] = @(YES); - dispatch_async(dispatch_get_main_queue(), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_ProfileWhitelistDidChange - object:nil - userInfo:@{ - kNSNotificationKey_ProfileGroupId : groupId, - }]; - }); + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:kNSNotificationName_ProfileWhitelistDidChange + object:nil + userInfo:@{ + kNSNotificationKey_ProfileGroupId : groupId, + }]; } }); } diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index e658ad86f1..39bb1b1188 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -54,6 +54,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 0071fde56a..e95f64b6b4 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -1213,6 +1213,9 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) { - (void)startExpirationTimerAnimations { + OWSAssert([NSThread isMainThread]); + + // This notification should be posted synchronously. [[NSNotificationCenter defaultCenter] postNotificationName:ConversationViewControllerDidAppearNotification object:nil]; } diff --git a/Signal/src/call/CallAudioService.swift b/Signal/src/call/CallAudioService.swift index 342839755e..4f93b457be 100644 --- a/Signal/src/call/CallAudioService.swift +++ b/Signal/src/call/CallAudioService.swift @@ -449,6 +449,8 @@ struct AudioSource: Hashable { mode: String? = nil, options: AVAudioSessionCategoryOptions = AVAudioSessionCategoryOptions(rawValue: 0)) { + AssertIsOnMainThread() + let session = AVAudioSession.sharedInstance() var audioSessionChanged = false do { @@ -500,7 +502,8 @@ struct AudioSource: Hashable { if audioSessionChanged { Logger.info("\(TAG) in \(#function)") - NotificationCenter.default.post(name: CallAudioServiceSessionChanged, object: nil) + // Update call view synchronously; already on main thread. + NotificationCenter.default.post(name:CallAudioServiceSessionChanged, object: nil) } } } diff --git a/Signal/src/contact/OWSContactsManager.m b/Signal/src/contact/OWSContactsManager.m index 694eddc34d..88df271662 100644 --- a/Signal/src/contact/OWSContactsManager.m +++ b/Signal/src/contact/OWSContactsManager.m @@ -9,6 +9,7 @@ #import "Util.h" #import "ViewControllerUtils.h" #import +#import #import #import #import @@ -308,8 +309,9 @@ NSString *const kTSStorageManager_AccountLastNames = @"kTSStorageManager_Account }]; }); - [[NSNotificationCenter defaultCenter] postNotificationName:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification + object:nil]; } - (void)loadCachedDisplayNames diff --git a/Signal/src/contact/SystemContactsFetcher.swift b/Signal/src/contact/SystemContactsFetcher.swift index 80aac269ae..947ed8611c 100644 --- a/Signal/src/contact/SystemContactsFetcher.swift +++ b/Signal/src/contact/SystemContactsFetcher.swift @@ -104,7 +104,7 @@ class ContactsFrameworkContactStoreAdaptee: ContactStoreAdaptee { } } -let kAddressBookContactyStoreDidChangeNotificationName = NSNotification.Name("AddressBookContactStoreAdapteeDidChange") +let kAddressBookContactStoreDidChangeNotificationName = NSNotification.Name("AddressBookContactStoreAdapteeDidChange") /** * System contact fetching compatible with iOS8 */ @@ -143,12 +143,12 @@ class AddressBookContactStoreAdaptee: ContactStoreAdaptee { assert(self.changeHandler == nil) self.changeHandler = changeHandler - NotificationCenter.default.addObserver(self, selector: #selector(runChangeHandler), name: kAddressBookContactyStoreDidChangeNotificationName, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(runChangeHandler), name: kAddressBookContactStoreDidChangeNotificationName, object: nil) let callback: ABExternalChangeCallback = { (_, _, _) in // Ideally we'd just call the changeHandler here, but because this is a C style callback in swift, // we can't capture any state in the closure, so we use a notification as a trampoline - NotificationCenter.default.post(name: kAddressBookContactyStoreDidChangeNotificationName, object: nil) + NotificationCenter.default.postNotificationNameAsync(kAddressBookContactStoreDidChangeNotificationName, object: nil) } ABAddressBookRegisterExternalChangeCallback(addressBook, callback, nil) diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index aafd4db9bc..5d4bdaf7e0 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -5,6 +5,7 @@ #import "TSAccountManager.h" #import "NSData+Base64.h" #import "NSData+hexString.h" +#import "NSNotificationCenter+OWS.h" #import "NSURLSessionDataTask+StatusCode.h" #import "OWSError.h" #import "SecurityUtils.h" @@ -70,9 +71,9 @@ NSString *const TSAccountManager_LocalRegistrationIdKey = @"TSStorageLocalRegist { _phoneNumberAwaitingVerification = phoneNumberAwaitingVerification; - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_LocalNumberDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_LocalNumberDidChange + object:nil + userInfo:nil]; } + (BOOL)isRegistered @@ -104,9 +105,9 @@ NSString *const TSAccountManager_LocalRegistrationIdKey = @"TSStorageLocalRegist [self storeLocalNumber:phoneNumber]; - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_RegistrationStateDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_RegistrationStateDidChange + object:nil + userInfo:nil]; } + (nullable NSString *)localNumber @@ -365,9 +366,10 @@ NSString *const TSAccountManager_LocalRegistrationIdKey = @"TSStorageLocalRegist // `kNSNotificationName_RegistrationStateDidChange` which is only safe to fire after // the data store is reset. - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_RegistrationStateDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:kNSNotificationName_RegistrationStateDidChange + object:nil + userInfo:nil]; } failure:^(NSURLSessionDataTask *task, NSError *error) { if (!IsNSErrorNetworkFailure(error)) { diff --git a/SignalServiceKit/src/Devices/OWSReadReceiptsProcessor.m b/SignalServiceKit/src/Devices/OWSReadReceiptsProcessor.m index 4088c10bf6..fe77baa7f3 100644 --- a/SignalServiceKit/src/Devices/OWSReadReceiptsProcessor.m +++ b/SignalServiceKit/src/Devices/OWSReadReceiptsProcessor.m @@ -3,6 +3,7 @@ // #import "OWSReadReceiptsProcessor.h" +#import "NSNotificationCenter+OWS.h" #import "OWSDisappearingMessagesJob.h" #import "OWSReadReceipt.h" #import "OWSSignalServiceProtos.pb.h" @@ -131,11 +132,9 @@ NSString *const OWSReadReceiptsProcessorMarkedMessageAsReadNotification = expirationStartedAt:readReceipt.timestamp]; // Fire event that will cancel any pending notifications for this message. - dispatch_async(dispatch_get_main_queue(), ^{ - [[NSNotificationCenter defaultCenter] - postNotificationName:OWSReadReceiptsProcessorMarkedMessageAsReadNotification - object:otherMessage]; - }); + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:OWSReadReceiptsProcessorMarkedMessageAsReadNotification + object:otherMessage]; } } diff --git a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m index c9e92eec19..13cbc5eaf8 100644 --- a/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m +++ b/SignalServiceKit/src/Messages/Attachments/OWSAttachmentsProcessor.m @@ -5,6 +5,7 @@ #import "OWSAttachmentsProcessor.h" #import "Cryptography.h" #import "MIMETypeUtil.h" +#import "NSNotificationCenter+OWS.h" #import "OWSError.h" #import "OWSSignalServiceProtos.pb.h" #import "TSAttachmentPointer.h" @@ -377,15 +378,13 @@ static const CGFloat kAttachmentDownloadProgressTheta = 0.001f; - (void)fireProgressNotification:(CGFloat)progress attachmentId:(NSString *)attachmentId { - dispatch_async(dispatch_get_main_queue(), ^{ - NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; - [notificationCenter postNotificationName:kAttachmentDownloadProgressNotification - object:nil - userInfo:@{ - kAttachmentDownloadProgressKey : @(progress), - kAttachmentDownloadAttachmentIDKey : attachmentId - }]; - }); + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter postNotificationNameAsync:kAttachmentDownloadProgressNotification + object:nil + userInfo:@{ + kAttachmentDownloadProgressKey : @(progress), + kAttachmentDownloadAttachmentIDKey : attachmentId + }]; } - (void)setAttachment:(TSAttachmentPointer *)pointer diff --git a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m index 45225acb57..d9656d4d5a 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m @@ -3,6 +3,7 @@ // #import "TSIncomingMessage.h" +#import "NSNotificationCenter+OWS.h" #import "OWSDisappearingMessagesConfiguration.h" #import "OWSDisappearingMessagesJob.h" #import "OWSReadReceiptManager.h" diff --git a/SignalServiceKit/src/Messages/OWSBlockingManager.m b/SignalServiceKit/src/Messages/OWSBlockingManager.m index 0038252134..6e435298e1 100644 --- a/SignalServiceKit/src/Messages/OWSBlockingManager.m +++ b/SignalServiceKit/src/Messages/OWSBlockingManager.m @@ -3,6 +3,7 @@ // #import "OWSBlockingManager.h" +#import "NSNotificationCenter+OWS.h" #import "OWSBlockedPhoneNumbersMessage.h" #import "OWSMessageSender.h" #import "TSStorageManager.h" @@ -201,9 +202,9 @@ NSString *const kOWSBlockingManager_SyncedBlockedPhoneNumbersKey = @"kOWSBlockin [self saveSyncedBlockedPhoneNumbers:blockedPhoneNumbers]; } - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_BlockedPhoneNumbersDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_BlockedPhoneNumbersDidChange + object:nil + userInfo:nil]; }); } diff --git a/SignalServiceKit/src/Messages/OWSIdentityManager.m b/SignalServiceKit/src/Messages/OWSIdentityManager.m index 93052e4913..834cca6ff4 100644 --- a/SignalServiceKit/src/Messages/OWSIdentityManager.m +++ b/SignalServiceKit/src/Messages/OWSIdentityManager.m @@ -4,6 +4,7 @@ #import "OWSIdentityManager.h" #import "NSDate+millisecondTimeStamp.h" +#import "NSNotificationCenter+OWS.h" #import "NotificationsProtocol.h" #import "OWSError.h" #import "OWSMessageSender.h" @@ -308,11 +309,9 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa - (void)fireIdentityStateChangeNotification { - dispatch_async(dispatch_get_main_queue(), ^{ - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_IdentityStateDidChange - object:nil - userInfo:nil]; - }); + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_IdentityStateDidChange + object:nil + userInfo:nil]; } - (BOOL)isTrustedIdentityKey:(NSData *)identityKey diff --git a/SignalServiceKit/src/Network/API/OWSUploadingService.m b/SignalServiceKit/src/Network/API/OWSUploadingService.m index 27a074539d..fc3e4ca19e 100644 --- a/SignalServiceKit/src/Network/API/OWSUploadingService.m +++ b/SignalServiceKit/src/Network/API/OWSUploadingService.m @@ -5,6 +5,7 @@ #import "OWSUploadingService.h" #import "Cryptography.h" #import "MIMETypeUtil.h" +#import "NSNotificationCenter+OWS.h" #import "OWSError.h" #import "OWSMessageSender.h" #import "TSAttachmentStream.h" @@ -167,15 +168,13 @@ static const CGFloat kAttachmentUploadProgressTheta = 0.001f; - (void)fireProgressNotification:(CGFloat)progress attachmentId:(NSString *)attachmentId { - dispatch_async(dispatch_get_main_queue(), ^{ NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; - [notificationCenter postNotificationName:kAttachmentUploadProgressNotification - object:nil - userInfo:@{ - kAttachmentUploadProgressKey : @(progress), - kAttachmentUploadAttachmentIDKey : attachmentId - }]; - }); + [notificationCenter postNotificationNameAsync:kAttachmentUploadProgressNotification + object:nil + userInfo:@{ + kAttachmentUploadProgressKey : @(progress), + kAttachmentUploadAttachmentIDKey : attachmentId + }]; } #pragma mark - Logging diff --git a/SignalServiceKit/src/Network/OWSSignalService.m b/SignalServiceKit/src/Network/OWSSignalService.m index 2568dbf8e2..037ab126c5 100644 --- a/SignalServiceKit/src/Network/OWSSignalService.m +++ b/SignalServiceKit/src/Network/OWSSignalService.m @@ -2,14 +2,14 @@ // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // -#import - +#import "OWSSignalService.h" +#import "NSNotificationCenter+OWS.h" #import "OWSCensorshipConfiguration.h" #import "OWSHTTPSecurityPolicy.h" -#import "OWSSignalService.h" #import "TSAccountManager.h" #import "TSConstants.h" #import "TSStorageManager.h" +#import NS_ASSUME_NONNULL_BEGIN @@ -141,9 +141,9 @@ NSString *const kNSNotificationName_IsCensorshipCircumventionActiveDidChange = } [[NSNotificationCenter defaultCenter] - postNotificationName:kNSNotificationName_IsCensorshipCircumventionActiveDidChange - object:nil - userInfo:nil]; + postNotificationNameAsync:kNSNotificationName_IsCensorshipCircumventionActiveDidChange + object:nil + userInfo:nil]; } - (BOOL)isCensorshipCircumventionActive diff --git a/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m b/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m index 154df77c9d..27150ae44c 100644 --- a/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m +++ b/SignalServiceKit/src/Network/WebSockets/TSSocketManager.m @@ -4,6 +4,7 @@ #import "TSSocketManager.h" #import "Cryptography.h" +#import "NSNotificationCenter+OWS.h" #import "NSTimer+OWS.h" #import "OWSMessageManager.h" #import "OWSMessageReceiver.h" @@ -296,9 +297,9 @@ NSString *const kNSNotification_SocketManagerStateDidChange = @"kNSNotification_ - (void)notifyStatusChange { - [[NSNotificationCenter defaultCenter] postNotificationName:kNSNotification_SocketManagerStateDidChange - object:nil - userInfo:nil]; + [[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotification_SocketManagerStateDidChange + object:nil + userInfo:nil]; } #pragma mark - diff --git a/SignalServiceKit/src/Storage/TSDatabaseView.m b/SignalServiceKit/src/Storage/TSDatabaseView.m index 5ef98df256..6d2e1b5b16 100644 --- a/SignalServiceKit/src/Storage/TSDatabaseView.m +++ b/SignalServiceKit/src/Storage/TSDatabaseView.m @@ -3,6 +3,7 @@ // #import "TSDatabaseView.h" +#import "NSNotificationCenter+OWS.h" #import "OWSDevice.h" #import "OWSReadTracking.h" #import "TSIncomingMessage.h" @@ -443,9 +444,9 @@ NSString *const TSSecondaryDevicesDatabaseViewExtensionName = @"TSSecondaryDevic dispatch_async(dispatch_get_main_queue(), ^{ [[NSNotificationCenter defaultCenter] - postNotificationName:kNSNotificationName_DatabaseViewRegistrationComplete - object:nil - userInfo:nil]; + postNotificationNameAsync:kNSNotificationName_DatabaseViewRegistrationComplete + object:nil + userInfo:nil]; }); }]; } diff --git a/SignalServiceKit/src/Util/NSNotificationCenter+OWS.h b/SignalServiceKit/src/Util/NSNotificationCenter+OWS.h new file mode 100644 index 0000000000..b58a7c2026 --- /dev/null +++ b/SignalServiceKit/src/Util/NSNotificationCenter+OWS.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +NS_ASSUME_NONNULL_BEGIN + +// We often use notifications as way to publish events. +// +// We never need these events to be received synchronously, +// so we should always send them asynchronously to avoid any +// possible risk of deadlock. These methods also ensure that +// the notifications are always fired on the main thread. +@interface NSNotificationCenter (OWS) + +- (void)postNotificationNameAsync:(NSNotificationName)name object:(nullable id)object; +- (void)postNotificationNameAsync:(NSNotificationName)name + object:(nullable id)object + userInfo:(nullable NSDictionary *)userInfo; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Util/NSNotificationCenter+OWS.m b/SignalServiceKit/src/Util/NSNotificationCenter+OWS.m new file mode 100644 index 0000000000..c406ff6b72 --- /dev/null +++ b/SignalServiceKit/src/Util/NSNotificationCenter+OWS.m @@ -0,0 +1,29 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "NSNotificationCenter+OWS.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation NSNotificationCenter (OWS) + +- (void)postNotificationNameAsync:(NSNotificationName)name object:(nullable id)object +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self postNotificationName:name object:object]; + }); +} + +- (void)postNotificationNameAsync:(NSNotificationName)name + object:(nullable id)object + userInfo:(nullable NSDictionary *)userInfo +{ + dispatch_async(dispatch_get_main_queue(), ^{ + [self postNotificationName:name object:object userInfo:userInfo]; + }); +} + +@end + +NS_ASSUME_NONNULL_END