Reputation: 11
I am new to iOS app development and I made an app which has a text field, an insert button and a table.
So, when something is entered into the text field, it is displayed on the table.
When the app enters background or terminates, it save that list as follows:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
NSBundle *myApp = [NSBundle mainBundle];
NSMutableString *fileDirectory = [[NSMutableString alloc] initWithString:[myApp bundlePath]];
[fileDirectory appendString:@"/list.plist"];
NSLog(@"%@", fileDirectory); //Just for refernece
[self.viewController.tasks writeToFile:fileDirectory atomically:YES];
NSLog(@"SAVED");
}
and
- (void)applicationWillTerminate:(UIApplication *)application {
NSBundle *myApp = [NSBundle mainBundle];
NSMutableString *fileDirectory = [[NSMutableString alloc] initWithString:[myApp bundlePath]];
[fileDirectory appendString:@"/list.plist"];
NSLog(@"%@", fileDirectory); //Just for refernece
[self.viewController.tasks writeToFile:fileDirectory atomically:YES];
NSLog(@"SAVED");
}
The file is saved.
After killing the app and opening the app again, I don't get the list back (only on my iPhone, on simulator it works fine)
Is it possible to retain the list on iPhone?
P.S: Sorry if I'm being verbose. Thank you.
Upvotes: 0
Views: 342
Reputation: 11
So, I fixed the issue.
The code now saves the file asynchronously in applicationDidEnterBackground as follows:
- (void)applicationDidEnterBackground:(UIApplication *)application {
typedef void (^block)();
block theBlock;
theBlock = ^(){
BOOL fileWritten = [self.viewController.tasks writeToFile:self.viewController.savedList atomically:YES];
if(fileWritten)
{
NSLog(@"Saved");
}
};
/* Saving file Asynchronorusly */
dispatch_queue_t myQueue = dispatch_queue_create("QUEUE-1",DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myQueue, theBlock);
}
and synchronously in applicationWillTerminate as follows:
- (void)applicationWillTerminate:(UIApplication *)application {
/* Saving file Synchronously */
BOOL fileWritten = [self.viewController.tasks writeToFile:self.viewController.savedList atomically:YES];
if(fileWritten)
{
NSLog(@"Saved");
}
}
Those who pointed out that I didn't have any retrieval code, I am sorry I forgot to mention it. It loads the .plist in applicationDidFinishLaunching as follows:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.viewController myButton:nil];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc]initWithNibName:@"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
NSURL *fileDirectory = self.viewController.applicationDocumentsDirectory;
NSMutableString *filePath = [[NSMutableString alloc] initWithString:[fileDirectory absoluteString]];
[filePath appendString:@"list.plist"];
filePath = (NSMutableString *)[filePath stringByReplacingOccurrencesOfString:@"file:///" withString:@""];
self.viewController.savedList = filePath;
if([[NSFileManager alloc] fileExistsAtPath:self.viewController.savedList])
{
self.viewController.tasks = [[NSMutableArray alloc] initWithContentsOfFile:self.viewController.savedList];
NSLog(@"DATA READ: %@", self.viewController.tasks);
}
[self.window makeKeyAndVisible];
return YES;
}
So, now the app works as expected. Thank you guys.
Upvotes: 0
Reputation: 3763
The method -writeToFile:atomically:
returns a BOOL
indicating if the write operation was successful.
In your case, it will be successful on the simulator, as your are writing to your Mac's disk, which can always be done, as your process has write-privileges to your application's bundle. This is not the case on the device: because the app is code-signed the bundle is readonly, and you cannot write a file into it, so the method will return NO
.
You should always check this value, and respond appropriately. There is also a method that takes an NSError
pointer, so you can see why a write operation failed.
Remember that -writeToFile:atomically:
is a synchronous operation, and it will block the thread on which it is called. In general, you want to avoid blocking the main thread, and therefore it is best to run the method on another thread (look up dispatch_async()
and GCD documentation). In your case, your are calling it in applicationWillTerminate:
, which is the last breath of your application and you do not want to dispatch to another thread, as it will die with the after application after applicationWillTerminate:
returns, and most likely before that secondary thread had a chance to finish. Note, however, that applicationWillTerminate:
might not be the best place to save state in, as time is short there, but also because this method is only called when your application will really terminate (it is not called when you press the home-button for example). Look up the documentation on the other application-lifetime methods to find out where to save your date best, you might find that you don't even need to use those methods, but saving can be done 'on th fly' while the app is running. Whatever suits your purposes.
To get a directory to which you can write, you can use for example this code:
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory: NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
Upvotes: 3
Reputation: 3126
Just load the file back in applicationDidBecomeActive
or applicationDidFinishLaunching
, assuming the file was successfully created and it didn't somehow get deleted between the time you closed the app and restarted it, which shouldn't happen, unless you're cleaning the build container files explicitly, but I doubt it.
Upvotes: 0