samedi 26 juillet 2014

iOS - déterminer quand il ya des nouvelles versions dans le modèle de données de base - Stack Overflow


Short question:


I want to run a certain code in my app only if my Core Data model has changed (new entities, new properties, etc). How can I determine if the model has changed or not?


Just some pseudo-code:


    if (current_model_version != previous_model_version) {
//do some code
} else {
// do some other code
}

I'm guessing I might use versionHashes to do this, or isConfiguration:compatibleWithStoreMetadata:, but I'm not certain how.


Some editing for clarity: 'current' as in 'now' and 'previous' as in 'last time app was launched.'




The answer seems to be isConfiguration:compatibleWithStoreMedia:.


I found some useful information here:


http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2


I set it up this way:


- (BOOL)modelChanged
{
NSError *error;
NSURL * sourceURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"db.sqlite"];
NSString *sourcePath = [sourceURL absoluteString];
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sourceURL error:&error];
BOOL isCompatible = [[self managedObjectModel] isConfiguration:sourcePath compatibleWithStoreMetadata:sourceMetadata];

return isCompatible;

}

'self' is my shared data store, not that it necessarily has to go there.


deanWombourne points out that what this really does is determine whether or not the data can be automatically migrated, so it's not exactly the solution to the problem I posed. It does serve my needs in this case.




This is replacement code for - (NSPersistentStoreCoordinator *)persistentStoreCoordinator that you get if you tick the Core Data box when setting up a new project in XCode.


It attempts to open the existing sqlite file (using lightweight migration if necessary). If that fails, it deletes and re-creates the store.


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

NSError *error = nil;

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Couldn't open the store. error %@, %@", error, [error userInfo]);

[self deleteSqliteFilesForStore:self.storeURL];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

// or [NSException raise ...]
}
else
{
NSLog(@"Store deleted and recreated");

// TEST DATA RE-INITIALIZATION CODE GOES HERE
}
}
else
{
NSLog(@"Existing Store opened successfully");
}

return _persistentStoreCoordinator;
}

- (void)deleteSqliteFilesForStore:(NSURL *)storeURL
{
NSURL *baseURL = [storeURL URLByDeletingPathExtension];

// Delete the associated files as well as the sqlite file

for (NSString *pathExtension in @[@"sqlite",@"sqlite-shm",@"sqlite-wal"])
{
NSURL *componentURL = [baseURL URLByAppendingPathExtension:pathExtension];

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[componentURL path]];
if(fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:[componentURL path] error:nil];
}
}
}


Short question:


I want to run a certain code in my app only if my Core Data model has changed (new entities, new properties, etc). How can I determine if the model has changed or not?


Just some pseudo-code:


    if (current_model_version != previous_model_version) {
//do some code
} else {
// do some other code
}

I'm guessing I might use versionHashes to do this, or isConfiguration:compatibleWithStoreMetadata:, but I'm not certain how.


Some editing for clarity: 'current' as in 'now' and 'previous' as in 'last time app was launched.'



The answer seems to be isConfiguration:compatibleWithStoreMedia:.


I found some useful information here:


http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2


I set it up this way:


- (BOOL)modelChanged
{
NSError *error;
NSURL * sourceURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"db.sqlite"];
NSString *sourcePath = [sourceURL absoluteString];
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:sourceURL error:&error];
BOOL isCompatible = [[self managedObjectModel] isConfiguration:sourcePath compatibleWithStoreMetadata:sourceMetadata];

return isCompatible;

}

'self' is my shared data store, not that it necessarily has to go there.


deanWombourne points out that what this really does is determine whether or not the data can be automatically migrated, so it's not exactly the solution to the problem I posed. It does serve my needs in this case.



This is replacement code for - (NSPersistentStoreCoordinator *)persistentStoreCoordinator that you get if you tick the Core Data box when setting up a new project in XCode.


It attempts to open the existing sqlite file (using lightweight migration if necessary). If that fails, it deletes and re-creates the store.


- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}

_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

NSError *error = nil;

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Couldn't open the store. error %@, %@", error, [error userInfo]);

[self deleteSqliteFilesForStore:self.storeURL];

if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:self.storeURL options:options error:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

// or [NSException raise ...]
}
else
{
NSLog(@"Store deleted and recreated");

// TEST DATA RE-INITIALIZATION CODE GOES HERE
}
}
else
{
NSLog(@"Existing Store opened successfully");
}

return _persistentStoreCoordinator;
}

- (void)deleteSqliteFilesForStore:(NSURL *)storeURL
{
NSURL *baseURL = [storeURL URLByDeletingPathExtension];

// Delete the associated files as well as the sqlite file

for (NSString *pathExtension in @[@"sqlite",@"sqlite-shm",@"sqlite-wal"])
{
NSURL *componentURL = [baseURL URLByAppendingPathExtension:pathExtension];

BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[componentURL path]];
if(fileExists)
{
[[NSFileManager defaultManager] removeItemAtPath:[componentURL path] error:nil];
}
}
}

0 commentaires:

Enregistrer un commentaire