From d9172cccb9965c327ef3012e62d190c568a70c62 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 30 May 2018 19:21:06 -0400 Subject: [PATCH 1/8] Measure time to display // FREEBIE --- .../ConversationView/ConversationViewController.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index cc3ae95fd..c46a03e46 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -158,6 +158,7 @@ typedef enum : NSUInteger { @property (nonatomic) TSThread *thread; @property (nonatomic) YapDatabaseConnection *editingDatabaseConnection; @property (nonatomic, readonly) AudioActivity *voiceNoteAudioActivity; +@property (nonatomic, readonly) NSTimeInterval viewControllerCreatedAt; // These two properties must be updated in lockstep. // @@ -275,6 +276,8 @@ typedef enum : NSUInteger { - (void)commonInit { + + _viewControllerCreatedAt = CACurrentMediaTime(); _contactsManager = [Environment current].contactsManager; _contactsUpdater = [Environment current].contactsUpdater; _messageSender = [Environment current].messageSender; @@ -677,6 +680,11 @@ typedef enum : NSUInteger { } [self updateLastVisibleTimestamp]; + + if (!self.viewHasEverAppeared) { + NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt; + DDLogInfo(@"%@ First viewWillAppear took: %.2fms", self.logTag, appearenceDuration * 1000); + } } - (NSIndexPath *_Nullable)indexPathOfUnreadMessagesIndicator @@ -1078,6 +1086,7 @@ typedef enum : NSUInteger { self.actionOnOpen = ConversationViewActionNone; + self.isViewCompletelyAppeared = YES; self.viewHasEverAppeared = YES; From ddd39fcd3d8f07caa5c2a5f9d2866c26f4426d25 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 31 May 2018 14:25:45 -0400 Subject: [PATCH 2/8] separate read/write db connections // FREEBIE --- .../ConversationViewController.m | 3 +- SignalMessaging/utils/ThreadUtil.h | 5 +- SignalMessaging/utils/ThreadUtil.m | 47 +++++++++++++++---- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index c46a03e46..28aadc63e 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2466,7 +2466,8 @@ typedef enum : NSUInteger { [ThreadUtil ensureDynamicInteractionsForThread:self.thread contactsManager:self.contactsManager blockingManager:self.blockingManager - dbConnection:self.editingDatabaseConnection + uiDatabaseConnection:self.uiDatabaseConnection + editingDatabaseConnection:self.editingDatabaseConnection hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator firstUnseenInteractionTimestamp:self.dynamicInteractions.firstUnseenInteractionTimestamp maxRangeSize:maxRangeSize]; diff --git a/SignalMessaging/utils/ThreadUtil.h b/SignalMessaging/utils/ThreadUtil.h index 197cc1c67..152282b92 100644 --- a/SignalMessaging/utils/ThreadUtil.h +++ b/SignalMessaging/utils/ThreadUtil.h @@ -102,9 +102,10 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection + uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection + editingDatabaseConnection:(YapDatabaseConnection *)editingDatabaseConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp + firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestampParameter maxRangeSize:(int)maxRangeSize; + (BOOL)shouldShowGroupProfileBannerInThread:(TSThread *)thread blockingManager:(OWSBlockingManager *)blockingManager; diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index c5df4a72a..e9eedd8b7 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -217,14 +217,16 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection + uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection + editingDatabaseConnection:(YapDatabaseConnection *)editingDatabaseConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp: (nullable NSNumber *)firstUnseenInteractionTimestampParameter maxRangeSize:(int)maxRangeSize { OWSAssert(thread); - OWSAssert(dbConnection); + OWSAssert(uiDatabaseConnection); + OWSAssert(editingDatabaseConnection); OWSAssert(contactsManager); OWSAssert(blockingManager); OWSAssert(maxRangeSize > 0); @@ -247,7 +249,8 @@ NS_ASSUME_NONNULL_BEGIN ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + NSMutableArray *writeBlocks = [NSMutableArray new]; + [uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { const int kMaxBlockOfferOutgoingMessageCount = 10; // Find any "dynamic" interactions and safety number changes. @@ -305,7 +308,9 @@ NS_ASSUME_NONNULL_BEGIN for (TSInteraction *interaction in interactionsToDelete) { DDLogDebug(@"Cleaning up interaction: %@", [interaction class]); - [interaction removeWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [interaction removeWithTransaction:writeTransaction]; + }]; } // Determine if there are "unread" messages in this conversation. @@ -546,7 +551,11 @@ NS_ASSUME_NONNULL_BEGIN // Preserve the timestamp of the existing "contact offers" so that // we replace it in the same position in the timeline. contactOffersTimestamp = existingContactOffers.timestamp; - [existingContactOffers removeWithTransaction:transaction]; + + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [existingContactOffers removeWithTransaction:writeTransaction]; + }]; + existingContactOffers = nil; } } @@ -556,7 +565,9 @@ NS_ASSUME_NONNULL_BEGIN self.logTag, existingContactOffers.uniqueId, existingContactOffers.timestampForSorting); - [existingContactOffers removeWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [existingContactOffers removeWithTransaction:writeTransaction]; + }]; } else if (!existingContactOffers && shouldHaveContactOffers) { NSString *recipientId = ((TSContactThread *)thread).contactIdentifier; @@ -567,7 +578,9 @@ NS_ASSUME_NONNULL_BEGIN hasAddToContactsOffer:shouldHaveAddToContactsOffer hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer recipientId:recipientId]; - [offersMessage saveWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [offersMessage saveWithTransaction:writeTransaction]; + }]; DDLogInfo(@"%@ Creating contact offers: %@ (%llu)", self.logTag, @@ -582,7 +595,9 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Removing obsolete TSUnreadIndicatorInteraction: %@", self.logTag, existingUnreadIndicator.uniqueId); - [existingUnreadIndicator removeWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [existingUnreadIndicator removeWithTransaction:writeTransaction]; + }]; } } else { // We want the unread indicator to appear just before the first unread incoming @@ -599,7 +614,9 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Removing TSUnreadIndicatorInteraction due to changed timestamp: %@", self.logTag, existingUnreadIndicator.uniqueId); - [existingUnreadIndicator removeWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [existingUnreadIndicator removeWithTransaction:writeTransaction]; + }]; } TSUnreadIndicatorInteraction *indicator = [[TSUnreadIndicatorInteraction alloc] @@ -607,7 +624,9 @@ NS_ASSUME_NONNULL_BEGIN thread:thread hasMoreUnseenMessages:result.hasMoreUnseenMessages missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount]; - [indicator saveWithTransaction:transaction]; + [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { + [indicator saveWithTransaction:writeTransaction]; + }]; DDLogInfo(@"%@ Creating TSUnreadIndicatorInteraction: %@ (%llu)", self.logTag, @@ -617,6 +636,14 @@ NS_ASSUME_NONNULL_BEGIN } }]; + if (writeBlocks.count > 0) { + [editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull writeTransaction) { + for (void (^ writeBlock)(YapDatabaseReadWriteTransaction *) in writeBlocks) { + writeBlock(writeTransaction); + } + }]; + } + return result; } From 00f8ea4ff8fd5164b52d9dac2579fae23a6cf0c8 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 31 May 2018 13:27:39 -0400 Subject: [PATCH 3/8] Use a single ui connection to share cache. Primarly two things: 1. using an extension for the first time per connection is slow 2. fetching the same objects (e.g. if you leave/re-enter the same conversation) // FREEBIE --- .../ConversationViewController.m | 60 +++++++--------- .../src/Storage/OWSPrimaryStorage.h | 12 +++- .../src/Storage/OWSPrimaryStorage.m | 71 +++++++++++++++++-- 3 files changed, 102 insertions(+), 41 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 28aadc63e..65fe5a58a 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -80,6 +80,7 @@ #import #import #import +#import #import #import #import @@ -312,13 +313,17 @@ typedef enum : NSUInteger { name:UIContentSizeCategoryDidChangeNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(yapDatabaseModified:) - name:YapDatabaseModifiedNotification + selector:@selector(uiDatabaseDidUpdateExternally:) + name:OWSUIDatabaseConnectionDidUpdateExternallyNotification object:OWSPrimaryStorage.sharedManager.dbNotificationObject]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(yapDatabaseModifiedExternally:) - name:YapDatabaseModifiedExternallyNotification - object:nil]; + selector:@selector(uiDatabaseWillUpdate:) + name:OWSUIDatabaseConnectionWillUpdateNotification + object:OWSPrimaryStorage.sharedManager.dbNotificationObject]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(uiDatabaseDidUpdate:) + name:OWSUIDatabaseConnectionDidUpdateNotification + object:OWSPrimaryStorage.sharedManager.dbNotificationObject]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground:) name:OWSApplicationWillEnterForegroundNotification @@ -3114,14 +3119,7 @@ typedef enum : NSUInteger { - (YapDatabaseConnection *)uiDatabaseConnection { - NSAssert([NSThread isMainThread], @"Must access uiDatabaseConnection on main thread!"); - if (!_uiDatabaseConnection) { - _uiDatabaseConnection = [self.primaryStorage newDatabaseConnection]; - // Increase object cache limit. Default is 250. - _uiDatabaseConnection.objectCacheLimit = 500; - [_uiDatabaseConnection beginLongLivedReadTransaction]; - } - return _uiDatabaseConnection; + return OWSPrimaryStorage.sharedManager.uiDatabaseConnection; } - (YapDatabaseConnection *)editingDatabaseConnection @@ -3132,7 +3130,7 @@ typedef enum : NSUInteger { return _editingDatabaseConnection; } -- (void)yapDatabaseModifiedExternally:(NSNotification *)notification +- (void)uiDatabaseDidUpdateExternally:(NSNotification *)notification { OWSAssertIsOnMainThread(); @@ -3149,20 +3147,8 @@ typedef enum : NSUInteger { } } -- (void)yapDatabaseModified:(NSNotification *)notification +- (void)uiDatabaseWillUpdate:(NSNotification *)notification { - OWSAssertIsOnMainThread(); - - // Currently, we update thread and message state every time - // the database is modified. That doesn't seem optimal, but - // in practice it's efficient enough. - - if (!self.shouldObserveDBModifications) { - return; - } - - DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); - // HACK to work around radar #28167779 // "UICollectionView performBatchUpdates can trigger a crash if the collection view is flagged for layout" // more: https://github.com/PSPDFKit-labs/radar.apple.com/tree/master/28167779%20-%20CollectionViewBatchingIssue @@ -3173,11 +3159,21 @@ typedef enum : NSUInteger { // view items before they are updated. [self.collectionView layoutIfNeeded]; // ENDHACK to work around radar #28167779 +} + +- (void)uiDatabaseDidUpdate:(NSNotification *)notification +{ + OWSAssertIsOnMainThread(); - // We need to `beginLongLivedReadTransaction` before we update our - // models in order to jump to the most recent commit. - NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction]; + if (!self.shouldObserveDBModifications) { + return; + } + + DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + NSArray *notifications = notification.userInfo[OWSUIDatabaseConnectionNotificationsKey]; + OWSAssert([notifications isKindOfClass:[NSArray class]]); + [self updateBackButtonUnreadCount]; [self updateNavigationBarSubtitleLabel]; @@ -4660,10 +4656,6 @@ typedef enum : NSUInteger { if (self.messageMappings != nil) { // Before we begin observing database modifications, make sure // our mapping and table state is up-to-date. - // - // We need to `beginLongLivedReadTransaction` before we update our - // mapping in order to jump to the most recent commit. - [self.uiDatabaseConnection beginLongLivedReadTransaction]; [self extendRangeToIncludeUnobservedItems]; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.messageMappings updateWithTransaction:transaction]; diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h b/SignalServiceKit/src/Storage/OWSPrimaryStorage.h index 64c68ba8d..702cbf7cb 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.h +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.h @@ -6,14 +6,22 @@ NS_ASSUME_NONNULL_BEGIN +extern NSString *const OWSUIDatabaseConnectionWillUpdateNotification; +extern NSString *const OWSUIDatabaseConnectionDidUpdateNotification; +extern NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification; +extern NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification; +extern NSString *const OWSUIDatabaseConnectionNotificationsKey; + @interface OWSPrimaryStorage : OWSStorage - (instancetype)init NS_UNAVAILABLE; + (instancetype)sharedManager NS_SWIFT_NAME(shared()); -- (YapDatabaseConnection *)dbReadConnection; -- (YapDatabaseConnection *)dbReadWriteConnection; +@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection; +@property (nonatomic, readonly) YapDatabaseConnection *dbReadConnection; +@property (nonatomic, readonly) YapDatabaseConnection *dbReadWriteConnection; + + (YapDatabaseConnection *)dbReadConnection; + (YapDatabaseConnection *)dbReadWriteConnection; diff --git a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m index e9f0f7ebd..c30519dd7 100644 --- a/SignalServiceKit/src/Storage/OWSPrimaryStorage.m +++ b/SignalServiceKit/src/Storage/OWSPrimaryStorage.m @@ -19,6 +19,12 @@ NS_ASSUME_NONNULL_BEGIN +NSString *const OWSUIDatabaseConnectionWillUpdateNotification = @"OWSUIDatabaseConnectionWillUpdateNotification"; +NSString *const OWSUIDatabaseConnectionDidUpdateNotification = @"OWSUIDatabaseConnectionDidUpdateNotification"; +NSString *const OWSUIDatabaseConnectionWillUpdateExternallyNotification = @"OWSUIDatabaseConnectionWillUpdateExternallyNotification"; +NSString *const OWSUIDatabaseConnectionDidUpdateExternallyNotification = @"OWSUIDatabaseConnectionDidUpdateExternallyNotification"; + +NSString *const OWSUIDatabaseConnectionNotificationsKey = @"OWSUIDatabaseConnectionNotificationsKey"; NSString *const OWSPrimaryStorageExceptionName_CouldNotCreateDatabaseDirectory = @"TSStorageManagerExceptionName_CouldNotCreateDatabaseDirectory"; @@ -86,9 +92,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) @interface OWSPrimaryStorage () -@property (nonatomic, readonly, nullable) YapDatabaseConnection *dbReadConnection; -@property (nonatomic, readonly, nullable) YapDatabaseConnection *dbReadWriteConnection; - @property (atomic) BOOL areAsyncRegistrationsComplete; @property (atomic) BOOL areSyncRegistrationsComplete; @@ -98,6 +101,8 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) @implementation OWSPrimaryStorage +@synthesize uiDatabaseConnection = _uiDatabaseConnection; + + (instancetype)sharedManager { static OWSPrimaryStorage *sharedManager = nil; @@ -119,8 +124,22 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) if (self) { [self loadDatabase]; - _dbReadConnection = self.newDatabaseConnection; - _dbReadWriteConnection = self.newDatabaseConnection; + _dbReadConnection = [self newDatabaseConnection]; + _dbReadWriteConnection = [self newDatabaseConnection]; + _uiDatabaseConnection = [self newDatabaseConnection]; + + // Increase object cache limit. Default is 250. + _uiDatabaseConnection.objectCacheLimit = 500; + [_uiDatabaseConnection beginLongLivedReadTransaction]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(yapDatabaseModified:) + name:YapDatabaseModifiedNotification + object:self.dbNotificationObject]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(yapDatabaseModifiedExternally:) + name:YapDatabaseModifiedExternallyNotification + object:nil]; OWSSingletonAssert(); } @@ -128,6 +147,48 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) return self; } +- (void)yapDatabaseModifiedExternally:(NSNotification *)notification +{ + // Notify observers we're about to update the database connection + [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateExternallyNotification object:self.dbNotificationObject]; + + // Move uiDatabaseConnection to the latest commit. + // Do so atomically, and fetch all the notifications for each commit we jump. + NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction]; + + // Notify observers that the uiDatabaseConnection was updated + NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications }; + [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateExternallyNotification + object:self.dbNotificationObject + userInfo:userInfo]; +} + +- (void)yapDatabaseModified:(NSNotification *)notification +{ + OWSAssertIsOnMainThread(); + + DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__); + + // Notify observers we're about to update the database connection + [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionWillUpdateNotification object:self.dbNotificationObject]; + + // Move uiDatabaseConnection to the latest commit. + // Do so atomically, and fetch all the notifications for each commit we jump. + NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction]; + + // Notify observers that the uiDatabaseConnection was updated + NSDictionary *userInfo = @{ OWSUIDatabaseConnectionNotificationsKey: notifications }; + [[NSNotificationCenter defaultCenter] postNotificationName:OWSUIDatabaseConnectionDidUpdateNotification + object:self.dbNotificationObject + userInfo:userInfo]; +} + +- (YapDatabaseConnection *)uiDatabaseConnection +{ + OWSAssertIsOnMainThread(); + return _uiDatabaseConnection; +} + - (void)resetStorage { _dbReadConnection = nil; From 468f7524ef4cae740153525a6910c6091cec5b3d Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 1 Jun 2018 09:57:50 -0400 Subject: [PATCH 4/8] Revert "separate read/write db connections" This reverts commit 3e61741060e6a7c2a9891b46cf3abd567d33aa3a. --- .../ConversationViewController.m | 3 +- SignalMessaging/utils/ThreadUtil.h | 5 +- SignalMessaging/utils/ThreadUtil.m | 47 ++++--------------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 65fe5a58a..169a54846 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2471,8 +2471,7 @@ typedef enum : NSUInteger { [ThreadUtil ensureDynamicInteractionsForThread:self.thread contactsManager:self.contactsManager blockingManager:self.blockingManager - uiDatabaseConnection:self.uiDatabaseConnection - editingDatabaseConnection:self.editingDatabaseConnection + dbConnection:self.editingDatabaseConnection hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator firstUnseenInteractionTimestamp:self.dynamicInteractions.firstUnseenInteractionTimestamp maxRangeSize:maxRangeSize]; diff --git a/SignalMessaging/utils/ThreadUtil.h b/SignalMessaging/utils/ThreadUtil.h index 152282b92..197cc1c67 100644 --- a/SignalMessaging/utils/ThreadUtil.h +++ b/SignalMessaging/utils/ThreadUtil.h @@ -102,10 +102,9 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection - editingDatabaseConnection:(YapDatabaseConnection *)editingDatabaseConnection + dbConnection:(YapDatabaseConnection *)dbConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator - firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestampParameter + firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp maxRangeSize:(int)maxRangeSize; + (BOOL)shouldShowGroupProfileBannerInThread:(TSThread *)thread blockingManager:(OWSBlockingManager *)blockingManager; diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index e9eedd8b7..c5df4a72a 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -217,16 +217,14 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection - editingDatabaseConnection:(YapDatabaseConnection *)editingDatabaseConnection + dbConnection:(YapDatabaseConnection *)dbConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp: (nullable NSNumber *)firstUnseenInteractionTimestampParameter maxRangeSize:(int)maxRangeSize { OWSAssert(thread); - OWSAssert(uiDatabaseConnection); - OWSAssert(editingDatabaseConnection); + OWSAssert(dbConnection); OWSAssert(contactsManager); OWSAssert(blockingManager); OWSAssert(maxRangeSize > 0); @@ -249,8 +247,7 @@ NS_ASSUME_NONNULL_BEGIN ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; - NSMutableArray *writeBlocks = [NSMutableArray new]; - [uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { const int kMaxBlockOfferOutgoingMessageCount = 10; // Find any "dynamic" interactions and safety number changes. @@ -308,9 +305,7 @@ NS_ASSUME_NONNULL_BEGIN for (TSInteraction *interaction in interactionsToDelete) { DDLogDebug(@"Cleaning up interaction: %@", [interaction class]); - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [interaction removeWithTransaction:writeTransaction]; - }]; + [interaction removeWithTransaction:transaction]; } // Determine if there are "unread" messages in this conversation. @@ -551,11 +546,7 @@ NS_ASSUME_NONNULL_BEGIN // Preserve the timestamp of the existing "contact offers" so that // we replace it in the same position in the timeline. contactOffersTimestamp = existingContactOffers.timestamp; - - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [existingContactOffers removeWithTransaction:writeTransaction]; - }]; - + [existingContactOffers removeWithTransaction:transaction]; existingContactOffers = nil; } } @@ -565,9 +556,7 @@ NS_ASSUME_NONNULL_BEGIN self.logTag, existingContactOffers.uniqueId, existingContactOffers.timestampForSorting); - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [existingContactOffers removeWithTransaction:writeTransaction]; - }]; + [existingContactOffers removeWithTransaction:transaction]; } else if (!existingContactOffers && shouldHaveContactOffers) { NSString *recipientId = ((TSContactThread *)thread).contactIdentifier; @@ -578,9 +567,7 @@ NS_ASSUME_NONNULL_BEGIN hasAddToContactsOffer:shouldHaveAddToContactsOffer hasAddToProfileWhitelistOffer:shouldHaveAddToProfileWhitelistOffer recipientId:recipientId]; - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [offersMessage saveWithTransaction:writeTransaction]; - }]; + [offersMessage saveWithTransaction:transaction]; DDLogInfo(@"%@ Creating contact offers: %@ (%llu)", self.logTag, @@ -595,9 +582,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Removing obsolete TSUnreadIndicatorInteraction: %@", self.logTag, existingUnreadIndicator.uniqueId); - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [existingUnreadIndicator removeWithTransaction:writeTransaction]; - }]; + [existingUnreadIndicator removeWithTransaction:transaction]; } } else { // We want the unread indicator to appear just before the first unread incoming @@ -614,9 +599,7 @@ NS_ASSUME_NONNULL_BEGIN DDLogInfo(@"%@ Removing TSUnreadIndicatorInteraction due to changed timestamp: %@", self.logTag, existingUnreadIndicator.uniqueId); - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [existingUnreadIndicator removeWithTransaction:writeTransaction]; - }]; + [existingUnreadIndicator removeWithTransaction:transaction]; } TSUnreadIndicatorInteraction *indicator = [[TSUnreadIndicatorInteraction alloc] @@ -624,9 +607,7 @@ NS_ASSUME_NONNULL_BEGIN thread:thread hasMoreUnseenMessages:result.hasMoreUnseenMessages missingUnseenSafetyNumberChangeCount:missingUnseenSafetyNumberChangeCount]; - [writeBlocks addObject:^(YapDatabaseReadWriteTransaction *writeTransaction) { - [indicator saveWithTransaction:writeTransaction]; - }]; + [indicator saveWithTransaction:transaction]; DDLogInfo(@"%@ Creating TSUnreadIndicatorInteraction: %@ (%llu)", self.logTag, @@ -636,14 +617,6 @@ NS_ASSUME_NONNULL_BEGIN } }]; - if (writeBlocks.count > 0) { - [editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull writeTransaction) { - for (void (^ writeBlock)(YapDatabaseReadWriteTransaction *) in writeBlocks) { - writeBlock(writeTransaction); - } - }]; - } - return result; } From 6e6a7446d02a4ef4afa707858e1a7bee5a87e172 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 1 Jun 2018 10:02:06 -0400 Subject: [PATCH 5/8] Use global readWrite connection // FREEBIE --- .../ConversationView/ConversationViewController.m | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 169a54846..dee268429 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3123,10 +3123,7 @@ typedef enum : NSUInteger { - (YapDatabaseConnection *)editingDatabaseConnection { - if (!_editingDatabaseConnection) { - _editingDatabaseConnection = [self.primaryStorage newDatabaseConnection]; - } - return _editingDatabaseConnection; + return OWSPrimaryStorage.sharedManager.dbReadWriteConnection; } - (void)uiDatabaseDidUpdateExternally:(NSNotification *)notification From e6c659d0ff5e810ae633de477ef8bff4ecd3d4ee Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 1 Jun 2018 10:11:24 -0400 Subject: [PATCH 6/8] remove incorrect comment --- .../ConversationView/ConversationViewController.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index dee268429..9eacfd0a7 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2465,8 +2465,6 @@ typedef enum : NSUInteger { const int currentMaxRangeSize = (int)self.lastRangeLength; const int maxRangeSize = MAX(kConversationInitialMaxRangeSize, currentMaxRangeSize); - // `ensureDynamicInteractionsForThread` should operate on the latest thread contents, so - // we should _read_ from uiDatabaseConnection and _write_ to `editingDatabaseConnection`. self.dynamicInteractions = [ThreadUtil ensureDynamicInteractionsForThread:self.thread contactsManager:self.contactsManager From ae1d82be841e506fc9ed1f019840a83e20b4f824 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 1 Jun 2018 11:09:16 -0400 Subject: [PATCH 7/8] Fix: input toolbar disappears when tapping media while edit menu is present // FREEBIE --- .../ConversationView/ConversationViewController.m | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 9eacfd0a7..3f68d8784 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -2075,6 +2075,12 @@ typedef enum : NSUInteger { [self dismissKeyBoard]; + // In case we were presenting edit menu, we need to become first responder before presenting another VC + // else UIKit won't restore first responder status to us when the presented VC is dismissed. + if (!self.isFirstResponder) { + [self becomeFirstResponder]; + } + if (![viewItem.interaction isKindOfClass:[TSMessage class]]) { OWSFail(@"Unexpected viewItem.interaction"); return; @@ -2098,6 +2104,11 @@ typedef enum : NSUInteger { OWSAssert(attachmentStream); [self dismissKeyBoard]; + // In case we were presenting edit menu, we need to become first responder before presenting another VC + // else UIKit won't restore first responder status to us when the presented VC is dismissed. + if (!self.isFirstResponder) { + [self becomeFirstResponder]; + } if (![viewItem.interaction isKindOfClass:[TSMessage class]]) { OWSFail(@"Unexpected viewItem.interaction"); From 9aafd899794a6df1643d7f02536feb48213922eb Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Fri, 1 Jun 2018 13:17:47 -0400 Subject: [PATCH 8/8] Remove unused synthesized ivars // FREEBIE --- .../ConversationView/ConversationViewController.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 3f68d8784..01c3c0f7b 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -157,7 +157,7 @@ typedef enum : NSUInteger { @property (nullable, nonatomic) UIPanGestureRecognizer *currentShowMessageDetailsPanGesture; @property (nonatomic) TSThread *thread; -@property (nonatomic) YapDatabaseConnection *editingDatabaseConnection; +@property (nonatomic, readonly) YapDatabaseConnection *editingDatabaseConnection; @property (nonatomic, readonly) AudioActivity *voiceNoteAudioActivity; @property (nonatomic, readonly) NSTimeInterval viewControllerCreatedAt; @@ -176,7 +176,7 @@ typedef enum : NSUInteger { // * If the first and/or second steps changes the set of messages // their ordering and/or their state, we must do the third and fourth steps. // * If we do the third step, we must call resetContentAndLayout afterward. -@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection; +@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection; @property (nonatomic) YapDatabaseViewMappings *messageMappings; @property (nonatomic, readonly) ConversationInputToolbar *inputToolbar; @@ -688,7 +688,7 @@ typedef enum : NSUInteger { if (!self.viewHasEverAppeared) { NSTimeInterval appearenceDuration = CACurrentMediaTime() - self.viewControllerCreatedAt; - DDLogInfo(@"%@ First viewWillAppear took: %.2fms", self.logTag, appearenceDuration * 1000); + DDLogVerbose(@"%@ First viewWillAppear took: %.2fms", self.logTag, appearenceDuration * 1000); } }