Fixed a few crashes.
[UPDATED] A nil type is never OK. Crash early if it is so. [UPDATED] Set crashlytics identifiers using its userIdentifier and userName property for good metadata. [FIXED] Make sure the MOC has a PSC with stores when returning it. [FIXED] Don't reset the store for just any open error! Only if it's actually incompatible. [IMPROVED] Remove timestamps from Crashlytics and TestFlight logs, they already provide them. [FIXED] Avoid crashes in some odd cases where there's no type set.
This commit is contained in:
parent
7921734740
commit
b9ccee398e
2
External/iCloudStoreManager
vendored
2
External/iCloudStoreManager
vendored
@ -1 +1 @@
|
|||||||
Subproject commit a7b028ff80cd4768be686a9ef2067dfd31989ce0
|
Subproject commit 8c7894a983f1c1e0795a6e3d5ee7a223a5e01a54
|
@ -153,7 +153,7 @@
|
|||||||
- (Class)classOfType:(MPElementType)type {
|
- (Class)classOfType:(MPElementType)type {
|
||||||
|
|
||||||
if (!type)
|
if (!type)
|
||||||
return nil;
|
Throw(@"No type given.");
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case MPElementTypeGeneratedMaximum:
|
case MPElementTypeGeneratedMaximum:
|
||||||
|
@ -148,7 +148,8 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
|
|||||||
@try {
|
@try {
|
||||||
if ([[MPiOSConfig get].sendInfo boolValue]) {
|
if ([[MPiOSConfig get].sendInfo boolValue]) {
|
||||||
[TestFlight addCustomEnvironmentInformation:user.userID forKey:@"username"];
|
[TestFlight addCustomEnvironmentInformation:user.userID forKey:@"username"];
|
||||||
[[Crashlytics sharedInstance] setObjectValue:user.userID forKey:@"username"];
|
[Crashlytics setObjectValue:user.userID forKey:@"username"];
|
||||||
|
[Crashlytics setUserName:user.userID];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@catch (id exception) {
|
@catch (id exception) {
|
||||||
|
@ -29,8 +29,7 @@
|
|||||||
if (managedObjectModel)
|
if (managedObjectModel)
|
||||||
return managedObjectModel;
|
return managedObjectModel;
|
||||||
|
|
||||||
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MasterPassword" withExtension:@"momd"];
|
return managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
|
||||||
return managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSManagedObjectContext *)managedObjectContextIfReady {
|
- (NSManagedObjectContext *)managedObjectContextIfReady {
|
||||||
@ -39,15 +38,21 @@
|
|||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
static NSManagedObjectContext *managedObjectContext = nil;
|
static NSManagedObjectContext *managedObjectContext = nil;
|
||||||
if (managedObjectContext)
|
if (!managedObjectContext) {
|
||||||
return managedObjectContext;
|
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
||||||
|
[managedObjectContext performBlockAndWait:^{
|
||||||
|
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
||||||
|
managedObjectContext.undoManager = [NSUndoManager new];
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
|
if (![managedObjectContext.persistentStoreCoordinator.persistentStores count])
|
||||||
[managedObjectContext performBlockAndWait:^{
|
[managedObjectContext performBlockAndWait:^{
|
||||||
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
|
managedObjectContext.persistentStoreCoordinator = [self storeManager].persistentStoreCoordinator;
|
||||||
managedObjectContext.persistentStoreCoordinator = [self storeManager].persistentStoreCoordinator;
|
}];
|
||||||
managedObjectContext.undoManager = [NSUndoManager new];
|
|
||||||
}];
|
if (![self storeManager].isReady)
|
||||||
|
return nil;
|
||||||
|
|
||||||
return managedObjectContext;
|
return managedObjectContext;
|
||||||
}
|
}
|
||||||
@ -62,7 +67,9 @@
|
|||||||
localStoreURL:[[self applicationFilesDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"]
|
localStoreURL:[[self applicationFilesDirectory] URLByAppendingPathComponent:@"MasterPassword.sqlite"]
|
||||||
containerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared"
|
containerIdentifier:@"HL3Q45LX9N.com.lyndir.lhunath.MasterPassword.shared"
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
additionalStoreOptions:@{NSPersistentStoreFileProtectionKey: NSFileProtectionComplete}
|
additionalStoreOptions:@{
|
||||||
|
NSPersistentStoreFileProtectionKey: NSFileProtectionComplete
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
additionalStoreOptions:nil
|
additionalStoreOptions:nil
|
||||||
#endif
|
#endif
|
||||||
@ -132,8 +139,9 @@
|
|||||||
#ifdef TESTFLIGHT_SDK_VERSION
|
#ifdef TESTFLIGHT_SDK_VERSION
|
||||||
[TestFlight passCheckpoint:iCloudEnabled? MPCheckpointCloudEnabled: MPCheckpointCloudDisabled];
|
[TestFlight passCheckpoint:iCloudEnabled? MPCheckpointCloudEnabled: MPCheckpointCloudDisabled];
|
||||||
#endif
|
#endif
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloud
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloud attributes:@{
|
||||||
attributes:@{@"enabled": iCloudEnabled? @"YES": @"NO"}];
|
@"enabled": iCloudEnabled? @"YES": @"NO"
|
||||||
|
}];
|
||||||
|
|
||||||
[MPConfig get].iCloud = @(iCloudEnabled);
|
[MPConfig get].iCloud = @(iCloudEnabled);
|
||||||
}
|
}
|
||||||
@ -154,27 +162,39 @@
|
|||||||
case UbiquityStoreManagerErrorCauseClearStore:
|
case UbiquityStoreManagerErrorCauseClearStore:
|
||||||
break;
|
break;
|
||||||
case UbiquityStoreManagerErrorCauseOpenLocalStore: {
|
case UbiquityStoreManagerErrorCauseOpenLocalStore: {
|
||||||
wrn(@"Local store could not be opened, resetting it.");
|
wrn(@"Local store could not be opened: %@", error);
|
||||||
|
|
||||||
|
if (error.code == NSMigrationMissingSourceModelError) {
|
||||||
|
wrn(@"Resetting the local store.");
|
||||||
|
|
||||||
#ifdef TESTFLIGHT_SDK_VERSION
|
#ifdef TESTFLIGHT_SDK_VERSION
|
||||||
[TestFlight passCheckpoint:MPCheckpointLocalStoreIncompatible];
|
[TestFlight passCheckpoint:MPCheckpointLocalStoreIncompatible];
|
||||||
#endif
|
#endif
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointLocalStoreIncompatible attributes:nil];
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointLocalStoreIncompatible attributes:nil];
|
||||||
manager.hardResetEnabled = YES;
|
manager.hardResetEnabled = YES;
|
||||||
[manager hardResetLocalStorage];
|
[manager hardResetLocalStorage];
|
||||||
|
|
||||||
Throw(@"Local store was reset, application must be restarted to use it.");
|
Throw(@"Local store was reset, application must be restarted to use it.");
|
||||||
|
} else
|
||||||
|
// Try again.
|
||||||
|
[self storeManager].persistentStoreCoordinator;
|
||||||
}
|
}
|
||||||
case UbiquityStoreManagerErrorCauseOpenCloudStore: {
|
case UbiquityStoreManagerErrorCauseOpenCloudStore: {
|
||||||
wrn(@"iCloud store could not be opened, resetting it.");
|
wrn(@"iCloud store could not be opened: %@", error);
|
||||||
|
|
||||||
|
if (error.code == NSMigrationMissingSourceModelError) {
|
||||||
|
wrn(@"Resetting the iCloud store.");
|
||||||
|
|
||||||
#ifdef TESTFLIGHT_SDK_VERSION
|
#ifdef TESTFLIGHT_SDK_VERSION
|
||||||
[TestFlight passCheckpoint:MPCheckpointCloudStoreIncompatible];
|
[TestFlight passCheckpoint:MPCheckpointCloudStoreIncompatible];
|
||||||
#endif
|
#endif
|
||||||
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloudStoreIncompatible attributes:nil];
|
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloudStoreIncompatible attributes:nil];
|
||||||
manager.hardResetEnabled = YES;
|
manager.hardResetEnabled = YES;
|
||||||
[manager hardResetCloudStorage];
|
[manager hardResetCloudStorage];
|
||||||
break;
|
break;
|
||||||
|
} else
|
||||||
|
// Try again.
|
||||||
|
[self storeManager].persistentStoreCoordinator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -366,8 +386,9 @@
|
|||||||
// Create new site.
|
// Create new site.
|
||||||
__block MPImportResult result = MPImportResultSuccess;
|
__block MPImportResult result = MPImportResultSuccess;
|
||||||
[self.managedObjectContextIfReady performBlockAndWait:^{
|
[self.managedObjectContextIfReady performBlockAndWait:^{
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion(version) classNameOfType:type]
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmForVersion(
|
||||||
inManagedObjectContext:self.managedObjectContextIfReady];
|
version) classNameOfType:type]
|
||||||
|
inManagedObjectContext:self.managedObjectContextIfReady];
|
||||||
element.name = name;
|
element.name = name;
|
||||||
element.user = user;
|
element.user = user;
|
||||||
element.type = type;
|
element.type = type;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1487" systemVersion="12A269" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1807" systemVersion="12A269" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||||
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
|
<entity name="MPElementEntity" representedClassName="MPElementEntity" isAbstract="YES" syncable="YES">
|
||||||
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
|
<attribute name="content" optional="YES" transient="YES" attributeType="Transformable" syncable="YES"/>
|
||||||
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
|
<attribute name="lastUsed" attributeType="Date" indexed="YES" syncable="YES"/>
|
||||||
@ -32,9 +32,9 @@
|
|||||||
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
<relationship name="elements" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="MPElementEntity" inverseName="user" inverseEntity="MPElementEntity" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="MPElementEntity" positionX="160" positionY="192" width="128" height="180"/>
|
<element name="MPElementEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPElementGeneratedEntity" positionX="160" positionY="192" width="128" height="60"/>
|
<element name="MPElementGeneratedEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPElementStoredEntity" positionX="160" positionY="192" width="128" height="60"/>
|
<element name="MPElementStoredEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
<element name="MPUserEntity" positionX="160" positionY="192" width="128" height="150"/>
|
<element name="MPUserEntity" positionX="0" positionY="0" width="0" height="0"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
@ -54,9 +54,10 @@
|
|||||||
NSString *testFlightToken = [self testFlightToken];
|
NSString *testFlightToken = [self testFlightToken];
|
||||||
if ([testFlightToken length]) {
|
if ([testFlightToken length]) {
|
||||||
inf(@"Initializing TestFlight");
|
inf(@"Initializing TestFlight");
|
||||||
[TestFlight addCustomEnvironmentInformation:@"Anonymous" forKey:@"username"];
|
|
||||||
[TestFlight setDeviceIdentifier:[(id)[UIDevice currentDevice] uniqueIdentifier]];
|
[TestFlight setDeviceIdentifier:[(id)[UIDevice currentDevice] uniqueIdentifier]];
|
||||||
// [TestFlight setDeviceIdentifier:[PearlKeyChain deviceIdentifier]];
|
//[TestFlight setDeviceIdentifier[PearlKeyChain deviceIdentifier]];
|
||||||
|
[TestFlight addCustomEnvironmentInformation:@"Anonymous" forKey:@"username"];
|
||||||
|
[TestFlight addCustomEnvironmentInformation:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
|
||||||
[TestFlight setOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
[TestFlight setOptions:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||||
[NSNumber numberWithBool:NO], @"logToConsole",
|
[NSNumber numberWithBool:NO], @"logToConsole",
|
||||||
[NSNumber numberWithBool:NO], @"logToSTDERR",
|
[NSNumber numberWithBool:NO], @"logToSTDERR",
|
||||||
@ -68,7 +69,7 @@
|
|||||||
level = PearlLogLevelInfo;
|
level = PearlLogLevelInfo;
|
||||||
|
|
||||||
if (message.level >= level)
|
if (message.level >= level)
|
||||||
TFLog(@"%@", message);
|
TFLog(@"%@", [message messageDescription]);
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
@ -87,16 +88,18 @@
|
|||||||
#if defined (DEBUG) || defined (ADHOC)
|
#if defined (DEBUG) || defined (ADHOC)
|
||||||
[Crashlytics sharedInstance].debugMode = YES;
|
[Crashlytics sharedInstance].debugMode = YES;
|
||||||
#endif
|
#endif
|
||||||
[[Crashlytics sharedInstance] setObjectValue:@"Anonymous" forKey:@"username"];
|
[Crashlytics setUserIdentifier:[PearlKeyChain deviceIdentifier]];
|
||||||
[[Crashlytics sharedInstance] setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
|
[Crashlytics setObjectValue:[PearlKeyChain deviceIdentifier] forKey:@"deviceIdentifier"];
|
||||||
[Crashlytics startWithAPIKey:crashlyticsAPIKey afterDelay:0];
|
[Crashlytics setUserName:@"Anonymous"];
|
||||||
|
[Crashlytics setObjectValue:@"Anonymous" forKey:@"username"];
|
||||||
|
[Crashlytics startWithAPIKey:crashlyticsAPIKey];
|
||||||
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
[[PearlLogger get] registerListener:^BOOL(PearlLogMessage *message) {
|
||||||
PearlLogLevel level = PearlLogLevelWarn;
|
PearlLogLevel level = PearlLogLevelWarn;
|
||||||
if ([[MPiOSConfig get].sendInfo boolValue])
|
if ([[MPiOSConfig get].sendInfo boolValue])
|
||||||
level = PearlLogLevelInfo;
|
level = PearlLogLevelInfo;
|
||||||
|
|
||||||
if (message.level >= level)
|
if (message.level >= level)
|
||||||
CLSLog(@"%@", message);
|
CLSLog(@"%@", [message messageDescription]);
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}];
|
}];
|
||||||
|
@ -357,6 +357,11 @@
|
|||||||
|
|
||||||
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
[self.fetchedResultsController.managedObjectContext performBlock:^{
|
||||||
MPElementType type = [MPAppDelegate get].activeUser.defaultType;
|
MPElementType type = [MPAppDelegate get].activeUser.defaultType;
|
||||||
|
if (!type) {
|
||||||
|
// Really shouldn't happen, but a few people crashed on this anyway. Uhh. Data store corruption? Old bugs?
|
||||||
|
type = [MPAppDelegate get].activeUser.defaultType = MPElementTypeGeneratedLong;
|
||||||
|
}
|
||||||
|
|
||||||
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmDefault classNameOfType:type]
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:[MPAlgorithmDefault classNameOfType:type]
|
||||||
inManagedObjectContext:self.fetchedResultsController.managedObjectContext];
|
inManagedObjectContext:self.fetchedResultsController.managedObjectContext];
|
||||||
assert([MPAppDelegate get].activeUser);
|
assert([MPAppDelegate get].activeUser);
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
|||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>FooterText</key>
|
<key>FooterText</key>
|
||||||
<string>If you're experiencing problems, enabling this will send us details that can help diagnose and resolve them. Great care has been taken to guarantee no private information is ever sent.</string>
|
<string>If you're experiencing problems, enabling this will send us details that can help diagnose and resolve them. You will remain completely anonymous amongst the other thousands of users. No sensitive information is ever sent.</string>
|
||||||
<key>Title</key>
|
<key>Title</key>
|
||||||
<string></string>
|
<string></string>
|
||||||
<key>Type</key>
|
<key>Type</key>
|
||||||
@ -48,7 +48,7 @@
|
|||||||
<key>Title</key>
|
<key>Title</key>
|
||||||
<string>Send Diagnostic Info</string>
|
<string>Send Diagnostic Info</string>
|
||||||
<key>Key</key>
|
<key>Key</key>
|
||||||
<string>sendInfo</string>
|
<string>sendInfo</string>
|
||||||
<key>DefaultValue</key>
|
<key>DefaultValue</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
|
Loading…
Reference in New Issue
Block a user