programmatically clearing secondary cache on iPhone - iphone

I have created an application , where i ll be downloading the images from server and storing it locally on the iPhone's file system. Its happening fine. Now the problem is , i want to clear the locally cached images on iPhone when ever i quit my application.
How do i delete those cached images on iPhone. it's using Secondary memory on iPhone, how do i access it programmatically ?
Thank You in advance.
Suse.

Clean them up in your applicationWillTerminate method.
- (void)applicationWillTerminate:(UIApplication *)application
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *imagesFiles = [fileManager contentsOfDirectoryAtPath:saveDirectory error:&error];
for (NSString *file in imagesFiles) {
error = nil;
[fileManager removeItemAtPath:[saveDirectory stringByAppendingPathComponent:file] error:&error];
/* do error handling here */
}
}

My answer would be as per Kirky Todds, but don't use applicationWillTerminate -- it's not a good strategy on iOS4+ with multitasking, because this method often won't get called -- an app will be background, and then can be dumped from memory if other apps are run (or the phone is turned off/restarted), without applicationWillTerminate getting called. (OR it will be foregrounded again. Either way, your cache doesn't get cleared.)
Instead, consider either clearing at startup (applicationDidFinishLaunching), or in applicationWillEnterForeground. The latter will tend to get called more frequently, because the former is only called on an actual proper app lauch (and not on a resume from being backgrounded).
For more info on backgrounding and the events generated, see:
http://www.cocoanetics.com/2010/07/understanding-ios-4-backgrounding-and-delegate-messaging/

Related

NSFileManager removeItemAtPath locks main thread

I'm working on an app that can remove large amounts of files. When I invoke the NSFileManager's removeItemAtPath method, the app's UI locks until the operation finishes (this can take a while).
I tried fixing this by invoking the method using performSelectorInBackground but it didn't work.
Any ideas?
Thanks in advance.
You could try using GCD to do it in a background thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
[[NSFileManager defaultManager] removeItemAtPath:path];
});

How to check if iCloud is configured programmatically

Here is the sentence from Apple Docs:
"If iCloud is not configured, ask users if they want to configure it (and, preferably, transfer them to Launch Settings if they want to configure iCloud)."
How can I check if iCloud is configured or not and how to launch settings for iCloud?
Edit:
If you are targeting iOS6 or above you can use [[NSFileManager defaultManager] ubiquityIdentityToken];. For usage example please refer #Dj S' answer :).
It is faster and easier than the original solution which was meant for people targeting iOS5 and above
Original Answer
As documented in iOS App programming guide - iCloud Storage. That can be checked by asking the ubiquity container URL to the file manager :)
As long as you supply a valid ubiquity container identifier below method should return YES
- (BOOL) isICloudAvailable
{
// Make sure a correct Ubiquity Container Identifier is passed
NSURL *ubiquityURL = [[NSFileManager defaultManager]
URLForUbiquityContainerIdentifier:#"ABCDEFGHI0.com.acme.MyApp"];
return ubiquityURL ? YES : NO;
}
However, I've found that URLForUbiquityContainerIdentifier: might take several seconds the very first time within a session (I used it in iOS5 so things might be different now). I remember using something like this:
dispatch_queue_t backgroundQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue,^{
BOOL isAvailable = [self isICloudAvailable]
/* change to the main queue if you want to do something with the UI. For example: */
dispatch_async(dispatch_get_main_queue(),^{
if (!isAvailable){
/* inform the user */
UIAlertView *alert = [[UIAlertView alloc] init...]
[alert show];
[alert release];
}
});
});
Just to supplement the answer above,
if you only want to know if iCloud is available for your application,
e.g.
1. no iCloud account is setup, or
2. Documents and Data is disabled (for all apps), or
3. Documents and Data is disabled for your app only
then you can use NSFileManager's ubiquityIdentityToken for iOS 6 and above.
If value is nil, then iCloud account is not configured. Otherwise, iCloud account is configured.
id token = [[NSFileManager defaultManager] ubiquityIdentityToken];
if (token == nil)
{
// iCloud is not available for this app
}
else
{
// iCloud is available
}
Note that according to Apple docs, you can call it from the main thread.
Because this method returns relatively quickly, you can call it at launch time and you can call it from your app’s main thread.

how do i remove coredata from iphone

You know how you can Reset the coredata store on an iPhone simulator when you've changed your entity structure?
Do I need to perform a similar process when I've created a new version of my core data store that is different from what I last ran on my iPhone? If so, how, please?
Thanks
Just for convenience, until you code a way to remove the persistent store through your app, you can just delete the app off the phone. (Hold your finger on the home screen until icons get wiggly, then click the x on your app.) Then with your phone connected to your Mac, choose Product > Run in XCode and it will reinstall your app on the phone, but with empty data directories.
For deployment, of course, you need to come up with a way to do it without deleting the app, if you will ever change your data model after deployment (assume you will). Data migration is the best option, but if all else fails delete the persistent store file. It would be preferable to prompt for the user's approval before doing that. If they have important data they can decline and maybe get the old version of your app back to view the data and migrate it by hand, or they can wait until you release version 2.0.1 that fixes your data migration bug.
Here is the routine I use to reset my App content. It erases the store and any other file stored.
- (void) resetContent
{
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSString * rootDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *rootURL = [NSURL fileURLWithPath:rootDir isDirectory:YES];
NSArray *content = [localFileManager contentsOfDirectoryAtURL:rootURL includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsSubdirectoryDescendants error:NULL];
for (NSURL *itemURL in content) {
[localFileManager removeItemAtURL:itemURL error:NULL];
}
[localFileManager release];
}
If you only want to erase the store, since you know its file name, you can refrain from enumerating the document directory content:
- (void) resetContent
{
NSFileManager *localFileManager = [[NSFileManager alloc] init];
NSString * rootDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSURL *rootURL = [NSURL fileURLWithPath:rootDir isDirectory:YES];
NSURL *storeURL = [rootURL URLByAppendingPathComponent:#"myStore.sqlite"];
[localFileManager removeItemAtURL:storeURL error:NULL];
[localFileManager release];
}
But please note that in many cases, its better to migrate your store when you change your model, rather than to delete it.
locate your app in /Users/username/Library/Application Support/iPhone Simulator/4.3.2 (iOS Version may be different) and delete the .sqlite file
You can look at the path that is being sent to the persistentStoreCoordinator on setup, and remove that file. Usually the approach I have taken is that I set up the store to auto migrate, and if that fails I delete the store and attempt one more time to create the persistentStoreCoordinator which will use the now empty path.
Don't forget you may need to repopulate anything stored in the old database.

App Crashing When Relaunching

When I hard exit (double click home and minus) and then relaunch app it is freezing up.
The Console shows this:
[app directory path .....]has changed; re-reading symbols.
I think it may have to do with this code in my appdelagate.m
- (void)applicationWillTerminate:(UIApplication *)application
{
[self saveCode];
}
- (void)saveCode
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"routine.plist"];
[NSArray writeToFile:path atomically:YES];
}
First: saving a plist to populate a UITableViewController is a really tedious way to save data persistently and an inconsistent one as you may have realized, I would recommend that you use Core Data instead.
Second: Run the debugger (before launching your app) and find any line of text that's shown in black (grey lines are for methods called by the os and the cocoa layer, black ones are for your own methods). The debugger can be run via Run > Debugger or Command + Shift + Y.
The similar kind of crashing issue - on quick relaunch is being faced when I use location manager in the application. The case is : my application quits on pressing home button rather than going into the background in iPhone 4. And on iPhone 3G (where no background processing is supported) the case is same - it crashes on relaunch [atleast it seems like a crash].
If we wait even 1 second to relaunch the app, it does not crash.

Core Data database doesn't save

I'm trying to implement the Paparazzi 2 assignment from the Stanford CS193 course and I'm running into a problem. My one call to save the database is when the app exits (I'm borrowing heavily from Mike Postel's version to check my code):
- (void)applicationWillTerminate:(UIApplication *)application {
if (flickrContext != nil) {
if ([flickrContext hasChanges] == YES) {
NSError *error = nil;
BOOL isSaved = [flickrContext save:&error];
NSLog(#"isSaved? %#", (isSaved ? #"YES" :#"NO") );
// Replace this implementation with code to handle the error appropriately.
if(isSaved == NO){
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
}
Unfortunately, this doesn't seem to be doing the job. I'm getting the occasional EXEC_BAD_ACCESS call that might be related to this, but the database never saves. I've inserted the save into other pieces and it works fine there, just not in this routine. I'm not releasing any of the managed objects in my views, just the managed object context (flickrContext, or whatever I'm calling it in a view).
Any ideas?
Are you sure that applicationWillTerminate: is even being called?
With iOS4 and background process support, the usual application lifecycle is now:
running -> background -> background suspended -> exit
You get an applicationDidEnterBackground: call when transitioning into the background state, but no further notification when the background process suspends or exits.
So, you really need to save state in applicationDidEnterBackground: for iOS4, as well as in applicationWillTerminate: for older versions
flickrContext is your managedObjectContext? I'm betting it is nil or otherwise hosed when you hit this method. You say you are releasing it in a view - surely you should be creating just one, having it owned by the application delegate, and release it only in app delegate's dealloc?
(And when you need to use it -
NSManagedObjectContext* moc = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
)
Regarding your EXEC_BAD_ACCESS - what happens with NSZombieEnabled = YES? What does the static analyzer say?
Good call. I actually solved this one the old fashioned (brute force) way. It turns out that applicationWillTerminate wasn't being called, but it wasn't obvious. The routine to create the database that I had borrowed from the web was explicitly releasing an NSArray that I'm pretty sure was autoreleased. It essentially turned the program into a time bomb. Although I still haven't figured out why it lasted as long as it did and just didn't manifest until I tried to exit.
I'm still learning XCode and CocoaTouch. I know about NSZombieEnabled but I haven't figured out how to use it correctly yet. I'm still in the ham-fisted monkey stage. Thanks for the tips, though. They were helpful.