I am facing the issue in preserving the state of my application.
My application is based on storyboard, this is how it goes.
First I have a navigation controller, then a login screen. When user logs in, I push it to a controller, which have table view on left side, with UITabbar Items, this is mainly a custom tab bar. On clicking every button, I add that container view to the the self. The application state preserves till here, But whenever I push further, it doesn't preserve and restore the state. On the custom tab bar, I have even encode and decoded the child view controller, and add accordingly when state restores. But when I navigate further it doesn't. Further I saw a strange behavior, If I initially hit the first tab item and move further in the navigation, it preserve and restore the state further.
One more thing, when I run the application on the simulator by hitting stop and play button, it shows the preserve view for few seconds and come back to the custom tab bar.
Any help would be appreciated.
My Tabbar code is
// encodeRestorableStateWithCoder is called when the app is suspended to the background
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
NSLog(#"ParentViewController: encodeRestorableStateWithCoder");
[coder encodeObject:theNavigationController forKey:#"RootNav"];
[coder encodeObject:ssTodayNaVController forKey:#"TodaysCallNavEncode"];
// remember our children view controllers
[coder encodeObject:self.ssDasboardVC forKey:#"DashboardChild"];
[coder encodeObject:self.ssMessageVC forKey:#"MessageChild"];
[coder encodeObject:self.ssSearchCustomerVC forKey:SEARCH_CUSTOMER_SCENE];
[coder encodeObject:self.ssTodaysCallVC forKey:TODAYS_SCENE];
// remember the segmented control state
[coder encodeInteger:self.tabBar.mSelectedIndex forKey:#"selectedIndex"];
[super encodeRestorableStateWithCoder:coder];
}
// decodeRestorableStateWithCoder is called when the app is re-launched
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
NSLog(#"ParentViewController: decodeRestorableStateWithCoder");
theNavigationController=[coder decodeObjectForKey:#"RootNav"];
ssTodayNaVController=[coder decodeObjectForKey:#"TodaysCallNavEncode"];
self.tabBar.mSelectedIndex = [coder decodeIntegerForKey:#"selectedIndex"];
[[NSNotificationCenter defaultCenter]postNotificationName:TABBUTTON_NOTIFICATION object:[NSNumber numberWithInteger:self.tabBar.mSelectedIndex]];
[self.tabBar reloadData];
[super decodeRestorableStateWithCoder:coder];
}
And if I print the saved controllers with this method, it prints but doesn't save
- (UIViewController *)application:(UIApplication *)application
viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
coder:(NSCoder *)coder {
// return various navigation controllers here.
// actual view controlers will each be returned in their own classes
SCLogNotice(#"Saved Controllers are %#",identifierComponents);
return nil;
}
Cheers
Related
I want to know how I can get to know when a viewController appears, disappears from the main window from the UIApplication. I don't want to put code in each and every UIViewController, but observe lifecycle of each viewcontroller from the UIApplication.
Every view controller has a life cycle. So every view controller has separate life cycle method. So you have to put code each and every UIViewController. In app delegate we check the application state.
The state's are:
Active state
Inactive state
Background state
Not Running state
Suspended state
Delegate Method:
application:didFinishLaunchingWithOptions:
applicationWillResignActive:
applicationDidBecomeActive:
applicationDidEnterBackground:
applicationWillEnterForeground:
applicationWillTerminate:
View Controller Life cycle method:
-(void)viewDidLoad:(BOOL)animated{
[super viewDidLoad:animated];
}
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
}
-(void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
}
I have a tabbed application with 2 storyboards. In the 2nd storyboard I have a restoration-ID.
I implemented the following in the AppDelegate:
-(BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
return YES;
}
-(BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
return YES;
}
and this in my SecondViewController:
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[coder encodeObject:self.myTextView.text forKey:#"unsavedText"];
[super encodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
self.myTextView.text=[coder decodeObjectForKey:#"unsavedText"];
[super decodeRestorableStateWithCoder:coder];
}
But when i go to Home with iOS simulator , stop the running application and restart, the TextView doesn't restore text, my application starts in a first tab.
You may have missed assigning a restoration ID elsewhere in your view hierarchy.
Did you also change your AppDelegate from -application:didFinishLaunchingWithOptions: to application:willFinishLaunchingWithOptions:?
There are some useful state restoration tools available at the Downloads for Apple Developers page.
Search for restoration to find a debug profile which logs your app's state restoration to the console, as well as the restorationArchiveTool to dump the state restoration data in human-readable format.
I've got an iPhone app that I've made, that on one view has a UIDatePicker.
When you initially launch the app - and the view first loads; inside the viewDidLoad I have the UIDatePicker get set to the current date/time. It works fine.
Now if the user minimizes the app and does other things (but does not kill the app) and then goes back to the app, the date/time does not update when you go back to that view.
I'm wondering how I would go about making it 'refresh' that UIDatePicker any time the view is loaded (for example, when you go back to it after it's already been opened but is sitting in the background).
Any thoughts?
If there's no quick/easy way - I also considered creating a time related variable when the UIDatePicker loads initially - then when it is reloaded having it check to see if more than 10 minutes had passed since the last view. If so, then it would set the UIDatePicker to current date/time.
Any ideas?
Your view did load could look something like this
- (void)viewDidLoad {
[super viewDidLoad];
// listen for notifications for when the app becomes active and refresh the date picker
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(refreshDatePicker) name:UIApplicationDidBecomeActiveNotification object:nil];
}
Then in your viewWillAppear:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// refresh the date picker when the view is about to appear, either for the
// first time or if we are switching to this view from another
[self refreshDatePicker];
}
And implement the refresh method simply as:
- (void)refreshDatePicker {
// set the current date on the picker
[self.datepicker setDate:[NSDate date]];
}
This will update your date picker in both cases, when the view is switched from another view to this view while the application is open, and when the app is backgrounded and comes to the foreground with that view already open.
You should be able to set the date in the viewWillAppear method. That method is called each time the view will appear on screen.
- (void) viewWillAppear: (BOOL) animated
{
[super viewWillAppear:animated];
// update the date in the datepicker
[self.datepicker setDate:[NSDate date]];
}
I've seen many conflicting answers that seem to be situation dependent, but I haven't figured out one that works for me. I'm building a tabbed application in Storyboard, and I want to save the state of a view controller inside one tab that lives inside a navigation controller. It has dynamically created objects (labels and pictures) that I want to preserve when the app is shut down.
Thus far, I have the following in AppDelegate.m:
-(BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder {
return YES; }
-(BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder {
return YES; }
and in my viewController.m file:
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[coder encodeObject:self.view forKey:#"view"];
[super encodeRestorableStateWithCoder:coder]; }
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder {
self.view = [coder decodeObjectForKey:#"view"];
[super decodeRestorableStateWithCoder:coder]; }
I've also assigned RestorationID's to UITabBarController, the navigation controller, and the view controller in question.
Right now, if I minimize and restore, data is preserved, but if I stop and restart using xcode, it's lost. What am I missing?
Try to run an app, push the Home button twice to go to the app switcher, swipe your app away to close it and run it by clicking the icon on home screen (not from Xcode!). Is now everything ok?
I suppose when you run your app from Xcode it not just relaunches it, but reinstalls it, so that is not exactly what you need.
I read in the documentation that the #property(nonatomic, copy) NSString *restorationIdentifier is capable of preserving the state of an UIImageView properties such as position, angle, etc. I tried adding the methods
-(BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
return YES;
}
-(BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
return YES;
}
to the view controller. I have set the restoration ID of the view controller as #"myFirstViewController in the IB.
I have added the following methods to the view controller as well.
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[coder encodeObject:_myImageView.image forKey:#"UnsavedImage"];
[super decodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
_myImageView.image = [coder decodeObjectForKey:#"UnsavedImage"];
[super encodeRestorableStateWithCoder:coder];
}
Am i supposed to add the first two methods in the appDelegate or the view controller?
The UIImageView is not getting preserved. What is wrong here?
To make the state preservation and restoration work there are two steps that are always required:
The App delegate must opt-in
Each view controller or view to be
preserved/restored must have a restoration identifier assigned.
You should also implement encodeRestorableStateWithCoder: and decodeRestorableStateWithCoder: for views and view controllers that require state to be saved and restored.
Add the following methods to the view controller of your UIImageView.
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
[coder encodeObject:UIImagePNGRepresentation(_imageView.image)
forKey:#"YourImageKey"];
[super decodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
_imageView.image = [UIImage imageWithData:[coder decodeObjectForKey:#"YourImageKey"]];
[super encodeRestorableStateWithCoder:coder];
}
State preservation and restoration is an optional feature so you need to have the application delegate opt-in by implementing two methods:
- (BOOL)application:(UIApplication *)application shouldSaveApplicationState:(NSCoder *)coder
{
return YES;
}
- (BOOL)application:(UIApplication *)application shouldRestoreApplicationState:(NSCoder *)coder
{
return YES;
}
Useful article about state preservation:
http://useyourloaf.com/blog/2013/05/21/state-preservation-and-restoration.html