hi i want create an application and my app remember last user action ,, it means user find himself in the same page as he was last time he ran the application .
how could implement that ?
you can use the NSUserDefaults to store some variable for your application to retrieve them after a close of the application.
For exemple:
// Set the name of the view
[[NSUserDefaults standardUserDefaults] setObject:#"viewName" forKey:#"lastViewName"];
To retrieve the last action of the user:
// Retrieve the last view name
NSString *lastViewName = [[NSUserDefaults standardUserDefaults] stringForKey:#"lastViewName"];
But you can add other than a string.
Edit:
define some constant like that on a header file:
#define HOME_VIEW 0
#define VIEW1 1
#define VIEW2 2
When a view is load you store the current constant view to your standardUserDefaults. For example the view1:
- (void)viewDidLoad {
[super viewDidLoad];
// Set the name of the view
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:VIEW1] forKey:#"lastView"];
}
When you application did load you retrieve your constant and you load your appropriate view:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Retrieve the last view name
NSInteger constantView = [[NSUserDefaults standardUserDefaults] integerForKey:#"lastView"];
switch(constantView) {
case HOME_VIEW : //load your UIViewController
break;
case VIEW1 : // load your VIEW1
break;
//...
}
}
I haven't tested this code, but it's something like that to do.
Use the Application Delegate and override the method:
- (void)applicationWillTerminate:(UIApplication *)application
In here you can save which view was last visible and what state it was in (and if necessary other views as well) and persist it.
Then when you start your application again you load the saved state and use it to determine which view should be visible.
There are a few ways to persist data in the iPhone SDK so please read this guide for more information on how to do that.
Related
I'm working in a book app, and I want to use a page marker to help the user remember where he stopped reading. So I have added a bar button with an image ("mark.png"). A mark view will be added to the chapter view when it is tapped, and if it is been tapped again the mark will be removed from the superView. I'm using this code:
- (void)showMark {
if (![markView superView]) {
[chapterOne addSubView:markView];
}
else {
[markView removeFromSuperView];
}
}
It is working fine but ever time I exit the app and rerun again the mark view is gone, so how can I keep it?
I found some forums talking about the NSUserDefaults to save actions but I really don't know how to use it with my code. Any help will be appreciated.
You can't use NSUserDefaults to save entire views, but you can save the parmeters that would help determine where the bookmark should be set.
For example if you are basing the book mark by a page number you could save the page to the NSUserDefaults when the user leaves the view controller.
Example:
[[NSUserDefaults standardUserDefaults] setInteger:23 forKey:#"bookMarkPage"];
[[NSUserDefaults standardUserDefaults] synchronize];
When the user comes back the the view controller you can check if there is a bookmark:
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"bookMarkPage"] != nil) {
int pageNumber = [[NSUserDefaults standardUserDefaults] objectForKey:#"bookMarkPage"];
[self setBookmarkForPage:pageNumber];
}
Possible bookmark construction method:
- (void) setBookmarkForPage:(Int)pageNumber {
// run through the logic of placing the bookmark on the correct page
}
You can use whatever parameters you need to determine where to place the book mark. When a user originally places the bookmark what parameters you use to figure out where to place the bookmark? Try to use the same logic for when a user first places the bookmark.
I don't know exactly what you want to save, but you can just about any kind of data with NSUserDefaults, like this:
[[NSUserDefaults standardUserDefaults] setInteger:123 forKey:#"CurrentPageNumber"];
When you have set all the values you need, save them:
[[NSUserDefaults standardUserDefaults] synchronize];
Then when app opens, check to see if the value is set. If it is draw your marker.
if ([defaults valueForKey:#"CurrentPageNumber"] != nil) {
int pageNumber = [defaults valueForKey:#"CurrentPageNumber"]
if (pageNumber == 1) {
[chapterOne addSubView:markView];
}
else {
[markView removeFromSuperView];
}
}
The other answers state great ways to work around the issue. Just to clarify, UIView or any of the derivatives are not supported for NSUserDefaults. NSUserDefaults allows just primitive object types (NSString, NSNumber, NSArray, and NSDictionary). There might be one or two I missed. But UIView or UIViewController object types can't be saved in NSUserDefaults.
Can i add some images(3) on scroll view to flip them as page controller and include them with the splash, so that they only appear when someone install's the application or when newer version is installed... is their a way of doing it programmatically instead of adding xib .. any help ... coding will be much appreciated .. Thanks in advance
You cant show them along with the Default launch image. You can only show a static image there. But when the user is using the app for the first time, you can show this particular view once the app is launched and then from second time onwards you can disable it. You can set a property in NSUserDefaults for this once you have shown this view to the user so that from second time onwards, user wont see it again.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *string = [defaults objectForKey:#"didShowCustomView"];
if ([string isEqualToString:#"YES"]) {
//show the custom view
//once it is shown, set the value in user defaults
[defaults setObject:#"YES" forKey:#"didShowCustomView"];
[defaults synchronize];
}
This one worked for me as NSUserDefault really did the trick ..
But i had to put the loop in reverse for working it out in my very first view controller i did like this ...
- (void)viewDidLoad {
NSString *type = [[NSUserDefaults standardUserDefaults] objectForKey:#"myText1"];
if([type isEqualToString:#"Kill"]) {
// put the method of view like images,buttons or anything you have in your method
// for loading on to the first view that you want to run after splash
}
if(!type) {
type = #"Kill";
[[NSUserDefaults standardUserDefaults] setObject:type forKey:#"myText1"];
// put the code for your splash image here ..
}
}
So now the splash will only run once the app get's installed as a fresh copy ..
This one Helped me out ... if any one looking for the same thing can try my code above ..
Thank you
I changed UINavigationBar's height by changing its frame.
But it's height restores to its original size if I send application to background and then open it again. How can I fix that?
You could write the frame to a resource file like a plist or XML file. Then load the plist in the app delegate file in either the -(void)applicationWillEnterForeground:(UIApplication *)application' or-(void)applicationDidBecomeActive:(UIApplication *)application`. I believe you could also use NSUserDefaults:
NSUserDefaults *frameSize = [NSUserDefaults standardUserDefaults];
//Put frame size into defaults
[sharedDefaults setObject:navigationBar.frame forKey:#"frame"];
[sharedDefaults synchronize];
Then in the aforementioned App Delegate methods, you could do something like this:
self.viewController.navigationController.frame = [sharedDefaults objectForKey:#"frame"];
Hope this helps and if it did, remember to up vote.
-----------EDIT------------
If you look at this question iOS selected tab, it tells you how to determine which tab is selected. What they basically say is to first add self.tabController.delegate = self in the app delegate, and make sure that the app delegate and the view controller with the tab bars conform to the UITabBarControllerDelegate protocol. Then in your View Controller file with the tab bars, you can use this method defined in the protocol:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if (tabBarController.selectedIndex == 0) {
//The 0 is the first tab, but you can replace that with any other tab's index
//Here you say that when said tab is selected, the navigation controller's frame is the stored length.
self.navigationController.frame = [sharedDefaults objectForKey:#"frame"];
}
else{
self.navigationController.frame = CGRectMake(frame, for, other, tabs);
}
}
I have a couple of images that I would like to display the first time a user runs the app to show the user how to effectively use the app. What is the best method to do this sort of thing?
Thanks
The easiest way is to set a flag that says you have shown the app instructions. You can store them in user defaults.
So you would put something like this in your app delegate.
static NSString* const kAppHasShownStartupScreen = #"kAppHasShownStartupScreen";
BOOL hasShownStartup = [[NSUserDefaults standardUserDefaults] boolForKey:kAppHasShownStartupScreen];
if(hasShownStartup)
{
window.rootViewController = //your normal startup view controller
}
else
{
window.rootViewController = //your new view controller with instructions
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:kAppHasShownStartupScreen];
}
Create some boolean values to store in NSUserDefaults or in Core Data that represent whether or not the user has viewed the 'tutorial'. Show the images by loading them into UIImageView's and adding them as subviews if the flag is false. Set the flag to true after they have viewed the images.
You can accomplish this functionality by using a BOOL value in NSUserDefaults:
#define appdb ((NSUserDefaults *)[NSUserDefaults standardUserDefaults])
if(![appdb boolForKey:#"applicationHasRunBefore"]) {
[appdb setBool:YES forKey:#"applicationHasRunBefore"];
[appdb synchronize];
...
// Do the tutorial
}
I have a function here that upon completing a single round, if your score is higher than either a default score entry or a newly placed high score then it will swap its data with your data and push everything else down. removing the last entry from the list. currently this is just one exchange and for functions sake I'm going to hard code it and then refactor it later.
My main problem is that when I set up a text input view to capture the players name execution continues immediately without the players input and crashes the game. I commented out the line that sets the text because I have a default value in place just in case any attempt that I try to make fails. How can I get Execution to wait for a moment while input is taken? Would I have to set up a delegate method? If so I'm still a bit confused by delegates. I could set it up to work but I don't understand it, so I wouldn't be able to do any other special custom tasks with it. I've worked on it for a while and got no further...
-(void)saveData:(ScoreKeep *)stats{
NSMutableDictionary *swap = [[NSMutableDictionary alloc]init];//used for swaping entries
NSString *filePath = [self pathOfFile];
NSLog(#"Writing to %#", filePath);
if ([[NSFileManager defaultManager]fileExistsAtPath:filePath]) {
NSLog(#"Loading previous dictionary to save...");
dataDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
if ([dataDictionary objectForKey:#"1"]) {
NSMutableDictionary *highScore = [dataDictionary objectForKey:#"1"];
if ([stats.score intValue] > [[highScore objectForKey:#"SCORE"] intValue]) {
NSLog(#"You Win! score: %# highscore: %#", stats.score,[NSNumber numberWithInt:[[highScore objectForKey:#"SCORE"] intValue]] );
stats = [[ScoreKeep alloc] initWithNibName:#"Scorekeep" bundle:nil];
NSLog(#"Setting up name entry");
[self.view addSubview:stats.view]; //New view is added so that the player can input data(Assume it is complete);
//stats.nameTag = setName.nameTag;//This line is executed before the new view is dismissed causing an error to occur
[stats setupDictionary]; // It just goes down hill from here if the previous line is uncommented
[dataDictionary setObject:stats.sComponents forKey:#"1"];
}else {
NSLog(#"You Lose: %# highscore: %#", stats.score,[NSNumber numberWithInt:[[highScore objectForKey:#"SCORE"] intValue]] );
}
NSLog(#"Got first place entry");
}else {
NSLog(#"Initilizing Score");
}
}else{
NSLog(#"Creating new dictionary to save...");
dataDictionary = [[NSMutableDictionary alloc]init];
}
[dataDictionary writeToFile:filePath atomically:YES];
}
Help would greatly be appreciated. If more information is needed I'd be happy to provide.
by the way ScoreKeep is an object that contains a dictionary and a function to create a dictionary such that it can set any values I need and package them into sComponents(the dictionary to be entered into the main savefile)
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#class omphalosUtility;
#pragma mark -
#pragma mark Saving data
#pragma mark -
static inline void poop(){
NSLog(#"POOP");
}
I'm going to try making a utility file that works independently of the app so that I Can update files and perform other universal operations such as saving when needed. Its a step in a direction that i'd like to take.
If i get it right, (The code is really nasty, man...) your problem is that you are trying to present a View Controller with the wrong way.
Correct me if i'm wrong, is ScoreKeep is a ViewController? if so, you have to name it properly. that's for a start.
Second, you cant present another view controller only by adding its "view" property to the current view controller's View Hierarchy. that way the view will not respond properly to the events.
the correct way to to what you'r trying to do is by presenting the ScoreKeep ViewController modally.
there is no other right way to do this without using delegation. you will have to acquire this technique.
Your view controller that responsible for getting the name from the user need to have a way to tell it's master view controller that the user entered a name. and that is achieved through delegation.
What you should do:
Basically you create a protocol called something like "NamePrompterViewControllerDelegate"
that will have at least one method that will be called when the user will done entering his name.
Your ScoreKeepViewController should have an instance variable that implemented the protocol (Look at the apple documentation on protocols for assistance)
Your main view controller (the one that contains the method you added) then should implement the protocol you created, and set itself as the delegate of ScoreKeep like that:
stats = [[ScoreKeep alloc] initWithNibName:#"Scorekeep" bundle:nil];
stats.delegate = self;
For more info on presenting and dismissing ViewControllers modally you should read the documentation at Apple Documentation
I hope i helped you, there is just a lot to cover and it hardly can be done by writing an answer.
Feel free to ask more for clearance.