should variable be released or not? iphone-sdk - iphone

I have the following piece of code from a book.
There is this function loadPrefs where the NSString *userTimeZone is being released before the end of the function.
Why? The string was not created with alloc and I assume that the stringForKey function returns an autoreleased NSString. Is this an error or am I missing something? Is it an error in the book? (I new into objective-C)
In the documentation for stringForKey the only thing it mentions is:
Special Considerations
The returned
string is immutable, even if the value
you originally set was a mutable
string.
The code:
- (void) loadPrefs {
timeZoneName = DefaultTimeZonePref;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *userTimeZone = [defaults stringForKey: TimeZonePrefKey];
if (userTimeZone != NULL)
timeZoneName = userTimeZone;
[userTimeZone release];
show24Hour = [defaults boolForKey:TwentyFourHourPrefKey];
}
Thanks!!!!

You're right. There are two things wrong with this code: it's releasing the string from stringForKey: improperly, and it's not retaining userTimeZone when it assigns the value to an instance variable.
Here's a better attempt:
- (void) loadPrefs {
[timeZoneName release]; // In case there was a previous value
timeZoneName = DefaultTimeZonePref; // ASSUMPTION: DefaultTimeZonePref is a constant
// And thus doesn't need retain/release.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *userTimeZone = [defaults stringForKey: TimeZonePrefKey];
if (userTimeZone != NULL) {
timeZoneName = [userTimeZone retain];
}
show24Hour = [defaults boolForKey:TwentyFourHourPrefKey];
}
And don't forget to release timeZoneName in dealloc.

Related

Storing Multiple value in MutableArray with different value

I have a button which on click I store the index of the current quotes into an array.
The problem is that it is overwriting the same object. How can I change it with different object of the NSNumber to store in the NSMutableArray?
[someButton setImage:[UIImage imageNamed:#"add_favoritegold.png"] forState:UIControlStateHighlighted];
NSUserDefaults *favoriteQuotes = [NSUserDefaults standardUserDefaults];
NSMutableArray *ListOfIndex= [[NSMutableArray alloc] init];
//Want to change with diffrent objecy
**NSNumber* Wrapped = [NSNumber numberWithInt:index];**
[ListOfIndex addObject:Wrapped];
int xOut = [[ListOfIndex lastObject] intValue];
NSLog(#"%d",xOut);
[favoriteQuotes setObject:ListOfIndex forKey:#"Indexes"];
Try this
- (void)saveFavouriteQuoteIndex:(NSUInteger)index
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *savedQuoteIndexes = [[defaults objectForKey:#"Indexes"]mutableCopy];
if (!savedQuoteIndexes) {
savedQuoteIndexes = [NSMutableArray array];
}
NSNumber *indexNumber = #(index);
if (![savedQuoteIndexes containsObject:indexNumber]) {
[savedQuoteIndexes addObject:indexNumber];
[defaults setObject:savedQuoteIndexes forKey:#"Indexes"];
[defaults synchronize];
}
}
You are saving ListOfIndex with key as Indexes.
So, for the next whatever value, it will replace previous value having key Indexes.
EDIT:
Read the array
NSArray *readArray=favoriteQuotes[#"Indexes"];
Add your new value into this same array.

NSUserDefaults: returning integer, not returning NSArray

I'm trying to store both an integer and NSArray with the NSUserDefaults, but I only can correctly retrieve the integer. When I try to recover the NSArray, it returns an empty array.
I start with a custom class XMLParser.m.
//XMLParser.m
//NSArray 'stored' correctly contains 10 data objects. 'stored' is an NSArray property of the XMLParser class
numberOfEvents = [stored count];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:stored forKey:#"eventsList"];
[defaults setInteger:numberOfEvents forKey:#"numberOfEvents"];
[defaults synchronize];
But when I try to access the data in another class, ie. my AppDelegate, I get an empty NSArray
//myApplicationAppDelegate.m
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int value = [defaults integerForKey:#"numberOfEvents"]; //returns 10
parsedEventsList = [defaults arrayForKey:#"eventsList"]; //parsedEventsList is an NSArray property of myApplicationAppDelegate class
int value2 = [parsedEventsList count]; //***returns 0***
I've even tried using
[defaults objectForKey:#"eventsList"]
and it's still returning nothing.
Thoughts? Thanks!
All of your objects in the stored array must be property list objects (i.e. instances of NSData, NSDate, NSNumber, NSString, NSArray, or NSDictionary).
Your problem appears to be that your objects are all custom.
I think you may have forgotten to make them serializable if you add code similar to this (for each of your objects) then it should work
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeObject:self.obj1 forKey:#"obj1"];
[encoder encodeObject:self.obj2 forKey:#"obj2"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if((self = [super init])) {
//decode properties, other class vars
self.obj1 = [decoder decodeObjectForKey:#"obj1"];
self.obj2 = [decoder decodeObjectForKey:#"obj2"];
}
return self;
}

NSMutableArray in NSUserDefaults

I'm sorry for my bad english but i'm trying to explain with best words.
I have some problem when i'm trying to insert an NSMutableArray in NSUserDefaults ([NSUserDefaults setObject:forKey:]: Attempt to insert non-property value ')
My code to insert the array is as follows:
-(void)saveToUserDefaults:(NSMutableArray*)myArray
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSArray *array = [[NSArray alloc ] initWithArray:myArray];
if (standardUserDefaults)
{
[standardUserDefaults setObject:array forKey:#"MyArray"];
[standardUserDefaults synchronize];
}
}
My code to retrieve the array:
-(NSMutableArray*)retrieveFromUserDefaults
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *val = [[NSMutableArray alloc]init];
if (standardUserDefaults)
val = [NSMutableArray arrayWithArray:[standardUserDefaults arrayForKey:#"MyArray"]];
return val;
}
and in my code :
NSMutableArray :
series = [[NSMutableArray alloc]initWithObjects:nil];
//add some object inf my array...
Save my NSMutableArray :
[self saveToUserDefaults:series];
Retrieve my NSMutableArray :
series = [self retrieveFromUserDefaults];
I think it's not the best way to do this, so if anyone have ideas , it'll be helpful for me.
Thanks for reading.
Tommy
Only immutable NSArrays can be placed into defaults. Rather than placing a NSMutableArray there, convert to regular array using [NSArray arrayWithArray:] and place that one into defaults.
For retrieval, retrieve an NSArray and then use [NSMutableArray arrayWithArray:].
You can use following method to get the mutable object from immutable. It's not optimized and only implemented for NSArray and NSDictionary.
+ (id) GetMutable:(id)input {
id result;
if ([input superclass] == [NSArray class] || [input superclass] == [NSMutableArray class]) {
result = [[NSMutableArray alloc] initWithArray:input copyItems:YES];
for (int i = 0; i < [(NSMutableArray*)result count]; i++) {
[(NSMutableArray*)result replaceObjectAtIndex:i withObject:[Globals GetMutable:[(NSMutableArray*)result objectAtIndex:i]]];
}
} else if ([input superclass] == [NSDictionary class] || [input superclass] == [NSMutableDictionary class]) {
result = [[NSMutableDictionary alloc] initWithDictionary:input copyItems:YES];
NSArray *keys=[(NSMutableDictionary*)result allKeys];
for (int i = 0; i < keys.count; i++) {
[(NSMutableDictionary*)result setObject:[Globals GetMutable:[(NSMutableDictionary*)result objectForKey:[keys objectAtIndex:i]]] forKey:[keys objectAtIndex:i]];
}
}
else {
return input;
}
return result;
}
I hope this tutorial helps, who expect answer for this question.
-(void)saveToUserDefaults:(NSString*)myServerName uname:(NSString*)myUserName
pass:(NSString*)myPassword
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
if (standardUserDefaults) {
[standardUserDefaults setObject:myServerName forKey:#"ServerKey"];
[standardUserDefaults setObject:myUserName forKey:#"UserNameKey"];
[standardUserDefaults setObject:myPassword forKey:#"PasswordKey"];
[standardUserDefaults synchronize];
}
}
-(NSArray*)retrieveFromUserDefaults
{
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *serverName = nil;
NSString *userName = nil;
NSString *password = nil;
if (standardUserDefaults)
serverName = [standardUserDefaults objectForKey:#"ServerKey"];
userName = [standardUserDefaults objectForKey:#"UserNameKey"];
password = [standardUserDefaults objectForKey:#"PasswordKey"];
NSArray* credentials = [NSArray arrayWithObjects:serverName,userName,password, nil];
return credentials;
}
To Pass values
[self saveToUserDefaults:serverVariable uname:usernameVariable pass:passVariable];
To get Values
NSArray *result=[self retrieveFromUserDefaults];
Happy coding!!!
The contents of your array can only by plist valid objects: (NSString, NSNumber, NSDate, NSData, NSArray, or NSDictionary objects).
See documentation for NSUserDefaults setObject:forKey: and What is a Property List?
Your code needs a lot of clean up. Here is the simple and correct way to access standard user defaults:
The value you pass to your save method does not need to be mutable, although it can be. But since you are not mutating it inside your method, there's no need for it to be mutable. It just has to be not nil, which you'll check before saving:
-(void)saveToUserDefaults:(NSArray*)myArray
{
if (myArray) {
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
myDefaults[#"myArray"] = myArray;
}
}
Standard user defaults only returns non-mutable objects, which you can convert to a mutable copy using the "mutableCopy" method:
-(NSMutableArray*)retrieveFromUserDefaults
{
NSUserDefaults *myDefaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *val = [[NSMutableArray alloc] init];
val = [myDefaults[#"MyArray"] mutableCopy];
return val;
}

How to store a float in NSUserDefaults

I want to store a float value into NSUserDefaults.
I also need to check that the float value exists..if not I need to assign some value in it.
and retrieve it...for the above I have the below code but it gives me an error.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults boolForKey:#"HANDWRITING_SIZE_SLIDER"] == YES) {
self.sizeSlider.value = 10.0;
} else {
self.sizeSlider.value = [[NSUserDefaults standardUserDefaults] floatForKey:#"HANDWRITING_SIZE_SLIDER"]];
}
Thanks for any help
Use the NSNumber class for this and store it via the setObject:forKey: method so you can check if it exists.
I'd also suggest the usage of constants as keys:
#define HANDWRITING_SIZE_SLIDER #"HSS"
Your code should be along these lines:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:HANDWRITING_SIZE_SLIDER] == nil) {
//doesn't exist in NSUserDefaults, set to default value...
self.sizeSlider.value = 10.0;
} else {
self.sizeSlider.value = [[defaults objectForKey:HANDWRITING_SIZE_SLIDER] floatValue];
}
Somewhere else in your app, you'd set the value in NSUserDefaults like this:
float sizeSliderValue = ...
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:sizeSliderValue] forKey:HANDWRITING_SIZE_SLIDER];
Try this code:
-(IBAction)sliderAction:(id)sender
{
float sliderValue = [sender floatValue];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithFloat:sliderValue] forKey:#"keySliderValue"];
NSLog(#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"keySliderValue"]);
}

IPhone SDK Default NSUserDefaults

I have set up the user defaults to record a integer for a UISlider, the problem is that, if the user has only just installed the app then the integer is zero or NULL. Is there a way to detect if it = NULL with a integer?
heres my code i have so far:
-(void)awakeFromNib {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
senset = [prefs integerForKey:#"senset"];
senset = sensitivity.value;
}
- (IBAction) setSens {
senset = sensitivity.value;
}
- (IBAction) goBackopt {
{
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setInteger:senset forKey:#"senset"];
[prefs synchronize];
}
}
senset is the integer. i have tried this code, and it sets it to 25 on the first time, but then if i try and overwrite it, it wont work and keeps setting it to 25. :(
if ( [prefs integerForKey:#"senset"] == NULL ) {
senset = 25;
}
Please help :P
Harry
You should set a valid default value for each of your preferences. This value will be used when one has not been set by the user.
NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
[defaults setObject:[NSNumber numberWithInt:25] forKey:#"senset"];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
Just ask for objectForKey:. If it isn't set, it will return nil.
Your test doesn't work, because integerForKey: with an unset value will return 0, which is nil, which is NULL. The differences between them only exist to the compiler.
If zero is not a valid value in a normal usage case (i.e. your saved preference would never set this integer to zero), then you can check
if( [prefs integerForKey:#"senset"] == 0){
[prefs setInteger:25 forKey:#"senset"];
}
Edit: err, I suppose I have a question: when you try to overwrite it, are you setting an integer value(25) for your key (#"senset")? If not, then it will remain zero or nil, and everytime you check it will attempt to change your local senset variable to 25 again.