#interface{
NSArray *array;
}
#property (nonatomic, retain) NSArray *array;
#end
#implementation
#synthesize array;
self.array = [[NSArray alloc] init];
array = [[NSArray alloc] init];
[self.array objectAtIndex:2]; [array objectAtIndex:2];
#end
Is there a difference between them? Why should I use one over the other?
self.array = foo is shorthand for [self setArray:foo] (i.e. you access the synthesized property methods), while just array = foo directly accesses the instance variable.
In exactly this case, you would create a memory leak with self.array = [[NSArray alloc] init]; since the property will retain it and the reference count would thus be 2 instead of 1. So better would be: self.array = [NSArray array];.
Which one to prefer is almost a matter of taste, but using the properties gives you a few advantages like automatic key-value coding support. It's also an advantage if you someday chose to do implement setArray: yourself so it can do additional stuff when the array is assigned (like reloading a UITableView). On the other hand, it's a little bit slower as it's an additional method call (only matters if called in a loop a lot). But for almost all applications it's better to be correct than as fast as possible. Using properties can make memory management easier for you.
The property "array" is declared to retain on assignment (the retain in the brackets after #property signifies this). Because it has the same name as the "array" instance variable it uses that instance variable as it's backing store.
Effectively calling self.array = [[NSArray alloc] init]; is the same as calling array = [[[NSArray alloc] init] retain];
When you assign to the instance variable directly, not using the property, no action is taken on it, so array simply points to a new instance of NSArray without retaining it.
Related
So in one of my Objective C classes I have a strong property say:
#property(nonatomic, strong) NSMutableArray *tags;
Which of the following is a better way to initialise this property
1 self.tags = [[NSMutableArray alloc] init];
or
2 self.tags = [NSMutableArray array];
With ARC, there is almost no difference. [NSMutableArray array] returns an "unretained
return value" which might have been put into the autorelease pool (and that actually happens
in your example, which you can see by inspecting the generated Assembler code).
This additional reference is released later, when the current autorelease pool ends.
So there is a slight overhead in the second method.
On the other hand, the Objective-C runtime has various methods to avoid unnecessary
retain/release calls (e.g. by inspecting the call stack), so the difference might be negligible.
It depends on your definition of better. First, if you are in the init method, you should not use self.tags = for the assignment at all, as you should not call methods from the init methods. Instead, access the instance variable directly:
_tags = ...;
As for the possible ways of doing it:
_tags = [[NSMutableArray alloc] init];
is currently a bit faster than
_tags = [NSMutableArray array];
but is also longer. And we should never optimize for a performance problem we haven't measured. If you are going for readability and short code, I would suggest a third option:
_tags = [NSMutableArray new];
In fact you can have even shorter code, but it may make your eyes bleed:
_tags = [#[] mutableCopy];
Extra track: Early in ARC the default for object properties has been assign, but it changed to strong pretty fast. So instead of
#property(nonatomic, strong) NSMutableArray *tags;
you can just use
#property(nonatomic) NSMutableArray *tags;
If I have a variable in my view controler
viewcontroller.m
#interface MemoryTestViewController : UIViewController
{
NSMutableArray *array;
}
#end
in my implementation
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *aux = [[NSMutableArray alloc] initWithCapacity:1];
array = aux;
[aux release];
// Do i have to do array release?
}
Do i have to release my variable array somewhere? Theoricaly i havent allocated that variable...
I testes the memory leaks and even if i dont release anything the instruments doesn't detect any leak.
No, you don't need to release. All you do is assign the pointer of aux to your array variable.
array is invalid at the moment where you release aux.
This is probably not as intended. If you want to work with array, you'll have to retain it.
You've already released the array with [aux release]; -- you in fact have the opposite problem to a leak: an over-release.
Assignments in Objective-C are just assignments of pointers; there's no copying or automatic memory management. When you say array = aux;, array now points to the exact same object as aux. If you then get rid of aux by releasing it (and therefore letting it be deallocated), array doesn't point to anything anymore.*
You have a couple of options for fixing this:
(Simplest) Assign the newly-created array directly to array:
array = [[NSMutableArray alloc] initWithCapacity:1];
This gives you ownership of the new array, under the name array. Don't release it until you are done with it (possibly in dealloc; certainly not in this method).
(Best) Create a declared property for array and let that mechanism handle the memory management for you:
#interface MemoryTestViewController : UIViewController
{
NSMutableArray *array;
}
#property (copy, nonatomic, setter=setArrayByMutableCopy) NSMutableArray * array;
#end
#implementation MemoryTestViewController
#synthesize array;
// Properties can't automatically make mutable copies, so you need to create
// your own setter method.
- (void) setArrayByMutableCopy: (NSMutableArray *)newArray {
NSMutableArray * tmp = [newArray mutableCopy];
[array release];
array = tmp;
}
...
*Or, rather, it points to a place where there used to be a valid object, which is a great way to make your program crash.
No. Assigning an object to a variable does not retain it. However if you plan to use that variable for a while, you should retain it and release it when you are done with it.
alloc raised the retain counter to 1 and [aux release] set it to 0
You should add a property:
#property (nonatomic, retain) NSMutableArray *array;
and later in your viewDidLoad:
// wrong, leaks: self.array = [[NSMutableArray alloc] initWithCapacity:1];
array = [[NSMutableArray alloc] initWithCapacity:1];
and yes, somewhat later release it, probably in dealloc..
the xcode analyzer tell me that a method returns an Objective-C object with a +1 retain count:
but the self.athletes is an object that I need also outside my function... how can I solve this 'warning?
thanks again
the athletes is declared like this:
NSMutableArray *athletes;
#property (nonatomic, retain) IBOutlet NSMutableArray *athletes;
Replace that line with this one:
self.athletes = [NSMutableArray array];
I wrote full explanation here : Memory Management for properties with retain attribute
Since your property is defined with "retain", using the dot notation will result in an extra retain. The return from the [[NSMutableArray alloc] init] has a retain count of 1, and then when you set the property using the setter function generated by the property declaration it will have a retain count of 2.
To fix, either:
self.athletes = [NSMutableArray array]; // Returns an autoreleased object
Or, you could also do this:
athletes = [[NSMutableArray alloc] init]; // Doesn't use the setter generated by the property declaration, so doesn't retain again.
There is a nice way to handle this (and you have already used this pattern while creating UI ).
NSMutableArray *athletesTemp = [[NSMutableArray alloc] init];
self.athletes = athletesTemp;
[athletesTemp release];
Here you don't need to carry the load of an auto release object.
I have a class which contain a NSArray object.
like this
#import <Foundation/Foundation.h>
#interface myClass : NSObject {
NSArray *myArray;
}
#property (nonatomic, retain) NSArray *myArray;
#end
In .m file, I init myArray in init method,and release myArray in dealloc method.
in a method, I create its object and add it to a NSMutableArray.
myClass *my = [[myClass alloc] init];
NSLog(#"init finish %d",[my retainCount]);
NSMutableArray *a = [[NSMutableArray alloc] init];
[a addObject:my];
NSLog(#"array added finish %d",[my retainCount]);
NSLog(#"array added finish %d",[my.myArray retainCount]);
[my release];
When i add object "my" to NSMutableArray, the retainCount of "my" was added.
but myArray wasn't. Did it mean that I must retain myArray by my self?
or something other I can do.
Can this code work normal after I release "my" object?
[a objectAtIndex:0];
Thanks!
Another great example of exactly why you should...
NEVER call -retainCount!
retainCount is useless, misleading and a waste of your time.
In this case, the reason why the retain count happens to be zero "unexpectedly" is because my.myArray returns nil. That happens because you never assign the created mutable array to myArray.
You need something like this (Class name capitalized to follow convention):
MyClass *my = [[MyClass alloc] init];
NSMutableArray *a = [[NSMutableArray alloc] init];
my.myArray = a;
[a addObject:my];
Note that this creates a retain cycle between my and the array. I.e. you will need to remove my from the array manually (or remove the array from my manually) whenever you release myArray and, of course, you can't do that in dealloc because dealloc will never be called until my has been removed from myArray.
I am not sure if that is the full source code above but for my.myArray to be retained you have to actually assign something to it.
So in your above example you created an NSMutableArray:
NSMutableArray *a = [[NSMutableArray alloc] init];
And then you added your class to it:
[a addObject:my];
But no where have you created an array and assigned it to myClass as in:
NSArray *anArray = [[NSArray alloc] init.....];
my.myArray = anArray;
At that point, myArray will get a reference to an object and will retain it (since you specified retain in your myArray prop declaration).
Perhaps if you clarified what it is you are trying to do or posted some more full source code?
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];
}