Anybody knows how to get the core-data model version when the app starts?
I've implemented the lightweight migration and it works fine but I need to check if the sqlite db is based to the old model version before the migration process starts.
In the new model I added a new entity but I need to populate it with value of an entity of the old model. I want to do that only one time.
Is there a way to do it in the appdelegate?
Thanks,
Max
I solved this by setting the DB-version in my preferences (.plist). So if I change the DB, I set the new DB-version in there and store the version from the last start in the NSUserDefaults.
NSNumber *newDbVersion = [[[NSBundle mainBundle] infoDictionary] objectForKey:#"DBVersion"];
NSNumber *oldDbVersion = [[NSUserDefaults standardUserDefaults] objectForKey:#"DBVersion"];
if (oldDbVersion == nil)
{
// part without handling, so you know the max db version.
}else
{
if([oldDbVersion intValue] < [newDbVersion intValue])
{
// try the liteweight migration and if that failed, migrate by hand
}
}
Related
We are using Amazon Ubuntu Server, Apache and PHP Installed Openfire of version 4.0.1 and the app configurations are XCode 7.2 by using Swift and library we are using is XMPP Framework of version 3.6.6.
We can able do single text chat, but cannot store chat history - How can we maintain chat history and retrieve that.
Create a XCMODEL schema file of core data in your project
Add your entities in that model.
That can be in your case
MESSAGE entity
CONTACT entity
etc (whatever you want to save )
For each entity in your DB model, you can now add "Attributes" in your Entity (say MESSAGE entity). Attributes can be created time, message text etc.
Make a NSObject extended class which have properties same as your attributes
.h file
#property (nonatomic, retain) NSNumber * createdAt;
.m file
#dynamic createdAt;
Now you can use : Core data operation methods like saving NS managed object etc to save or other operation on DB.
For Example : to save a contact in your DB with full name attribute.
DBHandler * dbHandler = [DBHandler sharedInstance];
DB_CONTACT* existingContact = [self getContactByKey:#"userId" value:[userContact userId]];
if (existingContact) {
return false;
}
BOOL result = NO;
DB_CONTACT * contact =
[NSEntityDescription
insertNewObjectForEntityForName:#"DB_CONTACT"
inManagedObjectContext:dbHandler.managedObjectContext];
contact.fullName = userContact.fullName;
NSError *error = nil;
result = [dbHandler.managedObjectContext save:&error];
if (!result) {
NSLog(#"DB ERROR :%#",error);
}
return result;
Method responsible to save in DB:
[NSEntityDescription
insertNewObjectForEntityForName:#"DB_CONTACT"
inManagedObjectContext:dbHandler.managedObjectContext];
Hope this gives you an idea. For more details check https://github.com/AppLozic/Applozic-iOS-SDK out as sample app for messaging.
If you want to maintain chat local history, you can use coredata to save all incoming and send messages on the right order.
To restore the chat history, use parameters like XMPPUserName (from and to) from your coredata.
To see the history on a openfire server, you can:
Install the Monitoring Server plugin
Go to the tab “Archiving”
Select their settings and enable "Archive one-to-one chats”
I have an already published app that use core data.
Now I want to add support for watch kit and today extension.
I need to move core data into shared container without lose previous user saved data, how can I do that in the best way?
You can migrate a Core Data Stack. A fuller answer can be found here, but the short version is:
Check if the old non-group copy of the data exists
If it does, set up a Core Data stack using that file. Then use migratePersistentStore:toURL:options:withType:error: to move it to the new location. Then remove the old copy.
If the old version doesn't exist, just set up Core Data with the new copy as usual.
(The problem with Stephen's answer is that it assumes that the Core Data stack is a single SQLite file, which isn't always true.)
Here is how I moved core data to the shared container in my app. I do this when the app launches.
NSUserDefaults* sharedDefs = [GPMapCore sharedCore].sharedUserDefaults;
if (![sharedDefs boolForKey:#"CoreDataMovedToExtension"])
{
NSURL* oldLocation = GET_LOCATION_OF_CORE_DATA_SQLITE_FILE();
NSURL* newLocation = GET_LOCATON_TO_MOVE_THE_SQLITE_FILE_TO();
if ([[NSFileManager defaultManager] fileExistsAtPath:[oldLocation filePathString]])
{
//Check if a new file exists. This can happen when the watch app is run before
//Topo Maps+ runs and move the core data database
if ([[NSFileManager defaultManager] fileExistsAtPath:[newLocation filePathString]])
{
[[NSFileManager defaultManager ] removeItemAtURL:newLocation error:nil];
}
[[NSFileManager defaultManager] moveItemAtURL:oldLocation toURL:newLocation error:nil];
}
[sharedDefs setBool:YES forKey:#"CoreDataMovedToExtension"];
[sharedDefs synchronize];
}
this has beed discussed alot, but nothing that I found helped me... I just want to add a single attribute to a singe entity. Of cause without loosing my data.
To do that, I followed these steps
But I don't think it worked at all. There are no errors as long as not try to use the new attribute. But in my Core Data Model (when I open the .xcdatamodel in XCode) it's there and even in my NSManagedObject Subclass of the entity, the new attribute is there as a property. But when I try to use it, this happens:
unrecognized selector sent to instance 0x74f8520
or
the entity Name is not key value coding-compliant for the key "isFavoriteName".'
The key "isFavoriteName"is the one I just added.Like I said, I did all the steps. Do I miss something?
I think, that the new Model Version is not being used, because when I delete some attributes in the Model, my app still works and the deleted information are still shown... I have set the current Core Data Model Version the the new one (Step 6).
I hope you can help me!
Nick
EDIT: Do I may have to change something in code as well? Apart from the setting the options when creating persistentStoreCoordinator... Because I have, let's say myApp.xdatamodel and inside of that, i know have myApp.xdatamodel and myApp 2,xdatamodel... but I my code I sill do:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"mom"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
That's right-- the page you linked to left out one step that applies in your case. Even though you created a new version of the model, your code is still loading the old one by name.
Don't just change it to load version 2 though. Do this instead:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"myApp" withExtension:#"momd"];
This will look in the momd folder and get whatever the current version is. In this case it will get version 2. If you change the model again in the future, it will get whatever version is current then.
My app is on App Store and in its new version I have updated the schema, like number of columns has been changed and name of columns has been changed. But now when I uploaded the new version on App Store, the app is crashing.
I came to know that this is happening because I have changed the schema. I have use SQLite so is there any solution to this problem?
SQLite supports a 'version' when you open (or create) the DB. This is a unique value that you decide. When you change the schema you should change the 'version' string so that the old database is abandoned for a new one. In the same way you would handle creating the database on first setup, you must then also manually migrate any important data from the previous database to the new one.
Unfortunately there's no way to role back an app to the last good version, the best you can do is to remove your app from the store for a few days until you get a fix into place.
Try like this.
Check the version
If new then - if you want Fetch all data from old DB
and remove the old DB. else
no changes
Create new db
Insert data what get from old DB
NSString *dbPath = [documentsDirectory stringByAppendingPathComponent:dbName];
BOOL dbSuccess = [fileManager fileExistsAtPath:dbPath];
if (dbSuccess) {
NSDictionary *oldDetailsDict = [NSDictionary dictionaryWithContentsOfFile:writablePath];
if(![[oldDetailsDict valueForKey:#"version"] isEqualToString:Current_APP_VERSION]){
NSString *oldVersion = [oldDetailsDict valueForKey:#"version"];
if ([oldVersion isEqualToString:Current_APP_VERSION]) {
//no code change needed
}else{
//Get data from old db
//Data moved to array
NSArray *oldDataArray = [Product getDataFromDatabase];
//Remove the old Database
NSString *deletePath = [documentsDirectory stringByAppendingPathComponent:#"sample.sqlite"];
[fileManager removeItemAtPath:deletePath error:nil];
//Create the new DB for new version
[self createdatabase];
//Again Insert the old data to new db
for (Product *pro in oldDataArray) {
[pro insertToDB];
}
}
}
}
i want to take the backup of all the data in the database of my iphone app in dropbox and restore it later.here the main problem is there is too much data in the app so if i am using sql queries to fetch data from sqlite3 database and storing it into the file and again reading data from that file and inserting it to database.can anyone suggest that how can i improve that or what is the best way to do that?
I presume that you mean that you want to be able to restore the data after user has somehow deleted the application and re-installed it again. Since each application has its influence inside the bounds of its sandbox, the only sane option would be to use server. In regards to simply answering your question - there is no way to do it as you've described.
You can use iCloud.
Go to your app manager on Itunes Connect to generate a iCloud Key.
So, all data will be stored on icloud.
You can use too a uuid as Key for your webservice. So, if the use delete app and when he reinstall, you cad download all data with key identifier.
For example:
uuid = [[UIDevice currentDevice] uniqueGlobalDeviceIdentifier];
With Class for UUID
Important: Use the global mode because it allows to use the uuid between applications.
my dropbox-based Sync API solution:
- (IBAction)onTouchDropboxBackup:(id)sender {
DBAccount *account = [[DBAccountManager sharedManager] linkedAccount];
if (account) {
if (![sharedDelegate filesystem]) {
DBFilesystem *filesystem = [[DBFilesystem alloc] initWithAccount:account];
[DBFilesystem setSharedFilesystem:filesystem];
[sharedDelegate setFilesystem:filesystem];
[filesystem release];
}
DBPath *destination = [[DBPath root] childPath:kDataDBFileName];
DBError *error = nil;
//check presense
DBFile *file = [[DBFilesystem sharedFilesystem] openFile:destination
error:&error];
if (error){//not present
[[DBFilesystem sharedFilesystem] createFile:destination
error:&error];
file = [[DBFilesystem sharedFilesystem] openFile:destination
error:&error];
}
if (!error) {
[file writeContentsOfFile:[DOCUMENTS_DIR stringByAppendingPathComponent: kDataDBFileName]
shouldSteal:NO
error:&error];
[file update:&error];
[file close];
}
}else
[[DBAccountManager sharedManager] linkFromController:self];
}