nesting "alloc" with a setter in Objective-C - objective-c

first question here, this is regarding the iPhoneOS3 not MacOSX. I am fairly new to Objective-C and I've never developed in a environment without automatic garbage collection so I am a little confused by this. Here's some valid code assigning a view controller to an app delegate from an example off Apple.com:
MyViewController *aViewController = [[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]];
[self setMyViewController:aViewController];
[aViewController release];
So, from what I understand, I must release aViewController because it is first allocated (+1 = 1); then retained in the setter (+1 = 2); then released in the setter (-1 = 1); and then no longer needed so finally released again (-1 = 0) and the memory is freed. Wel could I not just skip assigning the temporary object aViewController and nest these functions like so:
[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
I was wondering if this would work correctly? I am a little worried since the setter requires a pointer-to-ViewController instead of just a copy of one. And since I am only passing a return value, is the pointer-to-ViewController in the setter going to point to data that may be erased or lost before it can assign it? I am sorry if this seems like a dumb question, but I am having a hard time finding an answer anywhere, and I am trying to establish good techniques for non-garbage collection environments. Thanks!

Don't think of memory management in terms of absolute retain counts. Think of it entirely in terms of ownership and encapsulation.
When you alloc an object, you have created an object that you own. When you set that object as a value on another object, that other object should retain the object to express ownership. If your code is no longer interested in the object, you should then release (or autorelease it if you want to return it to something else).
[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
To answer your specific question, the above line of code, by itself, will cause a memory leak assuming that -setMyViewController: is implemented correctly.

I've decided that this code works sufficiently and doesn't cause a memory leak:
MyViewController *aViewController = [[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]] autorelease];
[setMyViewController:aViewController];
Thanks for all the help guys!

[self setMyViewController:[[MyViewController alloc]
initWithNibName:#"MyViewController" bundle:[NSBundle mainBundle]]];
here you allocate, then it is retained, so straight away you have a retain count of 2. but it would get set correctly, as you still pass the setter a pointer to the view controller.
If the property MyViewController was of type assign (not retain), you would only have a retain count of 1.

Related

When to use Self?

I am new to iOS development.
I have property as follows,
#property(nonatomic,retain)NSMutableArray *dataArray;
I am doing the following, to alloc it
self.dataArray=[[NSMutable alloc]init];
In the dealloc I am doing the following
-(void)delloc{
[dataArray release];
[super dealloc];
}
But I am getting memory leak for my array initialization.However , it doesn't create the
leak when I don't use self. But I wonder is it a write approach to initialise the array
without using self. Any help is appreciated.
You're getting a leak because the dataArray property is declared with retain, which means that when you use self (thus you use the setter), your retain count goes up to 2 and you only release it once. On the other hand, if you only use the ivar, the retain count is 1 (because of alloc) and you release it once, which is fine. To avoid the memory leak in the first situation, autorelease it like this.
self.data = [[NSMutableArray alloc] init] autorelease];
That will balance the retain count. As for access, except for inside the dealloc method, try to use self (setter and getter)
You should read the memory management docs, first thing to start with when developing for Cocoa Touch.
Also, why don't you use ARC?
If you use the self. signature you are accessing to the object via automatically generated / custom getter/setter. The setter will tipically manage the memory and you don't need to do that.
If you don't use self you access directly to the object.
The code what you presented is leaking, because the default setter of the dataArray will retain to the array, what you set with self.dataArray = [[NSMutableArray alloc] init];
The correct usage is:
self.dataArray = [[[NSMutableArray alloc] init] autorelease];
or:
_dataArray = [[NSMutableArray alloc] init];
What's happening here is that alloc is adding one to the retain count of the new object. The property reference is also retaining the object. If you want to do it this way, you only want one of those. A common method is:
self.dataArray = [[[NSMutableArray alloc]init] autorelease];
However, better still is to use ARC as #c.cam108 suggested and avoid the whole problem.

Managing Memory in Objective c

I am doing my project in xcode 4.2 (Older Version). For my application, I just set the variables, arrays in dto class for using in entire app lifecycle. so I set with a property like this.
AppDTO(sub class of NSObject)
AppDTO.h
#property(nonatomic,retain)anotherAppDTO *aAppDTO;
#property(nonatomic,retain)NSMutableArray *array1;
#property(nonatomic,retain)NSMutableArray *array2;
#property(nonatomic,retain)NSString *string1,*string2,*string3;
AppDTO.m
- (id)init
{
self = [super init];
if (self) {
self.aAppDTO = [[anotherAppDTO alloc]init];
self.array1 = [[NSMutableArray alloc]init];
self.array2 = [[NSMutableArray alloc]init];
self.string1 = #"Hello";
self.string2= #"Hai";
}
}
-(void)dealloc
{
if(array1 != nil)
{
[array1 release];
array1 = nil;
}
if(array2 != nil)
{
[array2 release];
array2 = nil;
}
[aAppDTO release];
aAppDTO = nil;
[super dealloc];
}
when I analyze my app in Xcode 4.3.2, I get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when I change self.array1 to array1, warning goes away.
What is the reason for using self. do I need to use self if I set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
Also in dealloc method, I heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
Do I need to release my string in dealloc method.
Also I am releasing aAppDTO in dealloc method. if I allocate some objects in anotherAppDTO class, will it release automatically when I call [aAppDTO release] method.
Can anyone clarify me.
Many Thanks,
Anish
You get the warning because when you write :
self.array1 = [[NSMutableArray alloc]init];
is the same as :
[self setArray1: [[NSMutableArray alloc]init]];
As you can notice you are not allocating the underlying array1 private variable, but you are calling the setter of the property that since it is declared as retain it retains the object once assigned, this means that when you eventually will assign another object the second time with the setter the first object will remain with a retain count of one until the application will be closed (since you don't have any reference to that object anymore ...) .
Take a look at this great article to understand better Manual Reference Counting in Objective-C .
when i analyze my app in Xcode 4.3.2, i get memory warning in self.array1 and self.array2 (Potential leak on object allocated on line….), but when i change self.array1 to array1, warning goes away.
the analyzer's right. the parameter is retained when set. as well, you should favor direct access in initialization and dealloc. so, you should just write array1 = [[NSMutableArray alloc] init];, and be done.
What is the reason for using self. do i need to use self if i set #property(nonatomic,retain) to variables(like array1,array2,string1,string2).
those go through the accessor methods. if not in initialization or dealloc, you should favor going through the accessor methods because that is the common correct execution path for a fully constructed object.
Also in dealloc method, i heard we don't want to use [self.array1 release], instead we can use [array1 release]. Is it Correct?
correct.
Do i need to release my string in dealloc method.
yes.
Also I am releasing aAppDTO in dealloc method. if i allocate some objects in anotherAppDTO class, will it release automatically when i call [aAppDTO release] method.
when its reference count reaches 0, its dealloc will be called.
I think the others have answered your question.
I do want to draw your attention to Apple's excellent Advance Memory Management Programming Guide: Practical Memory Management, in which they walk through these sorts of scenarios. It's hard to take it all in on the first reading, but it really does cover this stuff. In answer to your question about the use of instance variables versus the accessor methods, I draw your attention to the section labeled to "Don't Use Accessor Methods in Initializer Methods and dealloc".

Alloc a new objective C object to a retained property?

Sorry for asking a totally basic question, but if I have a synthesized property that is retained.
self.myProperty = [[NSObject alloc] init];
will cause a memory leak?
So am I correct in thinking that I need to do
self.myProperty = [[NSObject alloc] init];
[self.myProperty release];
in order to balance? Because that seems dumb.
Standard practice would be to use autorelease in that situation. So:
self.myProperty = [[[NSObject alloc] init] autorelease];
This is because init returns a retained object, and since your property also retains it, you'll have to release it.
Edited to add: #walkytalky makes a good point in the comments that it is actually alloc that retains the object, init just returns it.
Here is a thread that you will find helpful.
You are correct. Without ARC, any property that is retained needs to be released as well.
You can also do:
self.myProperty = nil;
From the docs:
retain
Specifies that retain should be invoked on the object upon
assignment.
The previous value is sent a release message.
Another (more verbose) technique is to do:
NSObject *o = [[NSObject alloc] init]; //retain count 1
self.myProperty = o; //retain count 2
[o release]; //retain count 1
Personally though, I'd probably just use autorelease as in the first example above.
With ARC enabled, xcode will handle alle the memory management.
When not using ARC be sure to release it in the dealloc method.

Correct memory management pattern for alloc/initing a view, adding to subview and returning

Im sure this sort of question has been asked to death and I understand what I should be doing, but its not working. My app is crashing:
Here's the code:
PDFViewController *cv = [[PDFViewController alloc] initWithNibName:#"PDFViewController" bundle:[NSBundle mainBundle]];
cv.view.frame = CGRectMake(0, 0, 1024, 748);
[self.view addSubview:cv.view];
Now, if I send a release message to the cv instance:
[cv release];
My application crashes. Same if I add it to the autorelease pool (on alloc/init).
Now my concern is this:
0) I'm alloc/init'ing, so its my duty to release (or add to auto-release pool).
1) Calling addSubview:cv.view increments the retain count of the cv.
2) I should be able to send it a release message, because it's being retained by the
self.view.
3) What's wrong?
TIA.
EDIT
Solution
PDFViewController *cv = [[PDFViewController alloc] initWithNibName:#"PDFViewController" bundle:[NSBundle mainBundle]];
[self presentModalViewController:cv animated:YES];
Calling addSubview:cv.view does not increments the retain count of the cv object. It does increments the retained count on "cv.view" therefore "self.view" only retains "cv.view".
cv.view is a getter that automatically has the view ivar calling autorelease. Your best bet is probably to create an ivar _cv and use that instead of a local variable. Then safely release the ivar in your dealloc: [_cv release]; _cv = nil;

Why always leak when using CLLocationManager?

myclass.m
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // send loc updates to myself
}
return self;
}
- (void)dealloc {
[locationManager release];
[super dealloc];
}
I use instrument to check leak. The leak always point to
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
Why?
I use instrument to check leak. The
leak always point to
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
Why?
Because that is the line of code where the allocation that is leaked occurred. Since you have balanced both implied retains in that code correctly (once here, once in -dealloc -- mmccomb's suggestion of direct assignment without autorelease is good, but won't fix the problem), the leak is elsewhere.
Specifically, the leak will be a retain that isn't balanced by a release. So, somewhere your are retaining the object and not releasing it.
Instruments can be used to show all retain/release events on any given object. Use that and look through the list of events related to your leaked object. There will be one more retain than release. Pair off the retains and releases. Whichever retain is left without a balanced release is the cause.
I wrote an article about using Heapshot analysis in Instruments to detect memory abuse. It includes discussion and screenshots showing the retain/release event inspector and will be applicable.
Try to avoid using the self. setter notation in init methods. When an object is being initialised there is no guarantee that it is in a consistent state. Change your implementation to directly set the ivar as follows...
locationManager = [[CLLocationManager alloc] init];
You no longer need the autorelease call which was previously accounting for the extra retain count brought about by invoking the setter. You do however need to release the object in your dealloc method (as you are already doing).
You can explicitly check the retain count in dealloc like so:
NSLog(#"locationManager retain count: %d", [locationManager retainCount]);
If it is more than 1, check where else you may be retaining it - like if you assign it to another retaining property (e.g. declared with retain keyword). You can add that NSLog call in other locations before and after you do something with locationManager and see where the retain count increases. Sometimes it may not be immediately obvious.
Another possibility: does the dealloc method even get called? Perhaps the whole "myclass" object is not properly released? (Although I suppose in that case you'd see a leak of type "myclass", too).