I have a tab bar in my application and it has a "More" tab because there are more than five tabs.
This "More" tab is generated automatically and therefore I thought that it would all work "out of the box" but when I tried going to the "Edit" menu, substitute an icon on the bar with one in the "More" view, it was not saved next time I launced the application.
How can I let the user save this setting?
As futureelite7 said, that is the way to go. If you need help, this is how we do it:
- (void) tabBarController:(UITabBarController *)tabBarCtroller
didEndCustomizingViewControllers:(NSArray *)viewControllers
changed:(BOOL)changed {
NSUInteger count = tabBarCtroller.viewControllers.count;
NSMutableArray *tabOrderArray = [[NSMutableArray alloc] initWithCapacity:count];
for (UIViewController *viewController in viewControllers) {
NSInteger tag = viewController.tabBarItem.tag;
[tabOrderArray addObject:[NSNumber numberWithInteger:tag]];
}
[[NSUserDefaults standardUserDefaults] setObject:tabOrderArray forKey:#"savedTabOrder"];
[[NSUserDefaults standardUserDefaults] synchronize];
[tabOrderArray release];
}
And in your applicationDidFinishLaunching
NSArray *initialViewControllers =
[NSArray arrayWithArray:self.tabBarController.viewControllers];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *tabBarOrder = [defaults arrayForKey:#"savedTabOrder"];
if (tabBarOrder) {
NSMutableArray *newViewControllers =
[NSMutableArray arrayWithCapacity:initialViewControllers.count];
for (NSNumber *tabBarNumber in tabBarOrder) {
NSUInteger tabBarIndex = [tabBarNumber unsignedIntegerValue];
[newViewControllers addObject:[initialViewControllers objectAtIndex:tabBarIndex]];
}
self.tabBarController.viewControllers = newViewControllers;
}
You need to roll your own solution. Use the UITabBarControllerDelegate's
tabBarController:willEndCustomizingViewControllers:changed:
to capture the time after the user finishes editing the icons. Then you can save the user's setting (e.g. assign a number for each tab, and save it into an array etc.) and load it the next time the program launches.
You may use
[NSUserDefaults standardUserDefaults];
for a quick way to save such settings.
Related
I have a main window where i use a setting button used with navigation controller. I have a view controller where i kept my UISwitch. My UISwitch works well with its functionality but when i go back the switch turns "OFF" automatically.
I tried using these,
[[NSUserDefaults standardUserDefaults] setBool:startTrackingButton.on forKey:#"switchValue"];
[[NSUserDefaults standardUserDefaults] synchronize];
but then the same problem exists. Since i have only one view controller i cant retrieve the NSUserDefaults.
Any Suggestions?
When you setup your view, either in the init method or in viewDidLoad do something like this.
[startTrackingButton setOn:[[NSUserDefaults standardUserDefaults] boolForKey:#"switchValue"]]
Then every time you switch is toggled save the state of the switch
[[NSUserDefaults standardUserDefaults] setBool:startTrackingButton.on forKey:#"switchValue"];
[[NSUserDefaults standardUserDefaults] synchronize];
"Since i have only one view controller i cant retrieve the NSUserDefaults."
You can retrive the user defaults in the viewDIdLoad to read the switch position in that one view
So if you have only one viewController
save to NSSsuserDefaults as you are doing
In viewDidLoad read the switch state to retrive the position of the switch
save switch state in your switch action method
if (sender == _switch) {
BOOL mySwitchValue = [ sender isOn ];
NSString *tmpString = mySwitchValue ? #"1" : #"-1" ;
NSUserDefaults *myNSUD = [NSUserDefaults standardUserDefaults];
[ myNSUD setObject:tmpString forKey: #"mySwitchValueKey" ];
[ myNSUD synchronize ];
//save a key to read switch state in another view if required
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setBool:self.barCodeSwitch.on forKey:#"switch1"];
[userDefaults synchronize];
}
}
Read the saved switch position in viewDidLoad
NSUserDefaults *myNSUD = [NSUserDefaults standardUserDefaults];
NSString *tmpString = [ myNSUD stringForKey: #"mySwitchValueKey"];
BOOL mySwitchValue = NO; // or DEFAULT_VALUE on/off
if (tmpString != nil) {
mySwitchValue = ( [ tmpString intValue ] == 1 );
}
[_autocompleteSwitch setOn: mySwitchValue];
So I have an app that lets you put in a title and an author on the front page, then you hit enter and it will go into the actual features of the app. I want to save the data with NSUserDefaults, so that when they click the enter button, it saves it *AND goes into the next view. I have it setup with the storybord already to go into the next view, but when I use this code:
-(IBAction)enter:(id)sender {
titleString = [[NSString alloc] initWithFormat:[title text]];
[title setText:titleString];
NSUserDefaults *titleDefault = [NSUserDefaults standardUserDefaults];
[titleDefault setObject:titleString forKey:#"stringkey"];
authorString = [[NSString alloc] initWithFormat:[author text]];
[title setText:authorString];
NSUserDefaults *authorDefault = [NSUserDefaults standardUserDefaults];
[authorDefault setObject:authorString forKey:#"stringkey2"];
}
It will always crash when you hit the button. I have all the NSStrings defined and such, so I don't see what the problem is. I also have it loading with:
title.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"stringkey"];
author.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"stringkey2"];
Under the viewdidload, so can I have some help as to why this wouldn't work?
Just to optimize your -enter:method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:title.text forKey:#"stringkey"];
[defaults setObject:author.text forKey:#"stringkey2"];
[defaults synchronize]; // this will store them instantly!
For the crash: can you please provide us with the exact crash log? Maybe your Button is linked to an unknown selector...
First, there are a few questions about this: here, here. Try searching around first, and at least let people know why the duplicate questions you found didn't work for you.
Secondly, I think you might benefit from adding a synchronize. Use this:
titleString = [[NSString alloc] initWithFormat:[title text]];
[title setText:titleString];
NSUserDefaults *titleDefault = [NSUserDefaults standardUserDefaults];
[titleDefault setObject:titleString forKey:#"stringkey"];
[titleDefault synchronize];
authorString = [[NSString alloc] initWithFormat:[author text]];
[author setText:authorString];
NSUserDefaults *authorDefault = [NSUserDefaults standardUserDefaults];
[authorDefault setObject:authorString forKey:#"stringkey2"];
[authorDefault synchronize];
I also changed the [title setText:authorString]; line to [author setText:authorString];. I do, however, think it is a bit redundant the way you are allocating the NSStrings to the value of the text fields and then setting the text back to the value of the string you created. I don't get the need. Anyway, hope this helps.
I am making an app in which the user can select a song in a settings tab and have this played in a different view on demand. I want it so that this item can be stored if the user is to shut the app and reopen it another time.
I have managed to allow the user to select and store a song in with:
-(IBAction)showMediaPicker:(id)sender{
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes: MPMediaTypeAny];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = NO;
mediaPicker.prompt = #"Select Alarm Sound";
[self presentModalViewController:mediaPicker animated:YES];
}
- (void) mediaPicker: (MPMediaPickerController *) mediaPicker didPickMediaItems: (MPMediaItemCollection *) mediaItemCollection {
[self dismissModalViewControllerAnimated: YES];
settingsData.selectedSong = mediaItemCollection;//Object of type MPMediaItemCollection
but I want the user to have to do this every time they use the app.
I have tried using NSUserDefaults:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:settingsData.selectedSong forKey:#"alarmSoundKey"];
[defaults synchronize];
but get the error:
* -[NSUserDefaults setObject:forKey:]: Attempt to insert non-property value '' of class 'MPMediaItemCollection'. Note that dictionaries and arrays in property lists must also contain only property values.
What are my options please? Not really sure how to tackle this one...
SOLUTION -
I can't answer my own questions yet so I'll put it up here:
I HAVE FOUND MY OWN SOLUTION TO THIS:
First convert/encode the MPMediaItemCollection to an NSData Object and slam store it using NSUserDefaults using:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:mediaItemCollection];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:data forKey:#"someKey"];
[defaults synchronize];
From there, you can decode and use anywhere else in your app....
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *data = [defaults objectForKey:#"someKey"];
MPMediaItemCollection *mediaItemCollection = [NSKeyedUnarchiver unarchiveObjectWithData:data]
Hope that is some help to someone. Spread the word, this hasn't been covered enough. Have literally been working on this problem for about 4 hours...
You can only store property list values in NSUserDefaults. Since MPMediaItemCollection conforms to NSCoding you could use an NSKeyedArchiver to store it instead.
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSKeyedArchiver_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40003672
You then use NSKeyedUnarchiver to read it back out of the file later.
You can also use the MPMediaItemPropertyPersistentID property. You can form a query to retrieve the item from the iPod library when your application next launches, and gracefully handle things like when the user decides to remove the song from their library.
Please help! I'm a newbie to programming and I'm having the following trouble. I am trying to write my first iphone app and I would like it to do the following.
When the app launches user enters name, presses button and goes to new view. Their name is saved to file and used through out the app. That much I have managed.
I would like the app to check to see if there is a saved file when it is launched and go directly to second view instead of the first view. I'm have search for days looking for an answer and I'm still not sure how to do this.
At the risk of seeming stupid do I use an IF statement and how do I write it. Please help.
Thanking you in advance.
You have to use NSUserDefaults for storing the user name and pass words. If you want to store more data's, have to use plist(Documents Directory) or core data or SQLite.
// Store the data
[[NSUserDefaults standardUserDefaults] setObject:#"yourPasswordString" forKey:#"YourKey"];
// Retrieve the data
NSString *passWord = [[NSUserDefaults standardUserDefaults] objectForKey:#"YourKey"];
Once you retrieved the data, you have to check the conditions like,
if(passWord == nil)
{
//load first view
}
else
{
// load second view
}
Thanks!
if you're using NSUserDefaults to save it then all you have to do is try reading the value into a string, then check if it is nil, if it is, then the files isn't there and you would load your first view, if it was, then load your second view.
NSString *tempStr = [[NSUserDefaults standardUserDefaults] objectForKey:#"yourKey"];
if(tempStr == nil)
{
//load your first view
}
else
{
// load your second view
}
You need to read your key back out in order to test if it is nil, the way you are doing this, you will never be nil and will always use the else choice, you need to set your object elsewhere, probably in the if statement.
-(IBAction)LogInButton:(id)sender
{
NSString *tempStr = [[NSUserDefaults standardUserDefaults] objectForKey:#"UserName"];
if (tempStr == nil || [tempStr isEqualToString:""])
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:Name.text forKey:#"UserName"];
[prefs synchronize];
ClubSearchViewController *CSearch = [[ClubSearchViewController alloc]initWithNibName:#"ClubSearchViewController" bundle:Nil];
[self presentModalViewController:CSearch animated:YES];
}
else
{
SearchMenu *SMenu = [[SearchMenu alloc]initWithNibName:#"SearchMenu" bundle:nil];
[self presentModalViewController:SMenu animated:YES];
}
}
-(IBAction)LogOutButton:(id)sender
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:#"" forKey:#"UserName"];
[prefs synchronize];
}
I have this in my app delegate applicationDidFinishLaunching method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if([defaults objectForKey:#"AcceptTC"] == nil){
NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:#"NO" forKey:#"AcceptTC"];
[defaults registerDefaults:appDefaults];
}
and I have this in my RootViewController viewDidLoad method:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if(![defaults boolForKey:#"AcceptTC"]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Notice" message:#"By using this application you agree to be bound by the Terms and Conditions as stated within this application." delegate:self cancelButtonTitle:#"No Deal" otherButtonTitles:#"I Understand",nil];
[alert show];
[alert release];
}
and my alert view delegate does this:
if(buttonIndex == 0){
exit(0);
}
else{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:#"YES" forKey:#"AcceptTC"];
}
However when I click "I understand" (button index 1) and then restart the application I still see the alert view! Even though I've definiely set the value to YES.
I have no idea how to change this. :( I only want it to show the first time a user starts the application - i don't want to keep showing it every time they want to use it.
Thanks
In my application I'm using NSUserDefaults with a bool, works fine.
When the first ViewController loads, it will do:
BOOL terms = [[NSUserDefaults standardUserDefaults] boolForKey:#"termsaccepted"];
if (!terms) {
[self presentModalViewController:disclaimerViewController animated:YES];
}
Within the disclaimer view, after the button has been tapped:
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"termsaccepted"];
[[NSUserDefaults standardUserDefaults] synchronize];
I think you're missing the "synchronize" part. However I find using a bool more streamlined, too.
Maybe you need to call synchronize on the defaults to save the changes to disk?
Concering registerDefaults:
The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file.
// Load default defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary \
dictionaryWithContentsOfFile:[[NSBundle mainBundle] \
pathForResource:#"Defaults" ofType:#"plist"]]];
Code taken from this SO answer.
Another blog article about NSDefaults:
http://retrodreamer.com/blog/2010/07/slight-change-of-plan/