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.
Related
What I have read from the apple document retain will increase the retain count by 1 , and release will decrease by 1. This is very much clear to me.
But In the case of copy and retain i am a bit confused.
Let me explain with the code i am trying.
property ---
#property(nonatomic, retain) NSMutableString *a;
#property(nonatomic, copy) NSMutableString *b;
#synthesize a = _a ,b = _b
a=[[NSMutableString alloc]initWithString:#"Hello Ankit"];
NSLog(#"a memory location A - %p", &a );
b=[[NSMutableString alloc]initWithString:#"Hello Nigam"];
NSLog(#"a memory location B- %p", &b );
c= [[NSMutableString alloc]initWithString:#"Ankit Nigam"];
NSLog(#"a memory location C %p",&c);
NSMutableString *temp =[[NSMutableString alloc]initWithString:#"hey"];
NSLog(#"temp = %# %p",temp,&temp);
self.b = temp;
NSLog(#"B is now %# %p",self.b,&b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&a);
And i get the output as -- - -
2012-05-10 03:24:34.756 retainCountTest[2655:f803] a memory location A - 0x6d314fc
2012-05-10 03:24:34.757 retainCountTest[2655:f803] a memory location B- 0x6d31500
2012-05-10 03:24:34.764 retainCountTest[2655:f803] a memory location C 0x6d31504
2012-05-10 03:24:34.764 retainCountTest[2655:f803] temp = hey 0xbfffdd04
2012-05-10 03:24:34.764 retainCountTest[2655:f803] B is now hey 0x6d31500
2012-05-10 03:24:34.765 retainCountTest[2655:f803] A is now hey 0x6d314fc
But as per I understand from the Doc the retain object must have the same memory address , where as copy object will create a new object with different memory location.
Again when i change the logs to ---
self.b = temp;
NSLog(#"B is now %# %p",self.b,&_b);
self.a = temp;
NSLog(#"A is now %# %p",self.a,&_a);
It return me a complete different memory location for both the object.
2012-05-10 03:28:49.905 retainCountTest[2688:f803] a memory location A - 0x6d4a4ac
2012-05-10 03:28:49.906 retainCountTest[2688:f803] a memory location B- 0x6d4a4b0
2012-05-10 03:28:49.907 retainCountTest[2688:f803] a memory location C 0x6d4a4b4
2012-05-10 03:28:49.907 retainCountTest[2688:f803] temp = hey 0xbfffdd04
2012-05-10 03:28:49.908 retainCountTest[2688:f803] B is now hey 0x6d4a4c0
2012-05-10 03:28:49.908 retainCountTest[2688:f803] a is now hey 0x6d4a4bc
Can any help me to understand the complete concept of these retain and copy. Also why I am getting these unexpected results.
Thanks a lot.
A property is just a declaration that allows for setters, getters, and dot-syntax accessors (interface variable hiding).
It does absolutely nothing on its own but allow you to use -[myInstance myProperty] to get the variable or use -[myInstance setMyProperty:] to set it (yes, the method name is auto-assigned to -setProperty: and -property).
When declaring a property, you have three categories - thread locking, access control, and memory management. You can only pick one of the modifiers for each category and if you do not pick one, it's auto-assigned to one automatically.
#property (<thread locking>, <access control>, <memory management>) id property;
The first category can either be atomic or nonatomic. The atomic modifier forces an #synchronized(myInstance) lock on the variable, to allow thread safety. The nonatomic does not use a synchronized-block, and is NOT thread safe. If you do not use either, it is automatically set to atomic.
The second category can either be readonly or readwrite. The readwrite modifier allows the property to be modified as well, and allows auto-generation of the -setProperty: method. When the readonly modifier is used, you cannot use the -setProperty: method. You must use the internal variable from within the object to set the variable directly.
The third category can either be assign, retain, and copy. The assign modifier means the internal object pointer is set to the pointer passed to the -setProperty: message. The retain modifier assigns the passed pointer and passes a -retain to the object.
The copy modifier does a straight-up clone of the object- a new pointer to a new object at a new address in the memory. This sets the internal object pointer to the copy of the passed object, by calling -copy on the passed object. The default modifier is assign, and the compiler will warn you if you do not set the memory management category modifier on an object - because an assign modifier on an object is frowned upon (unless explicitly declared).
For an example on -copy, look at this:
- (void)setProperty:(GXMyObject *)property {
// This points to the original passed object.
GXMyObject *original = property;
// This points to a copy of the passed object.
CGMyObject *copied = [property copy];
// This points to yet another copy of the passed object-
// Independent of the other copies and original.
_property = [property copy];
// The anotherProperty is now different on this copy
// than on the original and the other copies.
_property.anotherProperty = 4;
// This will prove that they are all individual objects.
NSLog(#"%p, %p, %p", original, copied, _property);
}
There is an optional method name declaration modifier and is used like so: getter = myCustomPropertyGetter and setter = myCustomPropertySetter: (The colon : at the end of the setter method name is required because it denotes that an argument must be passed).
The second half of this is the property synthesizer or dynamizer. Once a property is declared (for example, myView) like so:
#property (nonatomic, retain) NSView *myView;
You would either: define the setter and getter yourself; #synthesize the setter and getter; #dynamic the property to say that it exists in a category or the main class, or may be added at runtime (not a fun idea, mind you, and could cause bad runtime exceptions).
The first example, writing the methods yourself would look like this:
// In Apple's LLVM 3.1 Compiler, instance variables can be added
// within {} below the #implementation as well as the #interface,
// and in private categories (#interface GXMyClass ()) like before.
#implementation GXMyClass {
// The internal object pointer is prefixed with an _ to avoid name confusions.
NSView *_myView;
}
- (NSView *)myView {
return _myView;
}
- (void)setMyView:(NSView *)myView {
_myView = [myView retain];
}
#end
The second example would be to auto-synthesize it using the #synthesize directive:
#implementation GXMyClass
// In the new Apple LLVM 3.1 Clang compiler, the = operator when used
// next to the #synthesize directive declares an internal private
// variable and automatically sets to that variable.
#synthesize myView = _myView;
// The internal variable name is now myOtherView, because we did not use the
// = operator to assign an internal variable name to the property.
#synthesize myOtherView;
#end
Under the last example, perhaps the most confusing, because it requires the use of the #dynamic directive, you require something of a category or a runtime method addition:
#interface GXMyClass (InternalMethods)
#end
#implementation GXMyClass
// The = assignment operator does not work here.
#dynamic myView;
#end
#implementation GXMyClass (InternalMethods)
- (NSView *)myView {
return [self methodThatReturnsAnNSView];
}
- (void)setMyView:(NSView *)myView {
[self methodThatAcceptsAnNSViewArgument:myView];
}
#end
The #property declaration requires one of the three above declarations to be present- it does not do anything on its own. What it DOES allow, however is dot-syntax accessors (Java-like accessors for setting and getting properties).
For example, #property (copy) NSString *myName; could be accessed using -[myObject myName] and set using -[myObject setMyName:].
Now it can be set using myObjectInstance.myName = #"Bob"; and gotten using myObjectInstance.myName. Utilizing all the above concepts, one could create an object such as this one:
// The GXBufferQueue is a queue which buffers all requests, till they are read
// asynchronously later. The backing store is an NSMutableArray to which all
// buffer writes are appended to, and from which the first object is pulled and
// returned when the buffer is read to.
#interface GXBufferQueue
#property (nonatomic, readwrite, copy, setter = write:, getter = read) id buffer;
+ (GXBufferQueue *)queue;
#end
#implementation GXBufferQueue {
// This queue is an internal array and is 'tacked on' to the #implementation
// so no others can see it, and it can be marked #private so subclasses cannot
// use it. It is also good code practice to have #interfaces composed of only
// #properties, setters, and getters, rather than expose internal variables.
NSMutableArray *_internalQueue;
}
+ (GXBufferQueue *)queue {
return [[[GXBufferQueue alloc] init] autorelease];
}
- (id)init {
if((self = [super init])) {
_internalQueue = [[NSMutableArray alloc] init];
}
}
- (void)write:(id)buffer {
[_internalQueue addObject:buffer];
}
- (id)read {
if(!(_internalQueue.count > 0)) return nil;
id buffer = [_internalQueue objectAtIndex:0];
[_internalQueue removeObjectAtIndex:0];
return buffer;
}
#end
Note: This code was in no way tested.
Now that you have a GXBufferQueue, all the following works:
GXBufferQueue *queue = [GXBufferQueue queue];
// Option One: using the traditional message syntax:
[queue write:#"This will be now added to the buffer."];
NSLog(#"Now the string written to the queue will be read \
and removed from the queue, like a stack pop. ", [queue read]);
// Option Two: using the new dot-syntax accessors:
queue.buffer = #"As clunky as this looks, it works the same as above.";
NSLog(#"These lines work just the same as the ones above: ", queue.buffer);
As you can see, there's a lot possible with properties and a lot more that can be done with them than just variable declaration. If there are any questions or anything the community would like me to add/rectify to/in the post, please leave a comment! :D
Yes, retainCount is useless-- don't call it-- and assuming that copy will always return a new instance is incorrect.
If an immutable object is sent copy, it will typically be implemented as:
- copy { return [self retain]; }
I.e. there is no need to make an actual copy since the contents can't change.
Of course, since you are mucking about with static, compiled into the binary, strings, the implementation is likely closer to:
- retain { return self; }
- copy { return self; }
- (void)release { ; }
- (void)dealloc { ; }
Maybe -- all of the above are implementation details that may change at any time. The bottom line, though, is that all of the above fulfills the contract of retain/release/copy/etc...
Question #1
Will NSStringFromCGPoint() return an autorelease object or does the object needs to be released?
Question #2
When you have a property : #property (nonatomic, retain) NSString *someString;
And you set it like so: self.someString = [[[NSString alloc] initWithString:#"Something"] autorelease];
Is this:
[someString release];
someString = nil;
equal to
self.someString = nil;
I haven't checked that one specifically, but by convention those sorts of functions return autoreleased objects. You might be able to test this yourself by setting up a minimal, non-ARC project and calling -retainCount on what you get out of the function, but I'm not sure. (And in general, retainCount isn't something you want to use.)
Yes. The synthesized setter looks something like:
- (void)setSomeString:(NSString *)string
{
if (string != someString) {
[someString release];
}
someString = [string retain];
}
So, whether you call it explicitly or using the dot notation, the old value gets released (and the underlying ivar gets set to nil or whatever you pass in).
Also, I'm not sure if you were just doing it for a random example, but you don't have to wrap a string literal in memory management code to pass it to the property accessor. (That is, self.someString = #"Something" is fine.)
Does the call include the term "new", "alloc", "copy", or "create"? If not, you're getting back an object that you do not own (you may assume it is either autoreleased or that the reference is owned elsewhere).
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.
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;
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.