From d4a6a35ee30432afc36dcb88acc14fc13ead2baa Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Jun 2017 13:56:23 -0400 Subject: [PATCH 1/5] Avoid stale mapping in conversation view. // FREEBIE --- .../ConversationView/MessagesViewController.m | 40 ++++++++++--- Signal/src/util/ThreadUtil.h | 3 +- Signal/src/util/ThreadUtil.m | 59 +++++++++++++------ 3 files changed, 75 insertions(+), 27 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index d6c0f2d6d..26fdd6372 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -332,6 +332,8 @@ typedef enum : NSUInteger { _composeOnOpen = keyboardOnViewAppearing; _callOnOpen = callOnViewAppearing; + [self.uiDatabaseConnection beginLongLivedReadTransaction]; + // We need to create the "unread indicator" before we mark // all messages as read. [self ensureDynamicInteractions]; @@ -564,9 +566,12 @@ typedef enum : NSUInteger { // We need to `beginLongLivedReadTransaction` before we update our // mapping in order to jump to the most recent commit. [self.uiDatabaseConnection beginLongLivedReadTransaction]; + self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.thread.uniqueId ] + view:TSMessageDatabaseViewExtensionName]; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.messageMappings updateWithTransaction:transaction]; }]; + [self updateMessageMappingRangeOptions]; [self toggleObservers:YES]; @@ -2218,6 +2223,10 @@ typedef enum : NSUInteger { // while updating the range and the dynamic interactions. [[NSNotificationCenter defaultCenter] removeObserver:self name:YapDatabaseModifiedNotification object:nil]; + // We need to `beginLongLivedReadTransaction` before we update our + // mapping in order to jump to the most recent commit. + [self.uiDatabaseConnection beginLongLivedReadTransaction]; + // We need to update the dynamic interactions after loading earlier messages, // since the unseen indicator may need to move or change. [self ensureDynamicInteractions]; @@ -2566,7 +2575,7 @@ typedef enum : NSUInteger { DDLogInfo(@"%@ Blocking an unknown user.", self.tag); [self.blockingManager addBlockedPhoneNumber:errorMessage.contactId]; // Delete the block offer. - [self.storageManager.dbConnection + [self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [errorMessage removeWithTransaction:transaction]; }]; @@ -2693,7 +2702,8 @@ typedef enum : NSUInteger { [ThreadUtil ensureDynamicInteractionsForThread:self.thread contactsManager:self.contactsManager blockingManager:self.blockingManager - dbConnection:self.editingDatabaseConnection + readDBConnection:self.uiDatabaseConnection + writeDBConnection:self.editingDatabaseConnection hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator firstUnseenInteractionTimestamp:self.dynamicInteractions.firstUnseenInteractionTimestamp maxRangeSize:maxRangeSize]; @@ -3206,8 +3216,8 @@ typedef enum : NSUInteger { [self setNavigationTitle]; } - if (! - [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] hasChangesForNotifications:notifications]) { + if (![[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] hasChangesForGroup:self.thread.uniqueId + inNotifications:notifications]) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.messageMappings updateWithTransaction:transaction]; }]; @@ -3223,12 +3233,24 @@ typedef enum : NSUInteger { NSArray *messageRowChanges = nil; NSArray *sectionChanges = nil; - [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] getSectionChanges:§ionChanges - rowChanges:&messageRowChanges - forNotifications:notifications - withMappings:self.messageMappings]; + [[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] + getSectionChanges:§ionChanges + rowChanges:&messageRowChanges + forNotifications:notifications + withMappings:self.messageMappings]; + + if ([sectionChanges count] == 0 && [messageRowChanges count] == 0) { + // YapDatabase will ignore insertions within the message mapping's + // range that are not within the current mapping's contents. We + // may need to extend the mapping's contents to reflect the current + // range. + [self updateMessageMappingRangeOptions]; + + [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [self.messageMappings updateWithTransaction:transaction]; + }]; + [self resetContentAndLayout]; - if ([sectionChanges count] == 0 & [messageRowChanges count] == 0) { return; } diff --git a/Signal/src/util/ThreadUtil.h b/Signal/src/util/ThreadUtil.h index 41c84ab78..3f4f28768 100644 --- a/Signal/src/util/ThreadUtil.h +++ b/Signal/src/util/ThreadUtil.h @@ -83,7 +83,8 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection + readDBConnection:(YapDatabaseConnection *)readDBConnection + writeDBConnection:(YapDatabaseConnection *)writeDBConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp maxRangeSize:(int)maxRangeSize; diff --git a/Signal/src/util/ThreadUtil.m b/Signal/src/util/ThreadUtil.m index 7dfb85018..d68cba379 100644 --- a/Signal/src/util/ThreadUtil.m +++ b/Signal/src/util/ThreadUtil.m @@ -116,14 +116,16 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - dbConnection:(YapDatabaseConnection *)dbConnection + readDBConnection:(YapDatabaseConnection *)readDBConnection + writeDBConnection:(YapDatabaseConnection *)writeDBConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp: (nullable NSNumber *)firstUnseenInteractionTimestampParameter maxRangeSize:(int)maxRangeSize { OWSAssert(thread); - OWSAssert(dbConnection); + OWSAssert(readDBConnection); + OWSAssert(writeDBConnection); OWSAssert(contactsManager); OWSAssert(blockingManager); OWSAssert(maxRangeSize > 0); @@ -133,15 +135,23 @@ NS_ASSUME_NONNULL_BEGIN ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; - [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - const int kMaxBlockOfferOutgoingMessageCount = 10; + const int kMaxBlockOfferOutgoingMessageCount = 10; + + __block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil; + __block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil; + __block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil; + NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; + NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; + __block TSMessage *firstMessage = nil; + __block NSUInteger outgoingMessageCount; + __block NSUInteger threadMessageCount; + __block long visibleUnseenMessageCount = 0; + __block TSInteraction *interactionAfterUnreadIndicator = nil; + __block NSUInteger missingUnseenSafetyNumberChangeCount = 0; + + [readDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { // Find any "dynamic" interactions and safety number changes. - __block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil; - __block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil; - __block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil; - NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; - NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; // We use different views for performance reasons. [[TSDatabaseView threadSpecialMessagesDatabaseView:transaction] enumerateRowsInGroup:thread.uniqueId @@ -186,7 +196,6 @@ NS_ASSUME_NONNULL_BEGIN } } - __block TSMessage *firstMessage = nil; [[transaction ext:TSMessageDatabaseViewExtensionName] enumerateRowsInGroup:thread.uniqueId usingBlock:^( @@ -201,9 +210,9 @@ NS_ASSUME_NONNULL_BEGIN } }]; - NSUInteger outgoingMessageCount = + outgoingMessageCount = [[TSDatabaseView threadOutgoingMessageDatabaseView:transaction] numberOfItemsInGroup:thread.uniqueId]; - NSUInteger threadMessageCount = + threadMessageCount = [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId]; // Enumerate in reverse to count the number of messages @@ -212,9 +221,6 @@ NS_ASSUME_NONNULL_BEGIN // the messages view the position of the unread indicator, // so that it can widen its "load window" to always show // the unread indicator. - __block long visibleUnseenMessageCount = 0; - __block TSInteraction *interactionAfterUnreadIndicator = nil; - NSUInteger missingUnseenSafetyNumberChangeCount = 0; if (result.firstUnseenInteractionTimestamp != nil) { [[transaction ext:TSMessageDatabaseViewExtensionName] enumerateRowsInGroup:thread.uniqueId @@ -288,7 +294,9 @@ NS_ASSUME_NONNULL_BEGIN result.unreadIndicatorPosition = @(visibleUnseenMessageCount); } OWSAssert((result.firstUnseenInteractionTimestamp != nil) == (result.unreadIndicatorPosition != nil)); + }]; + [writeDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { BOOL shouldHaveBlockOffer = YES; BOOL shouldHaveAddToContactsOffer = YES; @@ -347,7 +355,11 @@ NS_ASSUME_NONNULL_BEGIN const int kUnreadIndicatorOfferOffset = -1; if (existingBlockOffer && !shouldHaveBlockOffer) { - DDLogInfo(@"Removing block offer"); + DDLogInfo(@"%@ Removing block offer: %@ (%llu)", + self.tag, + existingBlockOffer.uniqueId, + existingBlockOffer.timestampForSorting); + ; [existingBlockOffer removeWithTransaction:transaction]; } else if (!existingBlockOffer && shouldHaveBlockOffer) { DDLogInfo(@"Creating block offer for unknown contact"); @@ -363,10 +375,18 @@ NS_ASSUME_NONNULL_BEGIN thread:thread contactId:recipientId]; [offerMessage saveWithTransaction:transaction]; + + DDLogInfo(@"%@ Creating block offer: %@ (%llu)", + self.tag, + offerMessage.uniqueId, + offerMessage.timestampForSorting); } if (existingAddToContactsOffer && !shouldHaveAddToContactsOffer) { - DDLogInfo(@"Removing 'add to contacts' offer"); + DDLogInfo(@"%@ Removing 'add to contacts' offer: %@ (%llu)", + self.tag, + existingAddToContactsOffer.uniqueId, + existingAddToContactsOffer.timestampForSorting); [existingAddToContactsOffer removeWithTransaction:transaction]; } else if (!existingAddToContactsOffer && shouldHaveAddToContactsOffer) { @@ -383,6 +403,11 @@ NS_ASSUME_NONNULL_BEGIN thread:thread contactId:recipientId]; [offerMessage saveWithTransaction:transaction]; + + DDLogInfo(@"%@ Creating 'add to contacts' offer: %@ (%llu)", + self.tag, + offerMessage.uniqueId, + offerMessage.timestampForSorting); } BOOL shouldHaveUnreadIndicator From f6f08891ebc2931ae2459ea140d8fa1dfebb7eaf Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Jun 2017 14:05:59 -0400 Subject: [PATCH 2/5] Avoid stale mapping in conversation view. // FREEBIE --- .../ViewControllers/ConversationView/MessagesViewController.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index 26fdd6372..d9c226404 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -2698,6 +2698,8 @@ typedef enum : NSUInteger { const int currentMaxRangeSize = (int)(self.page + 1) * kYapDatabasePageSize; const int maxRangeSize = MAX(initialMaxRangeSize, 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 331a1e90e3e3a52735e350b74402a3975f4b6cd8 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Jun 2017 14:13:20 -0400 Subject: [PATCH 3/5] Avoid stale mapping in conversation view. // FREEBIE --- .../ViewControllers/ConversationView/MessagesViewController.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index d9c226404..c0e2ec9c6 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -566,8 +566,6 @@ typedef enum : NSUInteger { // We need to `beginLongLivedReadTransaction` before we update our // mapping in order to jump to the most recent commit. [self.uiDatabaseConnection beginLongLivedReadTransaction]; - self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.thread.uniqueId ] - view:TSMessageDatabaseViewExtensionName]; [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.messageMappings updateWithTransaction:transaction]; }]; From 0d07e0222f8daa026a42894986f5d2fe25192613 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Jun 2017 15:27:39 -0400 Subject: [PATCH 4/5] Avoid stale mapping in conversation view. // FREEBIE --- .../ViewControllers/ConversationView/MessagesViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index c0e2ec9c6..6ee81b6d8 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -548,8 +548,6 @@ typedef enum : NSUInteger { [self ensureBannerState]; - [self resetContentAndLayout]; - [super viewWillAppear:animated]; // In case we're dismissing a CNContactViewController which requires default system appearance @@ -570,6 +568,8 @@ typedef enum : NSUInteger { [self.messageMappings updateWithTransaction:transaction]; }]; [self updateMessageMappingRangeOptions]; + + [self resetContentAndLayout]; [self toggleObservers:YES]; From d01a52758bd8e8b9c11e4279752b5e5f1b88a877 Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 19 Jun 2017 17:10:34 -0400 Subject: [PATCH 5/5] Respond to CR. // FREEBIE --- .../ConversationView/MessagesViewController.m | 13 +++---- Signal/src/util/ThreadUtil.h | 3 +- Signal/src/util/ThreadUtil.m | 38 ++++++++----------- 3 files changed, 21 insertions(+), 33 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m index 6ee81b6d8..d24c61223 100644 --- a/Signal/src/ViewControllers/ConversationView/MessagesViewController.m +++ b/Signal/src/ViewControllers/ConversationView/MessagesViewController.m @@ -332,8 +332,6 @@ typedef enum : NSUInteger { _composeOnOpen = keyboardOnViewAppearing; _callOnOpen = callOnViewAppearing; - [self.uiDatabaseConnection beginLongLivedReadTransaction]; - // We need to create the "unread indicator" before we mark // all messages as read. [self ensureDynamicInteractions]; @@ -540,6 +538,8 @@ typedef enum : NSUInteger { - (void)viewWillAppear:(BOOL)animated { + DDLogDebug(@"%@ viewWillAppear", self.tag); + // We need to update the dynamic interactions before we do any layout. [self ensureDynamicInteractions]; @@ -990,6 +990,8 @@ typedef enum : NSUInteger { - (void)viewWillDisappear:(BOOL)animated { + DDLogDebug(@"%@ viewWillDisappear", self.tag); + [super viewWillDisappear:animated]; [self toggleObservers:NO]; @@ -2221,10 +2223,6 @@ typedef enum : NSUInteger { // while updating the range and the dynamic interactions. [[NSNotificationCenter defaultCenter] removeObserver:self name:YapDatabaseModifiedNotification object:nil]; - // We need to `beginLongLivedReadTransaction` before we update our - // mapping in order to jump to the most recent commit. - [self.uiDatabaseConnection beginLongLivedReadTransaction]; - // We need to update the dynamic interactions after loading earlier messages, // since the unseen indicator may need to move or change. [self ensureDynamicInteractions]; @@ -2702,8 +2700,7 @@ typedef enum : NSUInteger { [ThreadUtil ensureDynamicInteractionsForThread:self.thread contactsManager:self.contactsManager blockingManager:self.blockingManager - readDBConnection:self.uiDatabaseConnection - writeDBConnection:self.editingDatabaseConnection + dbConnection:self.editingDatabaseConnection hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator firstUnseenInteractionTimestamp:self.dynamicInteractions.firstUnseenInteractionTimestamp maxRangeSize:maxRangeSize]; diff --git a/Signal/src/util/ThreadUtil.h b/Signal/src/util/ThreadUtil.h index 3f4f28768..41c84ab78 100644 --- a/Signal/src/util/ThreadUtil.h +++ b/Signal/src/util/ThreadUtil.h @@ -83,8 +83,7 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - readDBConnection:(YapDatabaseConnection *)readDBConnection - writeDBConnection:(YapDatabaseConnection *)writeDBConnection + dbConnection:(YapDatabaseConnection *)dbConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp:(nullable NSNumber *)firstUnseenInteractionTimestamp maxRangeSize:(int)maxRangeSize; diff --git a/Signal/src/util/ThreadUtil.m b/Signal/src/util/ThreadUtil.m index d68cba379..6ae76e02a 100644 --- a/Signal/src/util/ThreadUtil.m +++ b/Signal/src/util/ThreadUtil.m @@ -116,16 +116,14 @@ NS_ASSUME_NONNULL_BEGIN + (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread contactsManager:(OWSContactsManager *)contactsManager blockingManager:(OWSBlockingManager *)blockingManager - readDBConnection:(YapDatabaseConnection *)readDBConnection - writeDBConnection:(YapDatabaseConnection *)writeDBConnection + dbConnection:(YapDatabaseConnection *)dbConnection hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator firstUnseenInteractionTimestamp: (nullable NSNumber *)firstUnseenInteractionTimestampParameter maxRangeSize:(int)maxRangeSize { OWSAssert(thread); - OWSAssert(readDBConnection); - OWSAssert(writeDBConnection); + OWSAssert(dbConnection); OWSAssert(contactsManager); OWSAssert(blockingManager); OWSAssert(maxRangeSize > 0); @@ -135,23 +133,15 @@ NS_ASSUME_NONNULL_BEGIN ThreadDynamicInteractions *result = [ThreadDynamicInteractions new]; - const int kMaxBlockOfferOutgoingMessageCount = 10; - - __block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil; - __block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil; - __block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil; - NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; - NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; - __block TSMessage *firstMessage = nil; - __block NSUInteger outgoingMessageCount; - __block NSUInteger threadMessageCount; - __block long visibleUnseenMessageCount = 0; - __block TSInteraction *interactionAfterUnreadIndicator = nil; - __block NSUInteger missingUnseenSafetyNumberChangeCount = 0; - - [readDBConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + [dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + const int kMaxBlockOfferOutgoingMessageCount = 10; // Find any "dynamic" interactions and safety number changes. + __block OWSAddToContactsOfferMessage *existingAddToContactsOffer = nil; + __block OWSUnknownContactBlockOfferMessage *existingBlockOffer = nil; + __block TSUnreadIndicatorInteraction *existingUnreadIndicator = nil; + NSMutableArray *blockingSafetyNumberChanges = [NSMutableArray new]; + NSMutableArray *nonBlockingSafetyNumberChanges = [NSMutableArray new]; // We use different views for performance reasons. [[TSDatabaseView threadSpecialMessagesDatabaseView:transaction] enumerateRowsInGroup:thread.uniqueId @@ -196,6 +186,7 @@ NS_ASSUME_NONNULL_BEGIN } } + __block TSMessage *firstMessage = nil; [[transaction ext:TSMessageDatabaseViewExtensionName] enumerateRowsInGroup:thread.uniqueId usingBlock:^( @@ -210,9 +201,9 @@ NS_ASSUME_NONNULL_BEGIN } }]; - outgoingMessageCount = + NSUInteger outgoingMessageCount = [[TSDatabaseView threadOutgoingMessageDatabaseView:transaction] numberOfItemsInGroup:thread.uniqueId]; - threadMessageCount = + NSUInteger threadMessageCount = [[transaction ext:TSMessageDatabaseViewExtensionName] numberOfItemsInGroup:thread.uniqueId]; // Enumerate in reverse to count the number of messages @@ -221,6 +212,9 @@ NS_ASSUME_NONNULL_BEGIN // the messages view the position of the unread indicator, // so that it can widen its "load window" to always show // the unread indicator. + __block long visibleUnseenMessageCount = 0; + __block TSInteraction *interactionAfterUnreadIndicator = nil; + NSUInteger missingUnseenSafetyNumberChangeCount = 0; if (result.firstUnseenInteractionTimestamp != nil) { [[transaction ext:TSMessageDatabaseViewExtensionName] enumerateRowsInGroup:thread.uniqueId @@ -294,9 +288,7 @@ NS_ASSUME_NONNULL_BEGIN result.unreadIndicatorPosition = @(visibleUnseenMessageCount); } OWSAssert((result.firstUnseenInteractionTimestamp != nil) == (result.unreadIndicatorPosition != nil)); - }]; - [writeDBConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { BOOL shouldHaveBlockOffer = YES; BOOL shouldHaveAddToContactsOffer = YES;