2
0

Safer migration, boolean description fix.

[ADDED]     Safer store migration: don't delete the old store, allowing the client to downgrade.
[ADDED]     Log checkpoints and send to TestFlight too.
[FIXED]     Describe booleans as YES/NO, not 1/0.
This commit is contained in:
Maarten Billemont 2013-05-02 11:19:34 -04:00
parent 5e1e88bdeb
commit ab15694d9a
4 changed files with 61 additions and 40 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit b889e6312d5ecd9d2e45eb1402cadc6e27ed84c4 Subproject commit 720acb2e6583a2ed9efbbe28ab53681a19070a42

View File

@ -15,6 +15,20 @@
#define STORE_OPTIONS #define STORE_OPTIONS
#endif #endif
#define MPMigrationLevelLocalStoreKey @"MPMigrationLevelLocalStoreKey"
typedef enum {
MPMigrationLevelLocalStoreV13,
MPMigrationLevelLocalStoreV14,
MPMigrationLevelLocalStoreCurrent = MPMigrationLevelLocalStoreV14,
} MPMigrationLevelLocalStore;
#define MPMigrationLevelCloudStoreKey @"MPMigrationLevelCloudStoreKey"
typedef enum {
MPMigrationLevelCloudStoreV13,
MPMigrationLevelCloudStoreV14,
MPMigrationLevelCloudStoreCurrent = MPMigrationLevelCloudStoreV14,
} MPMigrationLevelCloudStore;
@implementation MPAppDelegate_Shared(Store) @implementation MPAppDelegate_Shared(Store)
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert); PearlAssociatedObjectProperty(PearlAlert*, HandleCloudContentAlert, handleCloudContentAlert);
@ -98,18 +112,18 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification
object:[UIApplication sharedApplication] queue:nil object:[UIApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; [[self mainManagedObjectContext] saveToStore];
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillResignActiveNotification
object:[UIApplication sharedApplication] queue:nil object:[UIApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; [[self mainManagedObjectContext] saveToStore];
}]; }];
#else #else
[[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification
object:[NSApplication sharedApplication] queue:nil object:[NSApplication sharedApplication] queue:nil
usingBlock:^(NSNotification *note) { usingBlock:^(NSNotification *note) {
[self saveContexts]; [[self mainManagedObjectContext] saveToStore];
}]; }];
#endif #endif
@ -126,6 +140,11 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
- (void)migrateLocalStoreForManager:(UbiquityStoreManager *)manager { - (void)migrateLocalStoreForManager:(UbiquityStoreManager *)manager {
MPMigrationLevelLocalStore migrationLevel = [[NSUserDefaults standardUserDefaults] integerForKey:@"MPMigrationLevelLocalStore"];
if (migrationLevel >= MPMigrationLevelLocalStoreCurrent)
// Local store up-to-date.
return;
NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager] NSURL *applicationFilesDirectory = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *oldLocalStoreURL = [[applicationFilesDirectory NSURL *oldLocalStoreURL = [[applicationFilesDirectory
@ -137,10 +156,12 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
} }
if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NO]) { if (![[NSFileManager defaultManager] fileExistsAtPath:oldLocalStoreURL.path isDirectory:NO]) {
// No local store to migrate. // No local store to migrate.
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey];
return; return;
} }
if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) { if ([[NSFileManager defaultManager] fileExistsAtPath:newLocalStoreURL.path isDirectory:NO]) {
wrn(@"Can't migrate old local store: A new local store already exists."); wrn(@"Can't migrate old local store: A new local store already exists.");
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey];
return; return;
} }
@ -172,11 +193,17 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
return; return;
} }
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelLocalStoreCurrent forKey:MPMigrationLevelLocalStoreKey];
inf(@"Successfully migrated old to new local store."); inf(@"Successfully migrated old to new local store.");
} }
- (void)migrateCloudStoreForManager:(UbiquityStoreManager *)manager { - (void)migrateCloudStoreForManager:(UbiquityStoreManager *)manager {
MPMigrationLevelCloudStore migrationLevel = [[NSUserDefaults standardUserDefaults] integerForKey:@"MPMigrationLevelCloudStore"];
if (migrationLevel >= MPMigrationLevelCloudStoreCurrent)
// Cloud store up-to-date.
return;
// Migrate cloud enabled preference. // Migrate cloud enabled preference.
NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"]; NSNumber *oldCloudEnabled = [[NSUserDefaults standardUserDefaults] objectForKey:@"iCloudEnabledKey"];
if ([oldCloudEnabled boolValue]) { if ([oldCloudEnabled boolValue]) {
@ -186,12 +213,15 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
// Migrate cloud store. // Migrate cloud store.
NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"]; NSString *uuid = [[NSUserDefaults standardUserDefaults] stringForKey:@"LocalUUIDKey"];
if (!uuid) if (!uuid) {
// No old cloud store to migrate. // No old cloud store to migrate.
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey];
return; return;
}
if (![manager cloudSafeForSeeding]) { if (![manager cloudSafeForSeeding]) {
wrn(@"Can't migrate old cloud store: A new cloud store already exists."); wrn(@"Can't migrate old cloud store: A new cloud store already exists.");
[[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey];
return; return;
} }
@ -244,27 +274,10 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
error:nil cause:nil context:nil]) error:nil cause:nil context:nil])
return; return;
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LocalUUIDKey"]; [[NSUserDefaults standardUserDefaults] setInteger:MPMigrationLevelCloudStoreCurrent forKey:MPMigrationLevelCloudStoreKey];
inf(@"Successfully migrated old to new cloud store."); inf(@"Successfully migrated old to new cloud store.");
} }
- (void)saveContexts {
NSManagedObjectContext *mainManagedObjectContext = self.mainManagedObjectContext;
[mainManagedObjectContext performBlockAndWait:^{
NSError *error = nil;
if (![mainManagedObjectContext save:&error])
err(@"While saving main context: %@", error);
}];
NSManagedObjectContext *privateManagedObjectContext = [self privateManagedObjectContextIfReady];
[privateManagedObjectContext performBlockAndWait:^{
NSError *error = nil;
if (![privateManagedObjectContext save:&error])
err(@"While saving private context: %@", error);
}];
}
#pragma mark - UbiquityStoreManagerDelegate #pragma mark - UbiquityStoreManagerDelegate
- (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm { - (NSManagedObjectContext *)managedObjectContextForUbiquityStoreManager:(UbiquityStoreManager *)usm {
@ -301,8 +314,7 @@ PearlAssociatedObjectProperty(NSManagedObjectContext*, MainManagedObjectContext,
} ); } );
// Create our contexts. // Create our contexts.
NSManagedObjectContext NSManagedObjectContext *privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
*privateManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[privateManagedObjectContext performBlockAndWait:^{ [privateManagedObjectContext performBlockAndWait:^{
privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy; privateManagedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy;
privateManagedObjectContext.persistentStoreCoordinator = coordinator; privateManagedObjectContext.persistentStoreCoordinator = coordinator;

View File

@ -68,7 +68,7 @@ typedef enum {
#define MPCheckpointApps @"MPCheckpointApps" #define MPCheckpointApps @"MPCheckpointApps"
#define MPCheckpointApp @"MPCheckpointApp" #define MPCheckpointApp @"MPCheckpointApp"
#define MPCheckpointEmergencyGenerator @"MPCheckpointEmergencyGenerator" #define MPCheckpointEmergencyGenerator @"MPCheckpointEmergencyGenerator"
#define MPCheckpointLogs @"MPCheckpointLogs" #define MPCheckpointLogs @"MPCheckpointLogs"
#define MPSignedInNotification @"MPSignedInNotification" #define MPSignedInNotification @"MPSignedInNotification"
#define MPSignedOutNotification @"MPSignedOutNotification" #define MPSignedOutNotification @"MPSignedOutNotification"
@ -78,7 +78,11 @@ typedef enum {
static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) { static void MPCheckpoint(NSString *checkpoint, NSDictionary *attributes) {
inf(@"%@: %@", checkpoint, attributes);
#ifdef LOCALYTICS #ifdef LOCALYTICS
[[LocalyticsSession sharedLocalyticsSession] tagEvent:checkpoint attributes:attributes]; [[LocalyticsSession sharedLocalyticsSession] tagEvent:checkpoint attributes:attributes];
#endif #endif
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:checkpoint];
#endif
} }

View File

@ -202,23 +202,28 @@
[[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; [[Crashlytics sharedInstance] setObjectValue:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"];
#ifdef TESTFLIGHT_SDK_VERSION #ifdef TESTFLIGHT_SDK_VERSION
[TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].rememberLogin boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].rememberLogin)
forKey:@"rememberLogin"]; forKey:@"rememberLogin"];
[TestFlight addCustomEnvironmentInformation:[@([self storeManager].cloudEnabled) description] forKey:@"iCloud"]; [TestFlight addCustomEnvironmentInformation:PearlStringB([self storeManager].cloudEnabled)
[TestFlight addCustomEnvironmentInformation:[@([[MPConfig get].iCloudDecided boolValue]) description] forKey:@"iCloud"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPConfig get].iCloudDecided)
forKey:@"iCloudDecided"]; forKey:@"iCloudDecided"];
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].sendInfo boolValue]) description] forKey:@"sendInfo"]; [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].sendInfo)
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].helpHidden boolValue]) description] forKey:@"sendInfo"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].helpHidden)
forKey:@"helpHidden"]; forKey:@"helpHidden"];
[TestFlight addCustomEnvironmentInformation:[@([[MPiOSConfig get].showSetup boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([MPiOSConfig get].showSetup)
forKey:@"showQuickStart"]; forKey:@"showQuickStart"];
[TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].firstRun boolValue]) description] forKey:@"firstRun"]; [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].firstRun)
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].launchCount description] forKey:@"launchCount"]; forKey:@"firstRun"];
[TestFlight addCustomEnvironmentInformation:[@([[PearlConfig get].askForReviews boolValue]) description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].launchCount)
forKey:@"launchCount"];
[TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].askForReviews)
forKey:@"askForReviews"]; forKey:@"askForReviews"];
[TestFlight addCustomEnvironmentInformation:[[PearlConfig get].reviewAfterLaunches description] [TestFlight addCustomEnvironmentInformation:PearlStringNSB([PearlConfig get].reviewAfterLaunches)
forKey:@"reviewAfterLaunches"]; forKey:@"reviewAfterLaunches"];
[TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion forKey:@"reviewedVersion"]; [TestFlight addCustomEnvironmentInformation:[PearlConfig get].reviewedVersion
forKey:@"reviewedVersion"];
#endif #endif
MPCheckpoint( MPCheckpointConfig, @{ MPCheckpoint( MPCheckpointConfig, @{
@"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]), @"rememberLogin" : @([[MPConfig get].rememberLogin boolValue]),
@ -228,9 +233,9 @@
@"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]), @"helpHidden" : @([[MPiOSConfig get].helpHidden boolValue]),
@"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]), @"showQuickStart" : @([[MPiOSConfig get].showSetup boolValue]),
@"firstRun" : @([[PearlConfig get].firstRun boolValue]), @"firstRun" : @([[PearlConfig get].firstRun boolValue]),
@"launchCount" : NilToNSNull([[PearlConfig get].launchCount description]), @"launchCount" : NilToNSNull([PearlConfig get].launchCount),
@"askForReviews" : @([[PearlConfig get].askForReviews boolValue]), @"askForReviews" : @([[PearlConfig get].askForReviews boolValue]),
@"reviewAfterLaunches" : NilToNSNull([[PearlConfig get].reviewAfterLaunches description]), @"reviewAfterLaunches" : NilToNSNull([PearlConfig get].reviewAfterLaunches),
@"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion) @"reviewedVersion" : NilToNSNull([PearlConfig get].reviewedVersion)
} ); } );
} }