How to persist a file under NSHomeDirectory()? - ios

I am using NSKeyedArchiver and NSKeyedUnarchiver to implement cache function for my app.
In order to load the cache file each time the app launches, I store the cache file under NSHomeDirectory(). The code (C function) is as following:
NSString* getArchivePathForId(NSString* modelId)
{
NSString *cacheIdentifier = #"CacheIdentifier";
NSString *archiveDirPath = [NSHomeDirectory() stringByAppendingFormat:#"/tmp/%#/cachedModel/%#", getAppVersion(), cacheIdentifier];
NSError* error;
if (![[NSFileManager defaultManager] fileExistsAtPath:archiveDirPath]) {
if (![[NSFileManager defaultManager] createDirectoryAtPath:archiveDirPath
withIntermediateDirectories:YES
attributes:nil
error:&error])
{
NSLog(#"Create directory tmp/cachedModel directory error: %#", error);
return nil;
}
}
NSString *archivePath = [archiveDirPath stringByAppendingFormat:#"/%#", modelId];
return archivePath;
}
It works fine as long as the App is running or coming back to live from the background mode. But once the app is terminated and re-run, the cached archive file is deleted.
Is there any way to persist the archive file so that I can load the cache stored last time when the app was launched.
I have already realised that each time the app is launched, the application id part of the NSHomeDirectory() is different. Does this have anything to do with my issue?

The issue is the "tmp" directory name at the top level. Generally files are saved under the "Documents" directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths firstObject];`
Persistent caches are generally placed under the "Library" directly, use NSLibraryDirectory.
See: File System Programming Guide
tmp/
Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when they are no longer needed; however, the system may purge this directory when your app is not running.

Related

SQLite3 db on iOS 9: read only error, how to write to the db? [duplicate]

i deployed my App to my iPhone and get
Unknown error calling sqlite3_step (8: attempt to write a readonly database) eu
on Insert / Update Statements.
On the Simulator it all works like it should.
My sqlite Database is placed in the Resource Folder (Xcode).
Thanks for help!
Your application bundle is not writable on the iPhone. You MUST copy the file somewhere else, like your documents folder. It works in the simulator because the Mac does not enforce all the sandboxing restrictions the iPhone does.
You can copy your database from the application bundle directory to the Documents directory in viewDidLoad. You can read/write from/to your database in the Documents directory after this. Of course, you need to check if the database in the Documents directory exist before you do the copy in order not to overwrite it the next time you bring up the app.
Assuming you have defined your database name '#define kFilename #"yourdatabase.db"' in the .m file.
In viewDidLoad add:
// Get the path to the main bundle resource directory.
NSString *pathsToReources = [[NSBundle mainBundle] resourcePath];
NSString *yourOriginalDatabasePath = [pathsToResources stringByAppendingPathComponent:kFilename];
// Create the path to the database in the Documents directory.
NSArray *pathsToDocuments = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [pathsToDocuments objectAtIndex:0];
NSString *yourNewDatabasePath = [documentsDirectory stringByAppendingPathComponent:kFilename];
if (![[NSFileManager defaultManager] isReadableFileAtPath:yourNewDatabasePath]) {
if ([[NSFileManager defaultManager] copyItemAtPath:yourOriginalDatabasePath toPath:yourNewDatabasePath error:NULL] != YES)
NSAssert2(0, #"Fail to copy database from %# to %#", yourOriginalDatabasePath, yourNewDatabasePath);
}
Good luck!
aobs

Lost files in iOS App

I have a app that downloads video and image files from a server. I store these files in folders in my app. I have 3 different places where i store the files:
Caches Directory - Videos + Images downloaded
Application Support Directory - Database
Documents Directory - Videos taken by current user
The code that i use to get paths to these folders is:
+ (NSString *)FilesStoreDirectory
{
NSArray *paths = [[NSFileManager defaultManager] URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask];
NSString *path = paths.count ? [(NSURL *)paths.firstObject path] : NSTemporaryDirectory();
NSString *result = [path stringByAppendingPathComponent:#"files"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:result])
{
[fileManager createDirectoryAtPath:result withIntermediateDirectories:YES attributes:nil error:nil];
}
return result;
}
At the logout i remove all these folders and files. The database (sql) is the only file that is not deleted.
My problem is that the size of the app increases while use. I have a example of 4 GB of stored files and after logout it went down to 1.9 GB when it should only be 23 MB + database (small). The way that a check how big is the app is by checking Settings -> Usage.
I am thinking maybe there is a problem with the folder creation and it creates different folders between different runs of the app, but that didn't solve the problem.
I play these video files so i suspect the AVPlayer of caching these files and not letting them go. But that is just a hunch.
Anybody has a idea why this is happening, and how can i get back to 23 MB of app size?
Thanks.
LATER EDIT:
This is the code that i use to remove the folders:
[[NSFileManager defaultManager] removeItemAtPath:[LVCoreDataController FilesStoreDirectory] error:nil];

iOS-Creating a directory in Documents

I'm trying to create a folder in my documents directory and I want to be able to do it without typing out /Users/(username)/Documents/Foo/Bar
NSString *directoryPath = [NSString stringWithFormat:#"%#/Documents/Foo/Bar", NSHomeDirectory()];
BOOL isDir;
NSFileManager *fileManager= [NSFileManager defaultManager];
if(![fileManager fileExistsAtPath:directoryPath isDirectory:&isDir])
if(![fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:NULL])
NSLog(#"Error: Create folder failed %#", directoryPath);
This doesn't work when I try using NSHomeDirectory() with it. But if I typed out the full path /Users/(username)/Documents/Foo/Ba it works. How can it be done to not have to know the users folder?
EDIT:
directoryPath becomes
/Users/(username)/Library/Developer/CoreSimulator/Devices/FAB78255-38D2-49BE-9683-7A0676EA2288/data/Containers/Data/Application/67B0AACE-572A-4808-9535-D221AEEB9EFA/Foo/Bar
I just want /Users/(username)
This is an iOS app. The "Documents" folder of an iOS app's sandbox is not at all related to the user's "Documents" folder on their computer.
Since you appear to be running your iOS in the simulator, the path you are getting is more like what you should be seeing. You do not want a path in the user's home directory.
Keep in mind that you can't get access to the "Documents" folder of an iOS app using NSHomeDirectory(). That may have worked in older versions of iOS but it fails in iOS 8 and later. The proper code needs to be something like this:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsFolder = paths[0];
NSString *directoryPath = [documentsFolder stringByAppendingPathComponent:#"Foo/Bar"];

itunes file share restore deleted files

My app uses iTunes File Share. I used the code to delete a single file:
It worked the first time. On the second try, however, iTunes showed a empty share directory. It turns out all data files are gone. Can I recover those data files from the iPad? Thanks
- (void) deleteFileFromDisk: (NSString*) fileName {
if([self fileExists: fileName]) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) ;
NSString *documentsDirectory = [paths objectAtIndex: 0];
NSString* theFile = [documentsDirectory stringByAppendingPathComponent: fileName];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath: theFile error: &error];
There's no "restore" feature on the iPad. But in all probability there's nothing to worry about.
There's nothing about your code that would delete multiple files. It would delete just that file from the Documents directory that you supplied the name of as fileName. If you didn't call deleteFileFromDisk: multiple times, you didn't delete multiple files.
Perhaps at some point you deleted the app. That would delete its entire sandbox and thus would take with it anything in the Documents directory. That sort of thing is perfectly normal during repeated testing.

is it OK to handle a Core Data database created with from an UIManagedDocument with NSFileManager?

I'm making an app which uses Core Data, and for the purpose of my app I need to bundle a pre-populated database with the app bundle.
I'm using a UIManagedDocument
For this, I created the database with the app and later loaded the data. Then I searched the iOS Simulator folder in my Mac and drag and dropped the persistentStore file into the app bundle.
Later in the code I copied it to the NSDocumentDirectory because the user will be allowed to edit the database at runtime. This was done with the following method:
if(![[NSFileManager defaultManager] fileExistsAtPath:[self.appDatabase.fileURL path]])
{
// COPY FROM BUNDLE
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *DB = [[paths lastObject] stringByAppendingPathComponent:#"Default App Database"];
DB = [DB stringByAppendingPathComponent:#"StoreContent"];
[fileManager createDirectoryAtPath:DB withIntermediateDirectories:YES attributes:nil error:&error];
NSLog(#"create directory error: %#",error);
DB = [DB stringByAppendingPathComponent:#"persistentStore"];
NSString *shippedDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"persistentStore"];
NSLog(#"%d",[fileManager fileExistsAtPath:shippedDB]);
[fileManager copyItemAtPath:shippedDB toPath:DB error:&error];
NSLog(#"Copy error %#",error);
}
Everything is working perfectly! But, I'm not sure if this will generate some type of error. So my question, is it OK to handle a Core Data database created with from an UIManagedDocument with NSFileManager?
And, will Apple complain in the review process for bundling the persistentStore file?
Bundling a default persistent store with the app is explicitly mentioned in the "Core Data Programming Guide":
How do I initialize a store with default data?
...
You can create a separate persistent store that contains the default
data and include the store as an application resource. When you want
to use it, you must either copy the whole store to a suitable
location, or copy the objects from the defaults store to an existing
store.

Resources