Providing Initial Data with Core Data in iOS - ios

Here's what I need: To have a sqlite file populated with example entities that I made on the iPhone simulator, and then copy that file when the app initially runs for all my users.
What I've done:
I created a bunch of entries within the simulator.
I found the sqlite file attached to my app within the iPhone Simulator iOS folder on the MAC.
From the three files, .sqlite, .sqlite-shm, .sqlite-wal I simply copied the .sqlite file to my xCode project.
When I ran the app, the .sqlite file showed up empty!
How do I fix this?
Thank you!
EDIT:
What significance does the .sqlite-wal and .sqlite-shm have?
Why do they exist and why did not exist prior to iOS7?

first steps R OK but then U have to load the database
U need smth like this:
- (void)copyPreparedDatabase{
__persistentStoreCoordinator = nil;
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"DATABASE.sqlite"];
NSString *storePath = [storeURL path];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"DATABASE" ofType:#"sqlite"];
if (defaultStorePath) {
NSError *error = nil;
if ([fileManager fileExistsAtPath:storePath]) {
[fileManager removeItemAtPath:storePath error:&error];
}
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:&error];
NSDictionary *fileAttributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete forKey:NSFileProtectionKey];
if (![[NSFileManager defaultManager] setAttributes:fileAttributes ofItemAtPath:storePath error:&error]) {
}
}
}
And then U call it from - (NSPersistentStoreCoordinator *)persistentStoreCoordinator from
AppDelelate.m
Advice: Do some custom switch like
#define IMPORT_PREPARED_DATABASE
do it like this:
if (![fileManager fileExistsAtPath:storePath] && !IMPORT_PREPARED_DATABASE) { //&& 1==2
[self copyPreparedDatabase];
}
so U can control when to build new prepared database or when to use existing one....
Note:
When U build new prepared database sto simulator, copy database and paste it over the old one...

This tutorial can be a big help.
You made almost everything, but you are missing an important step. You need to copy the sqlite to your xcode project then you need to check in your persistentStoreCoordinator if the sqlite file exists in your Documents area. If not, you need to copy it. Jump to "Doctor, you’re needed in Xcode" section in that tutorial :).

Related

iOS Files in Application Support Directory or Documents Directory deleted after update

I have an iOS app where i copy a mp3 file from the bundle to a directory within Application Support Folder (Btw same thing happens if i use the Documents folder), and later user's download more mp3 files they are also stored there. Everything works fine until an update is published (or i install another instance using Xcode during dev), where the app says the files do not exist at the path. I have tried everything and i am stumped why do my files always get deleted after an update or overwrite install using Xcode.
Here is my code:
//folder being created here
NSString *libraryPath = [[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:#"Tracks"];
[[NSFileManager defaultManager] createDirectoryAtPath:libraryPath
withIntermediateDirectories:YES
attributes:nil
error:&error];
if (error != nil) {
NSLog(#"error creating directory: %#", error);
}
//file about to be copied
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"Evening-Visualization-vph" ofType:#"mp3"];
libraryPath = [libraryPath stringByAppendingPathComponent:#"Evening-Visualization-vph.mp3"];
if(![[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:libraryPath
error:&error]){
NSLog(#"Error Copying File from Bundle to Library");
}
NSURL * fileURL;
fileURL = [NSURL fileURLWithPath:libraryPath];
//file being marked so its not backed up to iCloud
if (![fileURL setResourceValue:[NSNumber numberWithBool: YES] forKey:NSURLIsExcludedFromBackupKey error:nil]) {
NSLog(#"Do not backup marked FAILED");
}
track.trackLocalPath = libraryPath;
The only solution i have left now is to manually check on each launch whether files exist at those path and mark my file list DB accordingly.

iOS Data Storage Rejection

My app got rejected because Apple found that on launch and/or content download, my app stores 14.18 MB.
Now I'm trying to skip backup of all the images and sounds I use in the game.
So far, I made a folder called "Resources" in my app folder itself, looking like this: App Folder Scrshot
What I did in AppDelegate.m is next:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[self addSkipBackupAttributeToItemAtURL:[self applicationDocumentsDirectory]];
return YES;
}
- (BOOL)addSkipBackupAttributeToItemAtURL:(NSURL *)URL
{
assert([[NSFileManager defaultManager] fileExistsAtPath: [URL path]]);
NSError *error = nil;
BOOL success = [URL setResourceValue: [NSNumber numberWithBool: YES]
forKey: NSURLIsExcludedFromBackupKey error: &error];
if(!success){
NSLog(#"Error excluding %# from backup %#", [URL lastPathComponent], error);
}
return success;
}
This isn't working.
I have 2 questions:
1)Am I doing the right thing from the start? Should I put all the images and sounds in folder called Resources, and then skipBackup for the entire folder or should I put them somewhere else?
If yes, then where?
(I saw over internet people talking about "Documents" folder...but I don't know what that folder is nor where to find it.
2)If I could put everything in "Resources" folder, how to I reach that folder from the code? How do I make URL to that folder, from Xcode itself?
Thanks in advance
You should deliver the content with your app. downloading the content on first launch is not a good idea due to the connection issue if user is on 3G/Edge.
the document directory is on the device, a folder under your app, and its created by ios automatically. Apple Documentation
getting files from resource folder is easy files from resources
I had this problem before ! The problem is not the size of what you store, it is where you store it. My guess is that you store your file in NSDocumentDirectory, which is bad because this directory should only be used to store data that the user created himself (documents, photo, etc). Adding the NSURLIsExcludedFromBackupKey is not enough. When it happened to me, I changed NSDocumentDirectory to NSApplicationSupportDirectory and my app got approved.
UPDATE
It is best if you first create a subdirectory in your NSApplicationSupportDirectory to store your file there.
Your methods should look like something like :
- (NSURL *) applicationDocumentsDirectory{
NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
appSupportDir = [appSupportDir stringByAppendingPathComponent:#"MyAppDirectory"];
return [NSURL URLWithString:appSupportDir];
}
And don't forget to create the directory first :
if (![[NSFileManager defaultManager] fileExistsAtPath:[self applicationDocumentsDirectory] isDirectory:NULL]) {
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtPath:[self applicationDocumentsDirectory] withIntermediateDirectories:YES attributes:nil error:&error];
}

Where should I put the XML file in iPhone Simulator's filesystem. XCode 4.2

A little embarrassing question, but I can find an answer which works in my case... I need to put some xml file (settings.xml) in order to read some data from it during application runtime.
According to some answers here and not only here, I have putted it here:
~/Library/Application Support/iPhone Simulator/5.0/[AppUUID]/Documents
and I'm trying to use it as follows:
// Loading data from external XML File
NSURL *url = [[NSBundle mainBundle]
URLForResource: #"settings" withExtension:#"xml"];
NSError *err;
if ([url checkResourceIsReachableAndReturnError:&err] == NO){
NSLog(#"FILE NOT FOUND");
}
Result: "FILE NOT FOUND".
I've tried to do put the file under any possible directory in
~/Library/Application Support/iPhone Simulator/5.0/[AppUUID]/ and efect is still the same.
I'm using XCode 4.2
If you are putting the file into the .../Documents folder then you need to use the following code to access it (you are looking for it in the App Bundle, which is a different location altogether):
NSString *docFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filename = [docFolder stringByAppendingPathComponent:#"settings.xml"];
if ([[NSFileManager defaultManager] fileExistsAtPath:filename])
{
// Read file
}
else
{
NSLog(#"settings.xml file not found!");
}

download file to Documents directory

I'm trying to copy a downloaded file to a specific folder in the app's documents directory but can't seem to get it working. The code I'm using is:
NSString *itemPathString = #"http://pathToFolder/folder/myFile.doc";
NSURL *myUrl = [NSURL URLWithString:itemPathString];
NSArray *paths = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *folderPath = [[paths objectAtIndex:0] URLByAppendingPathComponent:#"folder"];
NSURL *itemURL = [documentsPath URLByAppendingPathComponent:#"myFile.doc"];
// copy to documents directory asynchronously
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSFileManager *theFM = [[NSFileManager alloc] init];
NSError *error;
[theFM copyItemAtURL:myUrl toURL:itemURL error:&error];
}
});
I can retrieve the file OK but can't copy it. Can anyone tell me if there's anything wrong with the above code?
If downloading a file from a server, if it's a reasonably small file (e.g. measured in kb, not mb), you can use dataWithContentsOfURL. You can use that method to load the file into memory, and then use the NSData instance method writeToFile to save the file.
But, if it's a larger file, you will want to use NSURLConnection, which doesn't try to hold the whole file in memory, but rather writes it to the file system when appropriate. The trick here, though, is if you want to download multiple files, you either have to download them sequentially, or encapsulate the NSURLConnection and the NSOutputStream such that you can have separate copies of those for each simultaneous download.
I have uploaded a project, Download Manager that demonstrates what a NSURLConnection implementation might look like, but it's non-trivial. You might rather want to contemplate using an established, third-party library, such as ASIHTTPRequest or RestKit.
If you want to access a folder with a given name you should check if it exists and if not create it. That could quite easy be done like this:
NSString *folder = [documentsPath stringByAppendingPathComponent:folderName];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error = nil;
if (![fileManager fileExistsAtPath:folder]) {
[fileManager createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:nil error:&error];
}
if (error != nil) {
NSLog(#"Some error: %#", error);
return;
}
EDIT
If you want to check if the folder was created properly on your device got to Organizer -> Devices -> [YourDevelopingDeviceWhereTheAppWasInstalled] -> Applications -> [YourApplication]
In the lower section you should at least see some folders like Documents. And if successful your created folders as well.
You need to create any intermediate directories prior to copying files. Check in the Simulator folder to see wether the "folder" directory is created in the applications Documents-folder.
Path to simulator is /Users/$username/Library/Application Support/iPhone Simulator/

sqlite not working on iPhone simulator

I have a weird problem. My app works fine on my device but the sqlite database does not work on the simulator. The file "database.sqlite" exists in the same folder as my apps, it has the same name and the columns names are also correct.
So I assume there is something wrong with the configuration but I don't know what. Can someone please help me out.
Thanks
Here are some posts that seem to address the problem : http://forums.macrumors.com/showthread.php?t=484899
One reason might be because you should ensure the database is copied from your Supporting Files application directory (read only) to library or documents before you use it. Here's an ensurePrepared function from a sample of mine that uses sqlite that does just that. In this case, it's called contacts.db
- (BOOL)ensureDatabasePrepared: (NSError **)error
{
// already prepared
if ((_dbPath != nil) &&
([[NSFileManager defaultManager] fileExistsAtPath:_dbPath]))
{
return YES;
}
// db in main bundle - cant edit. copy to library if !exist
NSString *dbTemplatePath = [[NSBundle mainBundle] pathForResource:#"contacts" ofType:#"db"];
NSLog(#"%#", dbTemplatePath);
NSString *libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) lastObject];
_dbPath = [libraryPath stringByAppendingPathComponent:#"contacts.db"];
NSLog(#"dbPath: %#", _dbPath);
// copy db from template to library
if (![[NSFileManager defaultManager] fileExistsAtPath:_dbPath])
{
NSLog(#"db not exists");
NSError *error = nil;
if (![[NSFileManager defaultManager] copyItemAtPath:dbTemplatePath toPath:_dbPath error:&error])
{
return NO;
}
NSLog(#"copied");
}
return YES;
}

Resources