I am having trouble finding some information on persistence in iPhone apps. I am creating a tab based - navigation based app and want the application to save the current location when the app quits. For example if the user is in tab 1, several tiers into the navigation controller and the app quits, I would like the app to load up in the same place the next time it loads.
If anyone can point me in the direction of a good book/tutorial that would be great.
Cheers
Just to make it clear, I know that I would need to save the data somewhere and that NSUserDefaults seems to be the best way to do this. What is confusing me is what to actually save when the app is closed and then how to load it so that the correct view is loaded.
NSUserDefaults
http://icodeblog.com/2008/10/03/iphone-programming-tutorial-savingretrieving-data-using-nsuserdefaults/
Obviously, you'll need to save the tab you're displaying, and whatever sort of data storage you want to use to manually determine where the user is. If you're using a drill-down sort of system where your data is in arrays that the user opens, then I would suggest saving an NSIndexPath of the items the user clicked on to get to his current position.
Then, on app startup, first switch to the correct tab, then load the index path and create the necessary views and set the navigation controller's stack using [navigationController setViewControllers:animated:]
Related
I have a problem that I have not seen addressed in this particular way before, so hopefully someone can help me with it. Let's say I have a tab bar app with four views, one on each tab. Obviously the app will be forced to launch with the view controller it is told to launch with, but after that, it's up to the user to select which tab (view) to load next.
The problem comes from the fact that I would like to show a view on each tab ONLY the first time that particular view is loaded. Normally, you'd do this:
BOOL foo = [[NSUserDefaults standardUserDefaults]boolForKey:#"previouslyLaunched"];
if (!foo)
{
NSLog(#"FirstLaunch");
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:#"previouslyLaunched"];
///Do first run view initializaton here////
}
However, doing that once sets the NSUserDefault for all of the app, meaning that only the view for tab 1 will show and not the other three. So, my question is, how do I show a view for each of my four tabs only the first time each view loads? This is a complicated question because the user is able to select any tab in any order, so I can't guide them down a path, I think.
Would I have to use a different key for each view? Would that work? It seems like that might be the best course of action here, but this is my first time working with NSUserDefaults, so I'm a little lost.
Any and all help is much appreciated!
Use a different key for each view:
e.g. viewController1PreviouslyLaunched, viewController2PreviouslyLaunched... etc
k, I'm new to this so apologies all around, generally.
I'm trying to access the UISwitch value (on or off) from a different view and class and can't make it work.
It's a simple 2 view app. Main view and the second is a preference menu.
trying to write an if/else method to play sound when the switch (on the other view) is on and not when its off.
I cant seem to make it work. Any thoughts or some syntax examples would really help me out.
Thanks.
As Matt Wilding said "it's not good form to access UI components of one view controller from another...".
Instead of accessing the view object, when the switch state is changed by the user you save the status into NSUserDefaults as preference value. Whenever you want, you can access the switch status value through the preferences.
I'm going to take what I think you're trying to accomplish here and suggest an alternative approach. You want to have a preference in your app (assumed from "preferences menu") that allows the user to set something like whether or not you app plays background music. (May not be exact, this is just for clarification).
Typically, in a well designed app, the flow is driven by the data, with the UI reflecting the state of the data model and the controllers coordinating the two layers. What you are suggesting is to have your application play music based on the state of the UI, which is not backed by any data model. This cuts out the model level, and as you noticed, can lead to awkward attempts at communicating between the UI of different controllers for information.
Things like application preferences are typically stored in a nifty .plist file that is managed through the NSUserDefaults class. This would be a great place for the data level tracking of your preference. In this situation, the UISwitch would represent the state of the flag in the settings file, and changing the value of the switch would change the value in the file. Anywhere else in your application that you need to know if the play-sound-flag is set, you reference the data model info instead of the UI. This decouples the view controllers from each other, which is a good thing.
For this purpose add selector for swith and make NSInteger property in app delegate.Like the followed
[
yourSwitch addTarget:self action:#selector(switched:) forControlEvents:UIControlEventValueChanged];
-(IBAction) switched: (id)sender
{
int state=0;
if(yourSwitch.on)
state=1;
else
state=0;
objAppDelegate.switchState=state;
}
then you need to access this appDelegate property in second view where you are playing sound
then according to this value you can do what you want and for making object of appDelegate class you need this line
YourAppDelegateClass *objAppDelegate=(YourAppDelegateClass *)[[UIApplication sharedApplication] delegate];
ok if you have any other doubt then you can ask.
My app has a main login/password screen where user enters credentials and submits the info to a web service. Once authenticated, web-service will also tell me what kind of user is loggin in. So user can be type "A", "B" or "C".
Now depending on kind of user I need to load different views (having functionalities) only that particular type of user can use. So I have home screens for "A-HOME" "B-HOME" and "C-HOME" which will then be a Nav Controller or a Tab Controller.
So basically if A logged in - next view loaded should be "A-HOME"
My layman's guess is to load view programmatically. However, I prefer to not do it as you can forget few steps and leak or screw the app. Is there any common design pattern that is used in such cases. The scenario seems pretty regular case to me. Are there any apps with sample code on apple's developer website that does the same thing?
Please give your suggestions.
Thanks.
If the views are "sufficient distinct" use different view controllers for each one, and load the approriate one. You can load the whole thing from a nib if you want, just wire this up in code, after your login procedure, i.e.
-(void) doLogin:(LoginType)loginType
{
if (loginType == LoginTypeA)
{
TypeAViewController *viewController = .... // Load from i.e. "TypeAViewController.nib"
// Add its view
}
}
I have a tableview which shows a webview on clicking some row in the table, which in turn picks up the data from an sqlite. if a user closes the app by pressing home key while viewing a description in webview and reopens it after sometimes, I should be making the user to see the same screen. how to show the same view again ? What is the efficient way ?
Well I think the easiest way is to store the state of the application in NSUserDefaults. There is a delegate method on UIApplication called:
- (void)applicationWillTerminate:(UIApplication *)application
This delegate method gets called when the user quits the app. This is the time where you can save the state of your application off to the NSUserDefaults. But be aware that you cannot do time intensive stuff there. If you do, you get killed by the OS.
In your case why not simply store the row the user picked in NSUserDefaults and then check in
-(void)applicationDidFinishLaunching:(UIApplication *)application
if there is a saved row and restore the screen approbiately.
The easiest way is to write a string to a file in your documents directory that holds your state information in some easily parsed format. For example "screen_name:database_id". Or build a JSON string and parse it with JSON.
Everytime you switch screens, rewrite the file. When you open next time, read the file, parse it, and show the appropriate screen in your app.
I'll start with a confession here... I'm a real newbie to Objective-C & iPhone programming (started studying in February & coding in March), I have a project that's very ambitious for that level of experience & a very tight deadline to catch an opportunity to give my app a field trial.
My app is Core Data driven & downloads all of it's data on first run which is a choice made because it will be used on sites where 3G network access may not be reliable. I'd like to present a modal view while this happens, nothing fancy just a bit of text to explain, a progress bar or activity indicator, a graphic to pretty it up & button becoming visible when the job is done. I've tried a couple of approaches & failed dismally so no code for that as all but the XIB has been trashed.
At the moment I'm running this code in applicationDidFinishLaunching ...
[self checkDataAndLoadIfNeeded];
[window addSubview:rootController.view];
[window makeKeyAndVisible];
rootController is a TabBarController with nested NavigationControllers. checkDataAndLoadIfNeeded is a method that checks a default for the data being loaded & if it is not YES presents an alert. The delegate method for dismissing the alert then a custom class, DataLoader, which goes about downloading & importing the data.
What's happening is that the rootController view becomes visible before the alert does & the table on the first tab doesn't load any data until the next run of the app. I'm wondering if that data not loading is because I'm doing that in viewDidLoad & whether I'd do better to have it in viewWillAppear or viewDidAppear. When I tried loading the modal view I've built my rootController view still became visible first & my modal view didn't become visible until the data had finished (or almost finished) downloading (the Done button became visible immediately).
Can anyone offer suggestions as to how I can make this work?
Cheers & TIA, Pedro :)
Sounds like your rootController is not watching for changes in the data. It should not matter if the element is displayed already or if the data loads first. If the data loads later then the UI element should notice that the data is updated and then refresh itself.
Depending on your app design, you should look at the NSFetchedResultsController class and implement it along with its delegate methods. This class is designed to watch the NSManagedObjectContext for changes and when data is saved out to disk, update its delegate with what has changed.