Why aren't my variables persisting between methods? - iPhone - 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.

Related

Using self. to set but not to access causes issues

I am currently getting confused why the following works in some cases but not others. When using the following code:
NSString *currentLoc = [[NSString stringWithString:sceneName] retain];
self.currentLocation = currentLoc;
[currentLoc release];
This should overwrite my NSString *currentLocation, of type (nonatomic, retain) with the new value. Why can I now not access this value by doing the following:
NSString *test = currentLocation;
When debugging I see that test is set to a random array, so the pointer must be pointing at something completely different. I have checked through the code and the currentLocation variable is only set here. If I use the following:
NSString *test = self.currentLocation;
Then the correct value is now shown, can someone explain why currentLocation / self.currentLocation are treated as different objects, I understand that self. uses the accessor but surely if set correctly they should both point to the same value?
EDIT 1: (All code)
.h
NSString *currentLocation;
#property (nonatomic, retain) NSString *currentLocation;
.m
#synthesize currentLocation;
NSString *currentLoc = [[NSString stringWithString:sceneName] retain];
self.currentLocation = currentLoc;
[currentLoc release];
if (currentLocation != nil && singleton.storyLocation != nil)
{
if (boolMoviePlayed == false && [singleton.storyLocation isEqualToString:currentLocation]) // crash here due to current location being set to an array
[buttonPlayMovie setHidden:!textVisible];
}
self.currentLocation = nil; // viewDidUnload
[currentLocation release]; // dealloc
EDIT 2: (Updated code, still crashes)
So this time I've tried to access the code in the way it was set, as seen below:
if (self.currentLocation != nil && singleton.storyLocation != nil)
{
if (boolMoviePlayed == false && [singleton.storyLocation isEqualToString:self.currentLocation])
[buttonPlayMovie setHidden:!textVisible];
}
However, this time I get a crash where the variable seems to be unset, even though it is never changed at any point during this process (see code in EDIT 1).
EDIT 3:
Now I am getting confused, I thought I had the answer but I just plain don't. I tried using Erics suggestion:
#synthesize currentLocation = _currentLocation;
Then I made sure all access to currentLocation was set using self.currentLocation = xyz. Now when it comes to the dealloc method, I was always warned not to use self. in the dealloc. But this means all my values are nil as currentLocation has not been set. Is it safe to use [self.currentLocation release] or how can I fix my issues?
EDIT 4:
As far as I can tell, you then use [_currentLocation release] within the dealloc, if I am wrong please correct me, if not I will go down this route for now as it seems to work.
I would take a look at how you synthesized as well as your ivars. In reality currentLocation is referring to the iVar directly, while self.currentLocation, could be pointing to a different variable if you synthetized it like this for example:
#synthesize myVar = _myVar
and then you also had in your interface
interface {
myVar
}
In this scenario you would see the issue described.
currentLocation is a variable, self.currentLocation is a fancy way to call property getter (a method) - (NSString*)currentLocation.
Obviously you are using the property to store the value and there is no connection set between the variable and your property.
You should inspect the row where you are synthesizing the property currentLocation.
Answer to edit3:
The init methods and dealloc are the only two places when a property ivar should be accessed directly. In dealloc you usually write directly [_currentLocation release]. However there is a big discussion about it. In general it is correct to just put self.currentLocation = nil into dealloc but you have to know what you are doing.
To make it simple :
property = getter + setter + iver
Exp. #1:
.h
NSString *yourName; //iver
#property (nonatomic, retain) NSString *myName; //property
.m
#synthesize myName;
-(void)someMethod{
self.myName = #"Mike";
NSString * name = self.myName; // name will be "Mike"
name = myName; // name will be "Mike"
name = yourName; // name will be null
}
Here yourName, self.myName and are three different things :
yourName is a iver
self.myName is a getter or setter in two different cases
myName is a iver
Now I want to connect yourName iver to myName property.
Let see how in Exp. #2
Exp. #2
.m
#synthesize myName = yourName;
-(void)someMethod{
self.myName = #"Mike";
NSString * name = self.myName; // name will be "Mike"
name = yourName; // name will be "Mike"
yourName = #"James";
name = self.myName ; // name will be "James"
}
Here you cant use myName iver.
There is nothing wrong with the code you have shown. But you have shown bits and pieces of code (there is not even a complete method or class) and it's really hard to tell what's going on. The error must be from something else. All this talk about changing the variable name is completely irrelevant -- there is nothing wrong with using the same variable name.
Use #synthesize currentLocation = _currentLocation.

Objective C: Which is changed, property or ivar?

Worrying about duplicates but can not seem to find and answer I can understand in any of the other posts, I just have to ask:
When I have in my .h:
#interface SecondViewController : UIViewController{
NSString *changeName;
}
#property (readwrite, retain) NSString *changeName;
then in my .m
#synthesize changeName;
-(IBAction)changeButton:(id)sender{
changeName = #"changed";
}
Is it the synthesized property or the instance variable that get changed when I press "changeButton" ?
You (and it seems some of the others that answered) are confusing properties with actual variables.
The way properties work is, they create METHODS (called setter and getter) that set or get/return ivars. And the do notation (self.string) actually INVOKES these methods. So a property can't be CHANGED, only the declared iVar is.
When you declare a property like so:
#property (nonatomic, retain) NSString *string;
And #synthesize it the following happens:
An iVar called string (of type NString*) is created
(if you do
#synthesize string = whateverYouWant
the iVar created
is called whateverYouWant - a convention is to name the iVars
the same as the property with preceding underscore (_string))
an accessor method is created like this
-(NSString*) string;
a setter is created like this
-(void) setString: (NSString*) newString;
Now what self.xxxx does is, it actually sends the message xxxx to self
(like [self xxxx]).
It works with ANY method, not just properties, though it should only
Be used with properties.
So when you do self.string = #"hello" it actually comes down to
[self setString: #"hello"];
(Note that the compiler actually knows you are trying to set and so the
setString message is sent instead of just string. If you accessed self.string
it would send [self string])
Thus you don't SET a property, you invoke the (synthesized) setter method that in
itself sets the iVar.
Accessing your iVar directly is ok, if you know what your doing.
Just calling
string = #"something else";
Will produce leaking code, since no memory management is done.
The synthesized accessors and setters actually do this for you, depending
on how you defined th property (retain,copy,assign).
Because the setter (for a retained property) doesn't just do
IVar = newValue
If you declared a retained property it actually looks something like this:
-(void) setString: (NSString*) newString {
if (string) [string release];
string = [newString retain];
}
So the property synthesize takes a bit of work off your hands.
EDIT
Since it still doesn't seem clear, the property that is declared is not to be thought
of like a variable. In the above example, when using
#synthesize string = _string;
there IS NO variable called "string". It's just the way you access the method structures
that set the iVar _string through the setter methods. Since string is no variable/object pointer, you cannot send messages to it ([string doSomething] won't work).
When you just synthesize the property using #synthesize string; the generated iVar gets
the same name as the property.
Calling [string doSomething] will then work, but it has nothing to do with the property. The "string" refers to the iVar. Hence th convention to name the iVars underscored, so
you don't accidentally access the iVar when you meant to use the getter/setter.
Both. Property uses instance variable as its storage. In your code you change the instance variable, but if you access the property (via self.changeName) you'd get the same value as instance variable.
Usually to distinguish between ivars and properties people use _ prefix for ivars. And then synthesizes properties like this:
#synthesize myProperty=_myProperty;
well, the var
it's always the var
in your case the property methods aren't used at all.
now, consider this case:
self.changeName = #"changed";
this way you are using the property, but that just means that you are using the methods "magically" created for you by the compiler, the setter and getter methods, where you, again, change the var (property doesn't exist, in reality, it's just a way to create the setter and getter methods for you)

NSString not working

In my code I declared NSString object in .h and synthesized in .m , I m assigning it with string object in array . but its not working .
when I print it on Log it display sometime CAlayer Class , some time shows NSCFString class object .some time shows UIDevicewhitedevicetype class how to solve this ? help...
How are you assigning the string to the NSString object in your code?
Are you doing something like:
NSString* someString = #"My string";
self.myStringProperty = someString;
Where myStringProperty is the NSString declared as a property.
I think your memory is ruined. You maybe release something that should not be released.
The reference is definitely bad. You said you are assigning the string to a property. Does that imply that in your header you have something like:
#property (assign) NSString* myString;
If so, that explicitly states that you are not going to hold onto the string reference, allowing it to be dealloced even if you still hold a pointer (not a reference) to it. You should make it say either:
#property (copy) NSString* myString;
#property (retain) NSString* myString;
If you are pointing your string at a value in an array, as soon as that array is released all of its contents are released. If you aren't holding a retained reference to the string it will be deallocated. Once that has happened the pointer you have stored points to undefined memory that is being reused to hold the object types you listed.

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.

Do I have a leak with this statement?

The statement is:
//Pass the copy onto the child controller
self.childController.theFoodFacilityCopy = [self.theFoodFacility copy];
My property is set to:
#property (nonatomic, retain) FoodFacility *theFoodFacilityCopy;
The reason I think I have a leak is because copy retains the value and then my dot syntax property also retains the value. Doubly retained.
What is the correct way of writing the above statement?
yes, you do have a leak there.
SomeClass *someObj = [self.theFoodFacility copy];
self.childController.theFoodFacilityCopy = someObj;
[someObj release];
This mirrors the recommended approach for initializing an object too:
SomeClass *someObj = [[SomeClass alloc] init];
self.someProperty = someObj;
[someObj release];
In both cases the first line returns an objects with a retain count of 1, and you treat it identically after that.
As mentioned by others, that is indeed a leak. If you expect to be using copies in this way, it’s likely your property should be declared copy instead and the synthesized accessor will do the work for you.
You are right. The cleanest way is something like
id temp = [self.theFoodFacitlity copy];
self.childController.theFoodFacilityCopy = temp;
[temp release]
You want to read the apple site on memory management a lot until these rules become second nature.
What is the advantage of doing this vs just setting the property to copy?
#property (nonatomic, copy) FoodFacility *theFoodFacilityCopy;