I'm a little confused about synthesized properties. I have an array that I want to be accessible from other classes so this is my code:
MyClass.h
#interface MyClass : CCLayer {
NSMutableArray *myArray;
}
#property (nonatomic, retain) NSMutableArray *myArray;
MyClass.m
#synthesize myArray;
-(id)init
{
myArray = [[NSMutableArray alloc] init];
}
-(void)dealloc
{
[myArray release];
myArray = nil;
}
I am a little confused now..is myArray the same as self.myArray? Do I have to release self.myArray as well? Thanks.
You declared your property as retain, it means that it will be retained automatically if you will set is using self.myArray. So, you can simply create autoreleased array in your init method and set it as
myArray = [NSMutableArray array];
self.myArray = myArray;
in this case you are not have to release it in the dealloc method or anything else. And as dasblinkenlight said you have to use #synthesize if you want to be sure that self.myArray is linked with your myArray instance.
Assuming that your #synthesize directive looks like this
#synthesize myArray;
you do not need to do anything in addition to what you are already doing: your property stores its value in the instance variable of the same name.
EDITED : Removed the alternative that suggests setting self.myArray in the dealloc method.
Yes you do, the best method is to set the property nil and release your variable.
-(void)dealloc{
self.myArray = nil;
[myArray release];
[super dealloc];
}
The code you provided is not really correct.
No, accessing a property and accessing the field itself are not the same.
My guess is that you are looking at old obj C examples where it was necessary to create the field with the property.
You also have no #synthesize directive in your code.
In current obj C code there is no need to declare a field to back the property, the field and the getter and setter will be autosynthesized (generated by the compiler) for you.
The default field generation is the name of your property with an underscore in front of it.
When you access the field directly via _myArray you will bypass any retain or release code that is contained in the generated getter/setter and have to manually manage memory in a non ARC project.
So to sum up, you dont need your field definition, and you dont need a synthesize directive.
You access your field directly with _myArray, or the property via self.myArray
They are not the same thing, one goes through generated code which obeys your property definition as to retain, assign, copy and accessing the field directly bypasses these semantics altogether.
If you define your property as retain you will need to release it in dealloc
You can use either
self.myArray = nil;
which will handle the release or
[_myArray release];
_myArray = nil;
Although someone in a previous post said setting the property to nil in dealloc might cause a problem Ive never seen it actually happen in my apps, ymmv
To answer your questions:
I am a little confused now..is myArray the same as self.myArray?
Yes, but no. Both point to the same object, the same area in memory. If you read myArray or self.myArray, they're identical in behavior minus the message send overhead for self.myArray.
However if you assign to myArray, the object will not be retained. It will only be retained if you assign to self.myArray.
Do I have to release self.myArray as well?
No.
You can also choose to either release or set the property to nil. As long as the property is #synthesize'd both examples do the same thing:
-(void) dealloc
{
[super dealloc];
[myArray release];
}
-(void) dealloc
{
[super dealloc];
self.myArray = nil;
}
See here for a discussion of the pros/cons to each approach.
From the question I think you're the developer who should really be using ARC. You'll have less to learn and fewer technical problems down the road. I can't understate how important using ARC is in these days, specifically if you don't have much ObjC experience. Read this how to enable ARC for cocos2d or just use Kobold2D to be able to work with an ARC-enabled cocos2d out of the box.
Related
This is one of my method.
- (void)getSearchResultsByKeyword:(NSString *)keyword
searchOptions:(NSArray *)searchOptions
searchGroupsInResult:(NSArray *)searchGroupsInResult
{
_searchKeyword = [keyword retain];
_searchOptions = [searchOptions retain];
_searchGroupsInResult = [searchGroupsInResult retain];
[_searchResultsGroups removeAllObjects];
[_searchResultsGroupsIndexToNameMap removeAllObjects];
_pageNo = 1;
[[NSNotificationCenter defaultCenter] postNotificationOnMainThreadName:SearchResultsRetrievingStartLodingNotification
object:self];
[_dataProvider startGettingSearchResultsByKeyword:self.searchKeyword
searchOptions:_searchOptions
searchGroupsInResult:_searchGroupsInResult
pageNo:_pageNo
delegate:self];
}
In my method I have called retain on the objects which are parameters. So I have owned the object and has increased the retain count. So my problem is, how do I decrease the retain count after the
[_dataProvider startGettingSearchResultsByKeyword:self.searchKeyword
searchOptions:_searchOptions
searchGroupsInResult:_searchGroupsInResult
pageNo:_pageNo
delegate:self];
call. ( [keyword release] or [_searchKeyword release] ) ??
In my header file I have declared the _searchOptions as a private instance and _searchKeyword as a readonly property. In my implementation file, I have released both instances in dealloc.
I ran Analyze tool and it did not show this thing as an issue. But I have a doubt on it.
So, please show me a necessary way to work on this thing.
I'm working on XCode4 and iOS 4.3.
Thanks.
jaydee3's answer is correct. I would add that you really should use #properties with synthesized accessors. Then, instead of setting your instance variables directly, use the accessor methods. That way you can encapsulate all of the memory management of your instance variables in the accessor methods. This has the advantage of being more readable, much less error prone, and makes your code easier to modify in the future.
So, in your .h (or in a class extension in your .m if the properties should be "private"):
#property (nonatomic, copy) NSString *searchKeyword;
In your .m:
- (void)dealloc
{
self.searchKeyword = nil;
[super dealloc];
}
#synthesize searchKeyword = _searchKeyword;
Finally, in your -getSearchResultsByKeyword:searchOptions:searchGroupsInResult: method:
self.searchKeyword = keyword;
instead of
_searchKeyword = [keyword retain];
Now you don't have to worry about releasing or retaining searchKeyword. The setter method generated by the #synthesize directive will take care of it for you. I suggest reading Apple's documentation on Declared Properties.
Since you are assigning to an ivar, you have to retain it. This is correct.
Releasing it within dealloc is also correct. But thats not enough. Two things:
1) It's better to copy strings, rather than retain them. So use _searchKeyword = [keyword copy];. (This is also retained. So the retainCount is 1 after that.)
2) Also there is a problem, when you call your method the second time. That is the point, where you do have a leak. You are assigning a new value to your ivar `_searchKeyword', dismissing the pointer to the old keyword, which is still retained. So before assigning the new one, release the old one also.
Example:
[_searchKeyword release];
_searchKeyword = [keyword copy];
If you copy it, this is good, but if you only retain, it would be even better to do it like that (in case both reference the same object):
[keyword retain];
[_searchKeyword release];
_searchKeyword = keyword;
When there are two objects that are pointers to the same thing, it doesn't matter which one you call release on. The thing pointed at is where the reference count gets decremented.
Given you've released it in one place, and the analyzer isn't complaining, you don't have a problem.
Maybe someone could explain the difference between property:
in .h file
#property(nonatomic,retain) NSString *someString;
#property(nonatomic,retain) NSString *someString2;
in .m file
#synthesize someString = _someString;
or
#synthesize someString2;
what is the difference for _someString and self.someString2 using in controller?
and in dealloc how i should release these property's
[_someString release];
AND
[self.someString2 release];
OR
_someString = nil;
_someString2 = nil;
synthesize someString = _someString;
This says synthesize the property someString but for direct access, use _somestring.
synthesize someString2;
This says synthesize the property someString2 but for direct access, use someString2.
Think of it as if the compiler is generating the iVars for you but in the first case the iVar is called _someString and the second is called someString2
This is a common usage (I recently moved to it) so that when you are dealing with the object directly (such as initialisers or in dealloc, where you should't use self) you can see instantly that when you write _someString = #"aString"; you are not going through the property methods that would apply the memory management types (such as retain, or copy). It used to be common that people would assign values directly, and then wonder why they weren't being retained.
[_someString release];
[_someString2 release];
Is sending the release method directly to the object.
self.someString = nil;
self.someString2 = nil;
Sends release through the property. In this case, There is no difference. There would be a difference if you were allocating objects: for example:
_someString = someOtherString;
Is a leak (except under ARC, which I will come to later), because you are just putting in a new object to the store, without releasing the current object.
self.someString = someOtherString;
does not leak anything, because the sythesized setter will release the current object before setting (and retaining) the new object.
I said I'd come to ARC. In which case you can't call release anyway, so the questions don't arise, but _someString = someOtherString is not a leak, because the compiler will deal with releasing the current object for you.
After:
property(nonatomic,retain) NSString *someString;
property(nonatomic,retain) NSString *someString2;
and:
#synthesize someString = _someString;
#synthesize someString2;
someString is a property backed by the instance variable _someString. Memory retention and release is managed by Obj-C.
Assignments to someString should use the form self.someString within the class, and must use <reference>.someString outside of it. Except within an initializer there should never be any assignments to a plain _someString.
Reading the value can use simply _someString within the class, but self.someString is also valid, and must use <reference>.someString outside of it.
Releasing the value must use the form self.someString = nil within the class, and <reference>.someString = nil outside of it.
someString2 is similar except it is backed by an automatically named instance variable, which happens to be called someString2.
#synthesize someString = _someString; Means you're making a property with a different name then the member variable it's associated with. This is fine. Typically they are same name. Here's an example when that isn't the case. So someString would be your property and _someString is your member variable.
As for [_someString release]; and [self.someString2 release]; what you're seeing is release being called on the member variable of your class(Which is _someString). [self.someString2 release] calls release on whatever the property returns. Keep in mind that properties can do more then just simply get and set. They are methods just like any other you might right.
Also, don't do [self.someString2 release]; Instead do self.someString2 = nil; That will release it on your behalf. That way it nils out the string. That will protect you from accessing bad memory incase the string is actually deallocated.
_someString = nil won't release your property.
In this case _someString and self._someString point to the exact same object, so you can release using either.
[_someString release];
AND
[self.someString2 release];
releases twice, that's wrong. Use
_someString = nil;
_someString2 = nil;
simply sets your ivars to nil, it doesn't release them, so that's again wrong.
Correct: either
self.someString = nil;
self.someString2 = nil;
or
[_someString release];
[_someString2 release];
I'd recommend the first one (dot-notation), as it does the right thing (you don't know what kind of code does a compiler generate when synthesizing your accessors...)
In my last question (here), I had an issue where I was getting an EXC_BAD_ACCESS because I was releasing the variable I had just allocated:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
should have been
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
However, stack is a retained property of my class. It's declared like so:
#interface StateStack ()
#property (nonatomic, retain) NSMutableArray* stack;
#end
I was under the impression that when you assign a 'retain' variable, it automatically increments the retainCount of the object. So you are supposed to start by releasing your pointer (as here).
Why are these two cases different? Thanks!
Because you had to assign the property, not the instance variable. When you assign to the property it's going to retain the variable again and then you're not going to have the issue. Here's how your code should have been:
NSMutableArray* s = [[NSMutableArray alloc] init];
self.stack = s;
[s release];
This way you're not assigning to the variable, but using the property (that's, in fact, a method). If you did not release in this case then you'd have a memory leak in your code.
When you did stack = s you assigned directly to the instance variable and the array was never retained.
There is no such thing as a "retain variable". It's a retain property — meaning the setter method behind the property retains the new value and releases the old one. But assigning to a variable just assigns. In fact, the reason people generally recommend assigning directly to the instance variable in init is specifically so that it doesn't go through the setter, because the setter could conceivably have side effects you don't want in init (when your object isn't fully constructed yet).
Note: I'm talking about normal memory-management rules here. This is all different if you're using ARC. But I assume you would have mentioned if you were.
self.stack and stack are two completely different things. When you use stack, you are accessing an instance variable, not a property. This means that your accessor methods aren't called, which means automatic memory management isn't used. This is why you shouldn't release s in your example.
If you used self.stack instead, then you would be using a property. The compiler will treat self.stack = value exactly the same as [self setStack:value], and self.stack the same as [self stack]. Since accessors are being used, memory management will be taken care of to match the way you defined your property, and you should release a value after assigning it.
Maurício has the right answer: be sure to assign to the property to gain the benefits of #property. To clarify the point somewhat, try using code like this:
#interface StateStack : NSObject {
NSArray *_stack;
}
#property (nonatomic,retain) NSMutableArray *stack;
#end
#implementation StateStack
#synthesize stack=_stack;
#end
Now, if you try:
NSMutableArray* s = [[NSMutableArray alloc] init];
stack = s;
[s release];
You'll get an error, which will mean you tried to set the ivar rather than the property as intended. This mismatch between ivar name and property name is against Apple's recommendations, but it's a fine way to help you develop the habit of using property assignment when you intend to do so.
I have been developing an app for a while and now I have gotten to the "Instruments-Leaks" part.
I remember a thing that puzzled me about ivars a few months back when I was learning. I took the whole thing a bit on faith and just followed the way Apple and others did it. As far as I can read, the accessors generated by the SDK will take care of the memory management.
But how are ivars themselves initialized?
If I have an ivar like this in my interface;
#interface
{
NSArray *results;
}
#property(nonatomic, retain) NSArray *results;
#end
#implementation
#synthesize results;
If I during run time try to do this:
[self setResults:allReadyInitializedArray];
It will crash, telling me that this result object was not initialized. If I however do this:
self.results = [[NSArray alloc] init]; //Im assigning this property memory, but hasn't the SDK already done that?
[self setResults:allReadyInitializedArray];
it will work but it will apparently leak memory.
I was under the impression that using the generated
accessors would release the old value before setting the new, meaning
the above ought to come out with the old value released and the new with a +1 retain count.
Does it specifically have to do with the ivar being of type NSArray/NSMutableArray, I can't recall it has been a problem with other ivars.
The problem has been particular prominent in my XML parser, where I continuously need to set an ivar value, use it, overwrite this value, use the new value etc.
Would someone please help me outline the correct way "of going from": #property() -> #synthesize -> using the ivar -> to dealloc?
I have read the memory management documents, I have tried looking for some in debt documentation that was within my understanding, but it seems that even though I use ivars on a daily basis I don't understand what goes on behind the scenes.
All ivars initially set to nil so you need to instantiate them before use. It is really hard to say why setResults may produce errors without seeing its implementation.
self.results = [[NSArray alloc] init];
Here you create new array object using alloc method - its retain count equals 1. After that your setter method retains your array once more and so your 1st objects retain remains "unhandled" resulting in memory leak. To remove leak you can rewrite your code like:
self.results = [[[NSArray alloc] init] autorelease];
// or
self.results = [NSArray arrayWith...]; // any NSArray's convenience method that returns autoreleased object.
My understanding is that
self.results = anArray;
is the same as
[self setResults:anArray];
just because results is a property in this case.
The way setResults: is implemented is set by the #property (in this case it will retain the new value). So this means anArray will have a retain count of 1. After setting self.results, anArray will have a retain count of 2. This is why you want to release the previously used anArray.
That said, I don't understand why setResults: crashes when you're setting it. (Maybe it just crashes only when you try to use self.results, instead of setting it?)
I'm just a beginner myself, if something is wrong I strongly encourage everyone who reads this to let me know what is wrong or correct. Still learning this myself.
The way Apple would do this:
In the .h file
#property (nonatomic, retain) NSArray *results
In the .m file
#synthesize results;
- (id)init {
NSArray *anArray = [[NSArray alloc] init]; // retainCount = 1
self.results = anArray; // retainCount = 2
[anArray release]; // retainCount = 1, only one "left" is in self.results
}
- (void)dealloc {
[results release];
}
When you synthesize a property (see below)
#interface CelestialBody : NSObject {
NSString *name;
}
...
#interface Planet : NSObject {
NSString *name;
int mass;
CelestialBody *moon;
}
#property(nonatomic, retain) NSString *name;
#property(assign) int *mass;
#property(nonatomic, retain) CelestialBody *moon;
...
#implementation Planet
#synthesize name;
#synthesize mass;
#synthesize moon;
...
You get setters and getters for each of the iVars (i.e.)
[newPlanet setName:#"Jupiter"];
[newPlanet setMass:57];
NSString *closestName = [newPlanet name];
int largestMass = [newPlanet mass];
CelestialBody *newMoon = [[CelestialBody alloc] initWithName:#"Callisto"];
[self setMoon:newMoon];
[newMoon release];
but you also get the ability to release the object using ...
// Releases the object (frees memory) and sets the object pointer to nil.
[self setMoon: nil];
There will of course be deallocs for each Class.
// Moon
-(void)dealloc {
[name release];
[super dealloc];
}
// Planet
-(void)dealloc {
[name release];
[moon release];
[super dealloc];
}
Am I getting this right?
gary
Unless your planet object is declared as a property within some other class, using the retain/copy attributes, you can't release it this way.
When you declare a property using retain/copy, the resulting setter will release the old value and assign the new value, retaining or copying it in the process. If you pass nil, you will release the old value and assign nil, retaining or copying it, and retaining/copying nil is nil, so effectively you end up releasing the old value and assigning nil to the ivar.
This is an acceptable way to release instance variables.
In order to be able to release your newPlanet instance this way, you'd have to have declared it in a class as a property with either retain or copy.
As a further example, since your planet object declares its properties in this way, you could release those using this method.
Or in the Planet class's dealloc method, you could do:
self.name = nil;
This would release name and assign nil to it.
"you also get the ability to release the object"
Yes, as long as you didn't declare it with the assign attribute.
As you probably know, one of the reasons (although perhaps not the primary one) for using declared properties is that you can do:
self.moon = aMoon;
rather than;
[self setMoon:aMoon];
They are equivalent. That means that your deallocation can look like this:
self.moon = nil; // Releases and sets to nil
But remember to never just do:
moon = nil; // Sets to nil, doesn't release
It's very good practice to not only release the object, but to set the variable to nil, as you do, because otherwise some other code could mistakenly try to use the pointer that is left in the variable.
Your example shows the synthesis of one class's ivars (those of Planet) but the use of another (whatever "self" is). Is the "newPlanet" property of "self" in your last example also synthesized as (retain)? If so, then: Yes, setting newPlanet to nil will release whatever self's old "newPlanet" was.
I think you are not getting it right.
After your question update, yes, you can do that, and also:
self.moon = [[CelestialBody alloc] initWithName:#"Callisto"];
and release it later, probably in your dealloc method:
self.moon = nil;
Apple Objective-c 2.0 Properties and Memory Management docs are pretty good. Check Mac Dev Center library.