I am saving Images in NSCachesDirectory in a App. At the end of app execution i would like to clear all temporary cache. Is there a way to force clear all cache on application exit. I do realise the local folder keeps cache for 3 days..but my requirement is to force clear the Cache. Thx
This code should do the trick, just substitute the name of your cache directory...
NSString *cacheDirectoryName = [self getCacheDirectoryName];
NSArray *items = [fileManager directoryContentsAtPath:cacheDirectoryName];
for (NSString *item in items)
{
NSString *path = [cacheDirectoryName stringByAppendingPathComponent:item];
NSError *error = nil;
[fileManager removeItemAtPath:path error:&error];
[error release];
}
Then call the code in your AppDelegate applicationWillTerminate method.
Related
I'm a web app developer trying to test my app, but Apple has changed the way they save web app data when you add it to the home screen.
How can I clear my web app's local storage so I can see updates to my code?
iOS Apps are stored in a sandbox. So every application has its own directory and working space.
In that working space all data of the application gets stored. This includes documents, library files, temporary files, the application bundle, as well as the preferences file.
When a user chooses to delete an app, the whole sandbox gets removed, including those preferences.
Here are some Solutions for Handling App sandbox data
Deleting all the files in the iPhone sandbox
NSFileManager *fileMgr = [[[NSFileManager alloc] init] autorelease];
NSError *error = nil;
NSArray *directoryContents = [fileMgr contentsOfDirectoryAtPath:documentsDirectory error:&error];
if (error == nil) {
for (NSString *path in directoryContents) {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:path];
BOOL removeSuccess = [fileMgr removeItemAtPath:fullPath error:&error];
if (!removeSuccess) {
// Error handling
...
}
}
} else {
// Error handling
...
}
Clear Safari Cache
Clear UIWebView Cache
// Flush all cached data
[[NSURLCache sharedURLCache] removeAllCachedResponses];
Reference
Hope this helps!
I'm working on an app that lets users record voice (among other things) to the Documents directory of the app. But when I'm recording the voice, I'm recording to the caches directory of the app and then after the user says "Okay, save this one", then I'm coping it to the Documents directory. So far all these work. But if I try to delete the data file in cache, or when I try to move it, I get problems.
So my question is, shall I just leave the data in cache so that iOS will handle it or do I need to manually delete the files in cache. If so how would I go about doing it. This is the code I have so far (which doesn't work)
NSFileManager *fm = [NSFileManager defaultManager];
NSString *directory = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSError *error = nil;
BOOL success = [fm removeItemAtPath:[NSString stringWithFormat:#"%#%#", directory, currentEntry.audioFileURL] error:&error];
if (!success || error) {
// it failed.
NSLog(#"it failed to delete!!! %# %#", error, [error userInfo]);
} else {
NSLog(#"Deleted... yipee... !!!");
}
I think the problem is that your path is not correct. Always use the
- (NSString *)stringByAppendingPathComponent:(NSString *)aString
method of NSString.
You can try printing out the path you get now (maybe a backslash is missing), but anyway you should use the method I described.
UPD: Another thing is that NSCachesDirectory is actually never cleaned up. Use NSTemporaryDirectory() if you want automatic cleaning.
In my app I sometimes need to rebuild and repopulate database file. SQLite databse is created and managed by CoreData stack.
What I'm trying to do is drop the file and then simply recreate persistentStoreCoordinator object.
It works under simulator but not on device, where I'm getting such an error:
NSFilePath = "/var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite";
NSUnderlyingException = I/O error for database at /var/mobile/Applications/936C6CC7-423A-46F4-ADC0-7184EAB0CADD/Documents/MYDB.sqlite. SQLite error code:1, 'table ZXXXX already exists';
I cannot find the cause of this in any way. It indicates two different problems - Cocoa error 256 indicates that file does not exist or is not readable. But file IS created after creating persistenStoreCoordinator, although it's empty, but after executing some queries it disappears.
Second message indicating attempt to create alredy existing table is quite strange in that case.
I'm quite confused and cannot get the point what's going on here. My code looks like this:
NSString *path = [[WLLocalService dataStorePath] relativePath];
NSError *error = nil;
WLLOG(#"About to remove file %#", path);
[[NSFileManager defaultManager] removeItemAtPath: path error: &error];
if (error != nil) {
WLLOG(#"Error removing the DB: %#", error);
}
[self persistentStoreCoordinator];
WLLOG(#"Rebuild DB result %d", [[NSFileManager defaultManager] fileExistsAtPath: path]);
After this code is exectued, DB file exists but is empty. When then first query (and all following) is executed, it gives me the error above and file disappears.
Does anybody has an idea what's wrong with it?
Big thanks for pointing me the right way!
The Core Data stack does not like you removing the file under it. If you are wanting to delete the file you should tear down the stack, delete the file and then reconstruct the stack. That will eliminate the issue.
Part of the problem is that the stack keeps a cache of the data that is in the file. When you remove the file you don't have a way to clear that cache and you are then putting Core Data into an unknown and unstable state.
You can try telling the NSPersistentStoreCoordinator you are removing the file with a call to -removePersistentStore:error: and then adding the new store with a call to -addPersistentStoreWithType:configuration:URL:options:error:. I am doing that currently in ZSync and it works just fine.
I use the following method -resetApplicationModel in my app delegate and it works fine for me.
You may not need the kApplicationIsFirstTimeRunKey user default, but I use it to test whether to populate the Core Data store with default settings in a custom method called -setupModelDefaults, which I also call from -applicationDidFinishLaunching: if the first-time run flag is YES.
- (BOOL) resetApplicationModel {
// ----------------------
// This method removes all traces of the Core Data store and then resets the application defaults
// ----------------------
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:kApplicationIsFirstTimeRunKey];
NSLog(#"Turned ON the first-time run flag...");
NSError *_error = nil;
NSURL *_storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"MyAppSQLStore.sqlite"]];
NSPersistentStore *_store = [persistentStoreCoordinator persistentStoreForURL:_storeURL];
//
// Remove the SQL store and the file associated with it
//
if ([persistentStoreCoordinator removePersistentStore:_store error:&_error]) {
[[NSFileManager defaultManager] removeItemAtPath:_storeURL.path error:&_error];
}
if (_error) {
NSLog(#"Failed to remove persistent store: %#", [_error localizedDescription]);
NSArray *_detailedErrors = [[_error userInfo] objectForKey:NSDetailedErrorsKey];
if (_detailedErrors != nil && [_detailedErrors count] > 0) {
for (NSError *_detailedError in _detailedErrors) {
NSLog(#" DetailedError: %#", [_detailedError userInfo]);
}
}
else {
NSLog(#" %#", [_error userInfo]);
}
return NO;
}
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
[managedObjectContext release], managedObjectContext = nil;
//
// Rebuild the application's managed object context
//
[self managedObjectContext];
//
// Repopulate Core Data defaults
//
[self setupModelDefaults];
return YES;
}
You can keep a "clean" copy of your sqlite database as part of the application bundle, then just copy over the version in the documents directory whenever you'd like to refresh the database.
Here's some code from an App that does something similar (although this version will not copy over and existing db):
// Check for the existence of the seed database
// Get the path to the documents directory and append the databaseName
NSString* databasePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent: kDatabaseName];
NSFileManager* fileManager = [NSFileManager defaultManager];
if ( ![fileManager fileExistsAtPath: databasePath] )
{
NSString* databasePathFromApp = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent: kDatabaseName];
[fileManager copyItemAtPath: databasePathFromApp
toPath: databasePath
error: nil];
}
[fileManager release];
I'm trying to write two applications (iphone and desktop) to achieve what's been described in the following link:
core-data-is-it-possible-to-build-a-desktop-app-to-create-the-data-model-for-an
Ok. So I've created a very simple desktop app the has a single entity named Client with a string attribute field called name. I've also generated the corresponding Model class.
I've run the app added a couple of client names to the list and saved the file (as Testing.sqlite).
Now in my equivalent iphone app I'm attempting to load the file. I've generated the app initially using one of the application templates and included Core Data. NB: I've mirrored the Client entity and generated the corresponding Model class.
I've gone into my "application delegate" class and amended the persistentStoreCoordinator method to reference my "Testing.sqlite" file i.e.
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: #"Testing.sqlite"]];
I've also copied the saved desktop app file into the expected location i.e.
~/Library/Application Support/IPhone Simulator/User/... etc.
So now in theory at least each of the two apps should be the same.
However when I'm attempting to load the data from the it always seems to be empty. My code looks a little like this:
// fetch the delegate.
TestingAppDelegate *app = (TestingAppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = [app managedObjectContext];
// construct the request.
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Client" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
// execute the request.
NSError *error;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
if (results == nil) {
// Handle the error.
NSLog(#"No data loaded");
}
NSLog(#"Returned: %#", results);
// finally release
[results release];
[request release];
I can't seem to figure out what's going wrong. Any tips or suggestions would be totally appreciated.
When I've looked at the instance of the persistanceStoreCoordinator, managedObjectContext, resulting array (NSArray) whilst debugging I can see that it seems to contain 0 records for all of these. So I'm confused.
NB: The Testing.sqlite file contains entries.
Thanks in advance,
Matt
Simply copying the sqlite database file will not work when using Core Data.
You need to fully replicate the persistent store you created in your desktop application.
However, this may be a problem related to the fact that Core Data is not seeing your database file even though you copied it. Try the following:
1) add your database file to your project in the resources group
2) use this method to actually copy your database file in place
- (NSString *) initialize_db {
NSString *DATABASE_RESOURCE_NAME = #"testing";
NSString *DATABASE_RESOURCE_TYPE = #"sqlite";
NSString *DATABASE_FILE_NAME = #"testing.sqlite";
// copy the database from the bundle if necessary
// look to see if DB is in known location (~/Documents/$DATABASE_FILE_NAME)
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentFolderPath = [searchPaths objectAtIndex: 0];
NSString *dbFilePath = [documentFolderPath stringByAppendingPathComponent: DATABASE_FILE_NAME];
[dbFilePath retain];
if (! [[NSFileManager defaultManager] fileExistsAtPath: dbFilePath]) {
// didn't find db, need to copy
NSString *backupDbPath = [[NSBundle mainBundle]
pathForResource:DATABASE_RESOURCE_NAME
ofType:DATABASE_RESOURCE_TYPE];
if (backupDbPath == nil) {
// couldn't find backup db to copy, bail
NSLog (#"couldn't init db");
return NULL;
} else {
BOOL copiedBackupDb = [[NSFileManager defaultManager]
copyItemAtPath:backupDbPath
toPath:dbFilePath
error:nil];
if (! copiedBackupDb) {
// copying backup db failed, bail
NSLog (#"couldn't init db");
return NULL;
}
}
}
return dbFilePath;
}
Once you have copied the database file, you have its file path returned, and you use it to actually open the database.
I cache the images to the document directory of my app using the following code.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *saveDirectory = [paths objectAtIndex:0];
But even after I close the application, its still there. How can I clear it when I lose my app. I am doing all this in my simulator.
I would implement applicationWillTerminate: in my application delegate and remove the cache files there. Or better yet, as suggested by Vladimir, save them in a temporary directory and let the OS clean them up when needed.
- (void)applicationWillTerminate:(UIApplication *)app
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:saveDirectory error:error];
for (NSString *file in cacheFiles) {
error = nil;
[fileManager removeItemAtPath:[saveDirectory stringByAppendingPathComponent:file] error:error];
/* handle error */
}
}
If you do not want your cached images to be preserved after application is closed better save them to temporary directory - they will be removed automatically.
If you want to manually remove the files you must store the paths for them and use the following NSFileManager function:
- (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error
Edit: sorry, I appeared to be wrong here about automatic deleting. Here's a quote from Developing Guide:
Use this directory to write temporary files that you do not need to persist between launches of your application. Your application should remove files from this directory when it determines they are no longer needed. (The system may also purge lingering files from this directory when your application is not running.)
NSString *file;
NSDirectoryEnumerator *dirEnum = [[NSFileManager defaultManager] enumeratorAtPath:saveDirectory];
NSError* err;
while (file = [dirEnum nextObject]) {
err = nil;
[[NSFileManager defaultManager] removeItemAtPath:[saveDirectory stringByAppendingPathComponent:file] error:&err]];
if(err){
//print some errror message
}
}
Use the temporary directory path as specified in this question:
How can I get a writable path on the iPhone?