Im wondering if calling [[MyClass alloc] init] on an already existing (allocated) object create a leak in ARC? or does it manage the release and reallocation for you?
would doing the following be more proper:
myObject = nil;
myObject = [[MyClass alloc] init];
which is more appropriate? is there another way to do this properly?
With ARC, you don't need to set the myObject to be nil before reallocating it,only this line of code will be fine:
myObject = [[MyClass alloc] init];
When xcode compiles the code, it will automatically add the right release mechanism in.
Related
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Use autorelease when setting a retain property using dot syntax?
What is difference between using ivars and self. notation?
instanceVar is instance variable declared with retain.
1) instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"]; //do I need autorelease here?????
2) self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"] autorelease];
Also, Do I need autorelease in the first situation?
This is explained in multiple places but seems as you asked what the different is
The first call is unchanged and looks like this:
instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
The second call when compiled will look something like this (assuming you have used a #property with retain and #synthesize:
self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
// The previous line will compile to this next line
[self setInstanceVar:[[NSMutableArray alloc] initWithObjects:#"1", #"2"]];
The body of the - (void)setInstanceVar:(NSMutableArray *)instanceVar; method will look something like this (the compiler create this for you because of your #property and #sythesize):
- (void)setInstanceVar:(NSMutableArray *)anInstanceVar
{
if (instanceVar != anInstanceVar) {
[instanceVar release];
instanceVar = [anInstanceVar retain];
}
}
Therefore in the call
self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"];
You have the +1 retain count on the newly created NSMutableArray and then you have the +1 retain count added from going through the setter.
This means that you require the extra release to match retains you are taking. It is considered better to not use autorelease in iPhone so you can be sure memory is being freed when you want it to. Therefore you should normally take the pattern
Create local var
Assign local var to ivar through setter
release local var
Which looks like this (FIXED thanks to #jamapag)
NSArray *tmpMyArray - [[NSArray alloc] initWithObject:#"Hello"];
self.myArray = tmpMyArray;
[tmpMyArray release]; tmpMyArray = nil;
1) instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"]; //do I need autorelease here?????
The NSmutableArray is created with a retain count of 1, you need to release your instanceVar in your dealloc() method
2) self.instanceVar = [[NSMutableArray alloc] initWithObjects:#"1", #"2"] autorelease];
Here you are using the setter, and since it is declared with retain it will increase its retain count by 1, the alloc init already increased the retain count by 1, so the total retain count is 2. However the autorelease msg will decrease this by 1 probaby in the next run loop. So again you only have to release this on your dealloc() method.
In the first situation you probably DO NOT want to autorelease, since this is an IVar you will probably want to use it again, and if you autorelease it the retain count will be 0 soon (most likely in the next run loop)
#interface Approval : NSObject
{
NSMutableArray *approvalValues;
}
#property (nonatomic,retain) NSMutableArray *approvalValues;
If i do this, do I still need to call `approvalValues = [[NSMutableArray alloc] init] in the init method? I was under the impression that I had to but it is causing a leak. In the dealloc method I am releasing approvalValues
You need to alloc and init approvalValues. The problem seems to be related to the fact that you are over-retaining your object.
Your code probably looks like this:
self.approvalValues = [[NSMutableArray alloc] init];
alloc will return an object with a retainCount of 1, and when using the retain setter it will get bumped to 2. In order to solve it, you might want to autorelease the object before assigning it, making a code that looks like this:
self.approvalValues = [[[NSMutableArray alloc] init] autorelease];
This will end up with an instance variable with a retainCount of only 1, so when you dealloc the object it won't leak.
Yes you still need to alloc/init, however you only release in dealloc method.
In the init method you will often access the ivar directly and initialize it like this:
approvalValues = [[NSMutableArray alloc] init];
In the dealloc you will need a matchin release like this:
[approvalValues release];
It is often recommended to access the ivars directly in the init and dealloc method to avoid any side effects caused by setters/getters.
Throughout your class you will want to use the KVC setters/getters or dot notation to set objects like this
// Dot notation
NSMutableArray *tmpApprovalValues = [[NSMutableArray alloc] init];
self.approvalValues = tmpApprovalValues;
[tmpApprovalValues release]; tmpApprovalValues = nil;
// Call to setters/getters
NSMutableArray *tmpApprovalValues = [[NSMutableArray alloc] init];
[self setApprovalValues:tmpApprovalValues];
[tmpApprovalValues release]; tmpApprovalValues = nil;
Corrected terminology thanks to #Yuji
Ok, here goes.
Being a Java developer I'm still struggling with the memory management in ObjectiveC. I have all the basics covered, but once in a while I encounter a challenge.
What I want to do is something which in Java would look like this:
MyObject myObject = new MyObject(new MyParameterObject());
The constructor of MyObject class takes a parameter of type MyParameterObject which I initiate on-the-fly.
In ObjectiveC I tried to do this using following code:
MyObject *myObject = [[MyObject alloc] init:[[MyParameterObject alloc] init]];
However, running the Build and Analyze tool this gives me a "Potential leak of an object" warning for the MyParameter object which indeed occurs when I test it using Instruments. I do understand why this happens since I am taking ownership of the object with the alloc method and not relinquishing it, I just don't know the correct way of doing it.
I tried using
MyObject *myObject = [[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]];
but then the Analyze tool told me that "Object sent -autorelease too many times".
I could solve the issue by modifying the init method of MyParameterObject to say return [self autorelease]; in stead of just return self;. Analyze still warnes about a potential leak, but it doesn't actually occur. However I believe that this approach violates the convention for managing memory in ObjectiveC and I really want to do it the right way.
Thanx in advance.
Ok, here's a suggestion.
MyParameter *param = [[MyParam alloc] init];
MyObject *obj = [[MyObject alloc] initWithParam:param]; // do you know if param is retain'd or not?
[param release];
Why do it this way? This is the pattern used throughout ObjC/Cocoa. You add objects to NSArrays this way:
MyThing *thing = [[MyThing alloc] init];
[myMutableArray addObject: thing]; // this calls [thing retain]
[thing release];
You may also want to try to do this:
MyObject *obj = [[MyObject alloc] initWithParam: [MyParameter parameter]];
where:
+ (id) parameter
{
return [[[self alloc] init] autorelease];
}
that way you don't have to worry about it. This is the same as
[NSData data];
[NSArray array];
I hope that helps. Generally, it isn't a good idea to use init during another method call (like a setter or another init). Hiding it behind a Class Method (+ (id) parameter) means the user knows it'll be autorelease'd.
If you're ever unclear about how many retain's or release's something has, you can always do something like this:
[EDIT]
Caveat: Apparently you should never use -retainCount. I find it useful for teaching learners the basics of retain'd Memory Management, but the point is well taken.
Never Use it in actual code or for performance testing. This is only used to learn what retain does (and I believe it functions properly in this case). It will never give you an intelligent answer for an object which is autorelease'd or further retain'd by a NSArray or Other Foundation/AppKit/UIKit Classes
MyParameter *param = [[MyParam alloc] init];
NSLog(#"param retain count: %d",[param retainCount]); // should be 1
MyObject *obj = [[MyObject alloc] initWithParam:param];
NSLog(#"param retain count: %d",[param retainCount]); // should be 2, if MyObject retains it.
[param release];
NSLog(#"param retain count: %d",[param retainCount]); // should be 1
Also, when you dealloc MyObject, you'll need to release param if you retain'd it during initialization.
The following guide put out by Apple should help you to understand Objective-C Memory Management a little better.
MyThing *thing = [[MyThing alloc] init];
[otherThing methodWithAThing:thing];
[thing release];
or:
[otherThing methodWithAThing:[[[MyThing alloc] init] autorelease]];
or (if there is a "convenience constructor" on the class you're using):
[otherThing methodWithAThing:[MyThing thing]];
MyObject *myObject = [[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]];
should be ok, if there is no release in the init (there should definitely not be a release in the init). I often make a class method which makes a autoreleased object. So the code would be:
// using it:
MyObject *myObject = [[MyObject alloc] init:[MyParameterObject defaultParameters];
// in the class implementation of MyParameterObject
+ (MyParameterObject*) defaultParameters{
MyParameterObject* out = [[MyParameterObject alloc] init];
// set some values
return [out autorelease];
}
[[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]]
Without knowing what's going on in the init method, this seems fine.
NB, though, that it's more Objective-Cish to spell this "initWithParameterObject:". Though they gag people new to the language, Obj-C's descriptive method names are actually really helpful for code readability.
I am developing an iphone app. Instruments reported a leaked object ServiceTypes. Below is the relevant code. Does anyone have any ideas? Thanks a lot for your help.
ServiceTypes *serviceTypes = [[ServiceTypes alloc] init];
if ([userConnection getServiceTypes:serviceTypes]) {
if ([serviceTypes.types length] > 0) {
NSArray *array = [[NSArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString: SERVICE_TYPE_DELIMITOR]];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:array];
[array release];
}
}
[[self typesTableView] reloadData];
[serviceTypes release];
It doesn't look like serviceTypes is being leaked. From the code you posted, serviceTypes is always released at the end of the method, and it doesn't appear to be retained anywhere in your sample. My question is: what happens inside getServiceTypes:. Does that method retain the serviceTypes parameter?
One more thing. If serviceRequestTypes is an instance variable (and it looks like it is), then you may be leaking memory by reassigning it without releasing the existing serviceRequestTypes object first. You should either rewrite serviceRequestTypes to be a property and use a synthesized accessor or make sure to release it every time before assigning. If its current value is nil, no big deal; the release message will simply be ignored. For example:
[serviceRequestTypes release];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString:SERVICE_TYPE_DELIMITER]];
SomeObject *temp = [[SomeObject alloc] init]
self.theObject = temp;
[temp release];
Why is it always done that way? Why not
self.theObject = [[SomeObject alloc] init];
If the theObject property is a retaining property, the first way is correct, because it doesn't leak memory. It's also more efficient than the correct way to write the second version, which is this:
self.theObject = [[[SomeObject alloc] init] autorelease];
Whenever you create an object with alloc you're in charge of releasing it somehow, whether by release or autorelease.
The second version leaks the SomeObject instance, since self.theObject will call a setter that, if properly written, retains the object.
You could just do
theObject = [[SomeObject alloc] init];
and some people certainly do. Others prefer to always use accessors though, either for consistence or to avoid bugs if the accessors have side effects (for exmaple, you would be bypassing KVO notification, which could be a problem if it's not part of an init method).