Set a new value to a NSString variable with a previous value - iphone

I'm developing an iOS application with latest SDK and XCode.
This is a simple question but I don't know how to do it because I don't want any memory leaks on my code.
I'm using ARC on my project and I have the following header declaration:
#interface UserPreferences : NSObject
{
NSUserDefaults* prefs;
}
#property (nonatomic, readonly) NSString* appLanguage;
// More code
- (void) setAppLanguage:(NSString *)appLanguage;
// More code
#end
And this is how I've implemented - (void) setAppLanguage:(NSString *)appLanguage;.
- (void) setAppLanguage:(NSString *)newAppLanguage
{
[prefs setObject:appLanguage forKey:APP_LANGUAGE_KEY];
appLanguage = [NSString stringWithString:newAppLanguage];
}
Is appLanguage = [NSString stringWithString:newAppLanguage]; correct?
I don't know it appLanguage will have a value when I set a new one to it.
Is my code correct?

Your code doesn't have any leaks; ARC automatically releases the previous value for appLanguage for you. I would write appLanguage = [newAppLanguage copy] rather than using stringWithString:, but the effect is the same.

Unless you've omitted some code, this won't work...
You've created an instance variable for NSUserDefaults, but have never instantiated it with a value. When you call [prefs setObject:appLanguage forKey:APP_LANGUAGE_KEY]; prefs will be nil.
At some point, before you use prefs, you need to do something like: prefs = [NSUserDefaults standardUserDefaults];
If you have instantiated prefs somewhere else, you'll still have an issue with this logic. Presumably, you're trying to change the NSUserDefaults to the new language passed in. In that case, the method should be:
- (void) setAppLanguage:(NSString *)newAppLanguage {
_appLanguage = newAppLanguage; // implicit synchronize will set the ivar as _appLanguage
[prefs setObject:newAppLanguage forKey:APP_LANGUAGE_KEY];
[prefs synchronize];
}
Since the _appLanguage instance variable is set to strong by default, ARC will automatically add the necessary release and retain code, preventing a memory leak.
Also, if you are trying to create a private setter method, take - (void) setAppLanguage:(NSString *)appLanguage; out of the interface. If you're not trying to make a private setter, remove readonly from the property declaration.

Related

passing values to another method

I am setting the value for the string in the viewdidload method and getting the string value in the button action method the app gets crashed. can I know the reason for crashing and how to pass the values to the method.
in .h file
NSString *test;
in .m file
-(void)viewDidLoad
{
test = [NSString stringWithFormat:#"sample"];
}
-(IBAction) buttonPressed:(id)sender
{
NSLog(#"%#", test);
}
When I pressed the button the app crashes.
Please try using this solution, I think this will help you,
Create Property of test in .h file like this,,
#property(nonatomic,retain) NSString *test;
and synthesize it in .m file like this,
#synthesize test;
now use test as self.test in .m file like this,
-(void)viewDidLoad
{
self.test = [NSString stringWithFormat:#"sample"];
}
-(IBAction) buttonPressed:(id)sender
{
NSLog(#"%#", self.test);
}
Another solution for this is just retain that test string in ViewDidLoad also, I think this will also help you..
Hope this will help you..
Let me try to explain it in more detail:
You have a string variable in .h file. In view did load you are assigning it as:
test = [NSString stringWithFormat:#"sample"];
What actually happning in this code is your test is a autoreleased object. When you use this and object without alloc and init this is autoreleased object and will release memory after the method you occupied it.
For avoiding this situation you can use #Mehul's solution by creating property. This is against encapsulation concept. Sometimes you have objects you don't want to access outside of the class or don't want to show with objects. Use following in those conditions:
test = [[NSString stringWithFormat:#"sample"] retain]; // or
test = [[NSString alloc] initWithFormat:#"sample"];
this will keep your string alive till you release it.
There is another way that is not good to use but want to tell you so you can understand it better. Using
test = #"sample";
If you don't want to append string or use it with format you can assign simple string to you NSString object.
using this will have a infinite retainCount of your test variable. You can use this to avoid crash but this is not preferable because as I told this have a infinite retaiCount you can't release it and free your memory after use. So earlier methods are more correct.
This is true with all of your autorelease objects which are created with class methods and not with init.
Hope this will clear you more.
I think simple allocation will solve the problem. Just replace this code in the viewDidLoad method
-(void)viewDidLoad {
test=[[NSString alloc]initWithString:#"Sample"];
}

Why aren't my variables persisting between methods? - iPhone

Header file:
NSString *righta;
#property(nonatomic, retain) NSString *righta;
(I don't usually make #property declarations for my variables but thought this might help the variable persist through the class, though it hasn't)
Implementation file:
#synthesize righta;
- (void) function1 {
righta = [NSString stringWithFormat:#"A"];
}
- (IBAction)function2:(id)sender {
NSLog(#"righta is still %#", righta);
}
On trying to access the value of the string in the second function, I receive an "EXC_BAD_ACCESS" and the app crashes.
Any help would be GREATLY appreciated.
Thanks!
stringWithFormat returns an autoreleased object. You must retain it. Note that you are accessing the ivar directy, not the property so the string is not getting retained. Use the property instead:
self.righta = [NSString stringWithFormat:#"A"];
Some programmers prefer to synthesize their properties with a different ivar name to avoid accessing the ivar directly by mistake.
#synthesize righta = righta_;
You must use
self.righta = [NSString stringWithFormat:#"A"];
To assign the variable otherwise the accessor is not used and the value is not retained.
Change function1 to:
self.righta = [NSString stringWithFormat:#"A"];
You were assigning directly to the righta ivar without retaining the string.

why do my NSString values get lost in the definition class? is it normal?

I'm defining some simple variables in a class of type NSString
one of them is keeping my sqlite database path for example, and so on...
I am initializing that in the AppDelegate , function didFinishLaunchingWithOptions
and when I'm trying to see it's value outside this function... it's losing it's value durring runtime, (no I'm not overwrting or anything...)
here's my code...
app.h file
#interface AppDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
.....................
NSString *site_domain;
NSString *databaseName;
NSString *databasePath;
..........................
}
app.m file
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
databaseName = #"database.sqlite";
site_domain=#"http://localhost/webservice";
NSLog(#"%#",site_domain);
// inside this function I can use the value, ..if I call whatever function from
//this function, that function can also use the value...
}
-(void) functionTest {
NSLog(#"%#",site_domain);
//here the value is lost, it's like it can't reach it's pointer or something...
//puts on a wierd string
}
What am i Doing wrong?
What am i Doing wrong?
You aren't posting enough information. :)
//here the value is lost, it's like it can't reach it's pointer or something...
//puts on a wierd string
What does that mean? Show the string. Is functionTest defined in the same source file? Where is it called from?
Since you are using constant strings (#""), there is no need for retain/release, so that isn't the problem.
Are those really the string values you are using?
Because you never take ownership of it, your string is getting autoreleased by the auto release pool. In your didFinishLaunchingWithOptions: method, try using:
site_domain = [[NSString alloc] initWithString:#"http://..."];
And don't forget to release it int the dealloc method
-(void)dealloc
{
[site_domain release];
}

Sharing variables amongst 2 ViewControllers

Here is a simple one for you guys . I'm defining a class to store variables in so I can reuse those variables in different ViewControllers .
Here is how I do it, it`s obviously not working ( that's why I'm asking a question ... ):
I declare a class :
VariableStore.h
#interface VariableStore : NSObject {
int evTe;
}
#property (nonatomic) int evTe;
+ (VariableStore *)shareInstance;
#end
VariableStore.m
#implementation VariableStore
#synthesize evTe;
+ (VariableStore *)sharedInstance {
static VariableStore *myInstance = nil;
return myInstance;
}
#end
Now in my FirstViewController I want to set the value for evTe :
[[VariableStore sharedInstance] setEvte:2];
NSLog(#"value testing, %i", evTe);
And this keeps on returning 0 unfortunately, Im obviously missing something important here but I can't figure out what it is .
Later on Id like to set the value for evTe here in the FirstViewController and then reuse it back in the SecondViewController ..
You are setting your shared instance to nil and then returning it:
static VariableStore *myInstance = nil;
return myInstance;
A nil instance won't hold your variable. It's nil.
First off you shouldn't be using a singleton to pass around variables. If you're going to do that then you might as well just use global variables instead (don't do that either by, the way). Second, if you insist on using a singleton, you need to read up on how to use them.
Finally, if you want to pass variables between view controllers, you either need another view controller that is a parent to the two to facilitate passing data between them, or one needs to call the other and take the first one or its data as a parameter.
Well, you're asking for the value of evTe without calling the object to which it belongs. Try this:
NSLog(#"value testing, %i", [[VariableStore sharedInstance] evTe]);
If you keep using the singleton for a number of times, you might want to do:
VariableStore *vStore = [VariableStore sharedInstance];
so you can do:
[vStore setEvTe:2];
NSLog(#"value testing, %i", [vStore evTe]);
And look out for what Matt said about nilling your singleton ;)
I think in nslog you should output not just evTe, but [[VariableStore sharedInstance] evTe].
First, you have to declare the static variable outside the function, in a way both controllers can access.
static VariableStore* myInstance = nil;
The singleton sharedInstance should be:
if(myInstance == nil)
{
myInstance = [[VariableStore] alloc] init];
}
return myInstance;

Property vs. instance variable

I'm trying to understand how strategies some folks use to distinguish instance vars vs. properties. A common pattern is the following:
#interface MyClass : NSObject {
NSString *_myVar;
}
#property (nonatomic, retain) NSString *myVar;
#end
#implementation MyClass
#synthesize myVar = _myVar;
Now, I thought the entire premise behind this strategy is so that one can easily distinguish the difference between an ivar and property. So, if I want to use the memory management inherited by a synthesized property, I'd use something such as:
myVar = #"Foo";
The other way would be referencing it via self.[ivar/property here].
The problem with using the #synthesize myVar = _myVar strategy, is I figured that writing code such as:
myVar = some_other_object; // doesn't work.
The compiler complains that myVar is undeclared. Why is that the case?
Thanks.
Properties are just setters and getters for ivars and should (almost) always be used instead of direct access.
#interface APerson : NSObject {
// NSString *_name; // necessary for legacy runtime
}
#property(readwrite) NSString *name;
#end
#implementation APerson
#synthesize name; // use name = _name for legacy runtime
#end
#synthesize creates in this case those two methods (not 100% accurate):
- (NSString *)name {
return [[_name copy] autorelease];
}
- (void)setName:(NSString *)value {
[value retain];
[_name release];
_name = value;
}
It's easy now to distinguish between ivars and getters/setters. The accessors have got the self. prefix. You shouldn't access the variables directly anyway.
Your sample code doesn't work as it should be:
_myVar = some_other_object; // _myVar is the ivar, not myVar.
self.myVar = some_other_object; // works too, uses the accessors
A synthesized property named prop is actually represented by two methods prop (returning the current value of the property) and setProp: (setting a new value for prop).
The self.prop syntax is syntactic sugar for calling one of these accessors. In your example, you can do any one of the following to set the property myVar:
self.myVar = #"foo"; // handles retain/release as specified by your property declaration
[self setMyVar: #"foo"]; // handle retain/release
_myVar = #"Foo"; // does not release old object and does not retain the new object
To access properties, use self.propname. To access instance variables use just the instance variable's name.
The problem with using the #synthesize myVar = _myVar strategy, is I figured that writing code such as:
myVar = some_other_object; // doesn't work.
The compiler complains that myVar is undeclared. Why is that the case?
Because the variable myVar is undeclared.
That statement uses the syntax to access a variable, be it an instance variable or some other kind. As rincewind told you, to access a property, you must use either the property-access syntax (self.myVar = someOtherObject) or an explicit message to the accessor method ([self setMyVar:someOtherObject]).
Otherwise, you're attempting to access a variable, and since you don't have a variable named myVar, you're attempting to access a variable that doesn't exist.
In general, I name my properties the same as my instance variables; this is the default assumption that the #property syntax makes. If you find you're fighting the defaults, you're doing it wrong (or your framework sux, which is not the case for Cocoa/Cocoa-touch in my opinion).
The compiler error you're getting is because property use always has to have an object reference, even inside your own class implementation:
self.stuff = #"foo"; // property setter
[stuff release]; // instance variable
stuff = #"bar"; // instance variable
return self.stuff; // property getter
I know that many Cocoa programmers disagree, but I think it's bad practice to use properties inside your class implementation. I'd rather see something like this:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
[stuff release];
stuff = [theStuff copy];
// do something else
}
than this:
-(void) someActionWithStuff: (NSString*) theStuff {
// do something
self.stuff = theStuff;
// do something else
}
I prefer to do memory management as explicitly as possible. But even if you disagree, using the self.stuff form will clue in any experienced Objective-C programmer that you're calling a property rather than accessing an instance variable. It's a subtle point that's easy for beginners to gloss over, but after you've worked with Objective-C 2.0 for a while, it's pretty clear.
Don,
According to the "rules", you should call Release for every Copy, Alloc, and Retain. So why are you calling Release on stuff? Is this assuming it was created using Alloc, Copy, or Retain?
This brings up another question: Is it harmful to call Release on a reference to an object if it's already been released?
Since Apple reserves the _ prefix for itself, and since I prefer to make it more obvious when I am using the setter and when I am using the ivar, I have adopted the practive of using a prefix of i_ on my ivars, so for example:
#interface MyClass : NSObject {
NSString *i_myVar;
}
#property (nonatomic, retain) NSString *myVar;
#synthesize myVar = i_myVar;
i_myVar = [input retain];
self.myVar = anotherInput;
[i_myVar release]
Since it is quite important to know when you are using the setter and when you are using the ivar, I find the explicitly different name is safer.
In your question, it should be:
self.myVar = #"Foo"; // with setter, equivalent to [self setMyVar:#"Foo"]
and
_myVar = some_other_object; // direct ivar access - no memory management!
Remember that you should not use setters/getters in init/dealloc, so you need to do your direct ivar access (and careful memory management) iin those methods.
what's wrong with simply using
#interface MyClass : NSObject
#property NSString *prop;
#end
nonatomic and retain are not required, retain is the default, and atomic/nonatomic isn\t important unless XCode tells you with a warning.
it is NOT necessary to declare the iVar, one will be created for you named _prop, if you really want to use one (i don't see why to be honest)
#synthesize is NOT required.
when (and you should) using ARC you don't have to bother with retain and release either.
keep it simple !
furthermore, if you have a method like this one
- (void)aMethod:(NSString*)string
{
self.prop = string;
// shows very clearly that we are setting the property of our object
_aName = string;
// what is _aName ? the _ is a convention, not a real visual help
}
i would always use properties, more flexible, easier to read.