Fix issues around cross process db changes.

pull/1/head
Matthew Chen 7 years ago
parent 0be63d2939
commit 0c9d9ba679

@ -295,7 +295,7 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
name:YapDatabaseModifiedNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
@ -2782,6 +2782,15 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
return _editingDatabaseConnection;
}
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[self resetMappings];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
@ -2794,6 +2803,8 @@ typedef NS_ENUM(NSInteger, MessagesRangeSizeMode) {
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

@ -111,7 +111,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
_blockedPhoneNumberSet = [NSSet setWithArray:[_blockingManager blockedPhoneNumbers]];
// Ensure ExperienceUpgradeFinder has been initialized.
ExperienceUpgradeFinder.sharedManager;
[ExperienceUpgradeFinder sharedManager];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(blockedPhoneNumbersDidChange:)
@ -138,7 +138,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
name:YapDatabaseModifiedNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:nil];
}
@ -923,12 +923,25 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
return _uiDatabaseConnection;
}
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[self resetMappings];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
if (!self.shouldObserveDBModifications) {
return;
}
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
if (![[self.uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] hasChangesForGroup:self.currentGrouping

@ -65,11 +65,11 @@ int const OWSLinkedDevicesTableViewControllerSectionAddDevice = 1;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:self.dbConnection.database];
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:self.dbConnection.database];
object:nil];
self.refreshControl = [UIRefreshControl new];
[self.refreshControl addTarget:self action:@selector(refreshDevices) forControlEvents:UIControlEventValueChanged];
@ -200,8 +200,29 @@ int const OWSLinkedDevicesTableViewControllerSectionAddDevice = 1;
#pragma mark - Table view data source
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
// External database modifications can't be converted into incremental updates,
// so rebuild everything. This is expensive and usually isn't necessary, but
// there's no alternative.
[self.dbConnection beginLongLivedReadTransaction];
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.deviceMappings updateWithTransaction:transaction];
}];
[self.tableView reloadData];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSArray *notifications = [self.dbConnection beginLongLivedReadTransaction];
[self setupEditButton];

@ -12,6 +12,75 @@ NS_ASSUME_NONNULL_BEGIN
@implementation MainAppContext
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Notifications
- (void)applicationWillEnterForeground:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[DDLog flushLog];
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[DDLog flushLog];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[DDLog flushLog];
}
#pragma mark -
- (BOOL)isMainApp
{
return YES;

@ -3,6 +3,7 @@
//
#import "ThreadViewHelper.h"
#import <SignalServiceKit/AppContext.h>
#import <SignalServiceKit/TSDatabaseView.h>
#import <SignalServiceKit/TSStorageManager.h>
#import <SignalServiceKit/TSThread.h>
@ -16,9 +17,12 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic) YapDatabaseViewMappings *threadMappings;
@property (nonatomic) BOOL shouldObserveDBModifications;
@end
#pragma mark -
@implementation ThreadViewHelper
- (instancetype)init
@ -48,49 +52,117 @@ NS_ASSUME_NONNULL_BEGIN
[[YapDatabaseViewMappings alloc] initWithGroups:@[ grouping ] view:TSThreadDatabaseViewExtensionName];
[self.threadMappings setIsReversed:YES forGroup:grouping];
__weak ThreadViewHelper *weakSelf = self;
[self.uiDatabaseConnection asyncReadWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.threadMappings updateWithTransaction:transaction];
self.uiDatabaseConnection = [TSStorageManager.sharedManager newDatabaseConnection];
[self.uiDatabaseConnection beginLongLivedReadTransaction];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf updateThreads];
[weakSelf.delegate threadListDidChange];
});
}];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
self.shouldObserveDBModifications
= !(CurrentAppContext().isMainApp && CurrentAppContext().mainApplicationState == UIApplicationStateBackground);
}
#pragma mark - Database
- (void)applicationWillEnterForeground:(NSNotification *)notification
{
self.shouldObserveDBModifications = YES;
}
- (YapDatabaseConnection *)uiDatabaseConnection
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
self.shouldObserveDBModifications = NO;
}
// Don't observe database change notifications when the app is in the background.
//
// Instead, rebuild model state when app enters foreground.
- (void)setShouldObserveDBModifications:(BOOL)shouldObserveDBModifications
{
NSAssert([NSThread isMainThread], @"Must access uiDatabaseConnection on main thread!");
if (!_uiDatabaseConnection) {
YapDatabase *database = TSStorageManager.sharedManager.database;
_uiDatabaseConnection = [database newConnection];
[_uiDatabaseConnection beginLongLivedReadTransaction];
if (_shouldObserveDBModifications == shouldObserveDBModifications) {
return;
}
_shouldObserveDBModifications = shouldObserveDBModifications;
if (shouldObserveDBModifications) {
[self.uiDatabaseConnection beginLongLivedReadTransaction];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.threadMappings updateWithTransaction:transaction];
}];
[self updateThreads];
[self.delegate threadListDidChange];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:database];
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:database];
object:nil];
} else {
[[NSNotificationCenter defaultCenter] removeObserver:self name:YapDatabaseModifiedNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:YapDatabaseModifiedExternallyNotification
object:nil];
}
}
#pragma mark - Database
- (YapDatabaseConnection *)uiDatabaseConnection
{
OWSAssert([NSThread isMainThread]);
return _uiDatabaseConnection;
}
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
// External database modifications can't be converted into incremental updates,
// so rebuild everything. This is expensive and usually isn't necessary, but
// there's no alternative.
[self.uiDatabaseConnection beginLongLivedReadTransaction];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.threadMappings updateWithTransaction:transaction];
}];
[self updateThreads];
[self.delegate threadListDidChange];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssert([NSThread isMainThread]);
DDLogVerbose(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NSArray *notifications = [self.uiDatabaseConnection beginLongLivedReadTransaction];
if (!
[[self.uiDatabaseConnection ext:TSMessageDatabaseViewExtensionName] hasChangesForNotifications:notifications]) {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.threadMappings updateWithTransaction:transaction];
}];
return;
}
NSArray *sectionChanges = nil;
NSArray *rowChanges = nil;
[[self.uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] getSectionChanges:&sectionChanges
rowChanges:&rowChanges
forNotifications:notifications
withMappings:self.threadMappings];
if (sectionChanges.count == 0 && rowChanges.count == 0) {
// Ignore irrelevant modifications.
return;

@ -345,18 +345,24 @@ public class ShareViewController: UINavigationController, ShareViewDelegate, SAE
// MARK: ShareViewDelegate, SAEFailedViewDelegate
public func shareViewWasCompleted() {
Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
public func shareViewWasCancelled() {
Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
public func shareViewFailed(error: Error) {
Logger.info("\(self.logTag) \(#function)")
self.dismiss(animated: true) {
self.extensionContext!.cancelRequest(withError: error)
}

@ -29,9 +29,57 @@ NS_ASSUME_NONNULL_BEGIN
_rootViewController = rootViewController;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(extensionHostDidBecomeActive:)
name:NSExtensionHostDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(extensionHostWillResignActive:)
name:NSExtensionHostWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(extensionHostDidEnterBackground:)
name:NSExtensionHostDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(extensionHostWillEnterForeground:)
name:NSExtensionHostWillEnterForegroundNotification
object:nil];
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Notifications
- (void)extensionHostDidBecomeActive:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
}
- (void)extensionHostWillResignActive:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[DDLog flushLog];
}
- (void)extensionHostDidEnterBackground:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
[DDLog flushLog];
}
- (void)extensionHostWillEnterForeground:(NSNotification *)notification
{
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
}
#pragma mark -
- (BOOL)isMainApp
{
return NO;

Loading…
Cancel
Save