I'm developing an iPhone application.
I have the following property:
#property (nonatomic, retain) Point2D* endPoint;
And this is a method on the same class:
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
{
if (self = [super init])
{
endPoint = [[Point2D alloc] initWithX:x Y:y];
...
}
And finally the dealloc method on the same class:
- (void)dealloc {
[endPoint release];
[super dealloc];
}
My question is it this code correct?
endPoint = [[Point2D alloc] initWithX:x Y:y];
Or maybe I have to do an autorelease here.
Go read the memory management guide as it'll explain all of this and a lot more.
In short, that code is correct.
If you did self.endPoint = [... alloc/init ...], then you'd need to autorelease or release in init to balance the extra retain.
Your assignment
endPoint = [[Point2D alloc] initWithX:x Y:y];
does not increase the retainCount, so if you want to keep endPoint to use later you don't use autorelease here.
Or you can use like this
self.endPoint = [[[Point2D alloc] initWithX:x Y:y] autorelease];
=> This assignment will increase the counter of endPoint.
You shouldn't use endPoint directly but rather through self.endPoint.
#property (nonatomic, retain) Point2D* endPoint;
- (id)initWithX:(CGFloat)x Y:(CGFloat)y;
{
if (self = [super init])
{
self.endPoint = [[[Point2D alloc] initWithX:x Y:y] autorelease]; //It'll retain it for us.
...
}
- (void)dealloc {
self.endPoint = nil; //setting it to nil means it'll release the object it was previously pointing to.
[super dealloc];
}
change endPoint = [[Point2D alloc] initWithX:x Y:y]; to
Point2D *temp = [[Point2D alloc] initWithX:x Y:y];
self.endPoint = temp;
[temp release];
to take advantage of the properties retaining setter.
Related
I have following property in one of my class
#property (nonatomic, retain, readonly) NSMutableArray *children;
And I have following method to allocate memory to this property.
- (NSMutableArray *)children {
if (!children) {
children = [[NSMutableArray alloc] initWithCapacity:1];
}
return children;
}
When I run the profiler in the xcode it shows I have memory leak in the above method. I'm confused about releasing memory in such situation.
Is it ok if I use it with autorelase as follows.
children = [[[NSMutableArray alloc] initWithCapacity:1] autorelease];
can some one pls help me to solve this.
Do you release the children in your dealloc? If not, thats your problem!
- (void)dealloc {
[children release];
...
[super dealloc];
}
Why don't you let the compiler do the work for you? You could do the following:
- (id) init {
if(self=[super init]) {
children = [[NSMutableArray alloc] init]
}
Use the dealloc iTukker showed you and make the property synthesized.
At least for me this is far more straightforward.
Somewhere on .h I put
#property (nonatomic, retain) NSMutableArray * BusinessQueue;
-(BNUtilitiesQuick *) init {
if (!(self = [super init]))
{
return nil;
}//if the superclass is NSObject, this must be init
self.locationManager = [[[CLLocationManager alloc] init]autorelease];
BusinessQueue = [[[NSMutableArray alloc]init]autorelease];
return self; //and return the object itself
}
The way I see it BusinessQueue = [[[NSMutableArray alloc]init]autorelease]; will make reference count 1. 1 for alloc. -1 for autorelease (sometimes latter) and 1 because BusinessQueue is a retain property.
However, BusinessQueue will get deallocated sometimes usually.
Why BusinessQueue always error but location manager doesn't
any wrong code? or NSMutableArray Can't be declared at init class?
BusinessQueue is not a property. self.BusinessQueue may be, if you defined it that way.
Added:
And the best/simplest way to do the initialization is:
self.businessQueue = [NSMutableArray array];
I have a string (titleName) stored in a class (newNoteBook) stored in an array (myLibrary). I was trying to access it, but I only get a (null) printed in the log.
What am I doing wrong?
-(void) setupLibrary {
NoteBook *newNoteBook = [[NoteBook alloc] init];
newNoteBook.titleName = #"TEST";
NSLog(#"titleName:%#", newNoteBook.titleName); // this prints TEST in the log
[myLibrary addObject:newNoteBook];
NSLog(#"titleName:%#", [[self.myLibrary objectAtIndex:0] titleName]); // this prints (null) in the log)
}
There is nothing fancy in my class... simply:
#interface NoteBook : NSObject {
NSString *titleName; }
#property (nonatomic, retain) NSString *titleName;
#end
#implementation NoteBook
#synthesize titleName;
Try this
NSLog(#"titleName:%#", ((NoteBook *)[self.myLibrary objectAtIndex:0]).titleName);
Possible reasons:
myLibrary (the instance variable) is nil;
self.myLibrary is nil or its backing instance variable isn’t myLibrary;
[self.myLibrary objectAtIndex:0] is not the same object as newNoteBook because there was at least one other element in self.myLibrary.
Edit: you need to create a new mutable array and assign it to your property/instance variable myLibrary:
self.myLibrary = [NSMutableArray array];
or
myLibrary = [[NSMutableArray alloc] init];
Where you should this depend on how your class is used. If an instance of your class should always have valid myLibrary, a good place to do that is in -init:
- (id)init {
self = [super init];
if (self) {
myLibrary = [[NSMutableArray alloc] init];
}
return self;
}
Alternatively, if you want to lazily create myLibrary only when -setupLibrary is executed, create it in that method:
-(void) setupLibrary {
self.myLibrary = [NSMutableArray array];
NoteBook *newNoteBook = [[NoteBook alloc] init];
…
}
Don’t forget to release it in your -dealloc method:
- (void)dealloc {
[myLibrary release];
[super dealloc];
}
I think you are not type casting object from array -
NSLog(#"titleName:%#", [(NoteBook*)[self.myLibrary objectAtIndex:0] titleName]);
and you should alloc your array before adding object to it -
myLibrary = [[NSMutableArray alloc] init];
NSLog(#"titleName:%#", [self.myLibrary objectAtIndex:0].titleName);
Is correct as they said before you don't need to cast.
Until yesterday I thought that I had understood the iPhones memory management.
Well here is my problem:
// .h file
#property(nonatomic, retain) NSMutableDictionary *dicParams;
#property(nonatomic, retain) NSMutableDictionary *dicReferences;
#property(nonatomic, retain) FtMonitorHandler *monitorHandler;
// .m file
#synthesize dicParams, dicReferences, monitorHandler;
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
- (void)dealloc {
[monitorHandler release];
[dicParams release];
[dicReferences release];
[super dealloc];
}
If I set somewhere else, after the viewcontroller's allocation for example
self.dicParams = dicValues;
… it will turn into a leak
My understanding of setting instance variables with "self. …" was, that the current value will be "released" and then set with "retain".
I tried a little bit with instruments. Results:
-(void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = [[NSMutableDictionary alloc] init];
}
-(void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = nil;
self.dicParams = [[NSMutableDictionary alloc] init];
}
- (void)createWithoutLeak {
if(dicParams != nil) [dicParams release];
self.dicParams = [[NSMutableDictionary alloc] init];
}
Have I missed something, or is this the behavior as it should be?
EDIT: I tried to implement the suggested changes. It works fine, as long, as my variable is not GUI element. (UIView, UILabel, etc)
The autorelease will cause an app crash after a memory warning
- (void)loadView {
[super loadView];
// ... here is some other stuff ...
self.lblDeparture = [[[UILabel alloc] init] autorelease];
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
self.lblDeparture = nil;
}
- (void)dealloc {
[lblDeparture release];
[super dealloc];
}
I'm not quite sure, but I assume that the following lines are the real issue:
CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, INFO_VIEW_HEIGHT);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
[imageView addSubview:lblDeparture];
[lblDeparture release]; // is this correct?
[self.view addSubview:imageView];
[imageView release];
if you init you need to auto release.
-(void)dontCreateAnotherLeak {
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
self.dicParams = nil;
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
}
the easier equivalent is to use the convenience accessor.
self.dicParams = [NSMutableDictionary dictionary];
if you would like to handle this yourself. On top of the #synthesize dictParams; you will also want to create your own setter.
-(void)setDictParams:(NSMutableDictionary*) newDictParams
{
if (dictParams != newDictParams)
{
[dictParams release];
dictParams = [newDictParams retain];
}
}
this is a little simple. but essentially what the compiler creates with the retain modifier added to the #property tag
If you set a instance variable for which you have specified retain in property retain count becomes 1
Now as you call with reference to self as in case “self.variable = value” increase the retain count by 1, So the total retain count becomes 2.
So now to release it you need to bring retain count to 0. Hence you need to release it twice.
Hopew this helps.
I am not sure I understand the question fully, however your second part is easily explained...
-(void)createLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = [[NSMutableDictionary alloc] init];
that's clear...
now but this one
-(void)createAnotherLeak {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicParams = nil;
self.dicParams = [[NSMutableDictionary alloc] init]; }
does not release the first alloced self.dicParams but rather forgets any reference to it by setting it to nil and then resetting it with a new one. Setting to nil is not equal to release. If you would have created the first one with autorelease and then set it to nil it's something different. That should work correctly. And that's exatcly what you do with your 3rd example!
Now as to your inital question, what is it that leaks when you write
self.dicParams = dicValues;
?
the variable self.dicParams should just hold the value until you release it again
I recommend you read Apple's Memory Management Programming Guide carefully. http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
It's all explained in there.
There are a couple of obvious mistakes I can see that you are making.
Firstly, you shouldn't use accessors in init or dealloc.
So, this
- (id)init {
self = [super init];
if (self) {
self.dicParams = [[NSMutableDictionary alloc] init];
self.dicReferences = [[NSMutableDictionary alloc] init];
self.monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
should be
- (id)init {
self = [super init];
if (self) {
dicParams = [[NSMutableDictionary alloc] init];
dicReferences = [[NSMutableDictionary alloc] init];
monitorHandler = [[FtMonitorHandlerService alloc] init];
}
return self;
}
Secondly, when you set a retained property, the you need to release the whatever you are setting it to.
So, this
self.dicParams = [[NSMutableDictionary alloc] init];
should be
self.dicParams = [[[NSMutableDictionary alloc] init] autorelease];
or you can do this
NSMutableDictionary *newDicParams = [[NSMutableDictionary alloc] init];
self.dicParams = newDicParams;
[newDictParams release];
The setter generated by #synthesize for a (readwrite, retain, nonatomic) property looks something like this:
- (void) setSomething: (id) newSomething;
{
if (something != newSomething) {
[something release];
something = [newSomething retain];
}
}
The old object pointed to by the instance variable something will be released while the new object will be retained.
Your mistake is the object creation. You create your dictionary with [[NSDictionary alloc] init]. This dictionary has a retain count of 1. Your setter retains the object, so the new retain count is 2. When you call the setter again the retain count of your original dictionary correctly gets decreased - it’s 1 again. For the dictionary to be freed you’d have to release it again. For this there is autorelease. An autoreleased object will get released some time later. So the correct code to set your property would be
self.something = [[[NSDictionary alloc] init] autorelease];
or even better using the convenience allocator
self.something = [NSDictionary dictionary];
You really should read and understand Apple’s memory management guide - it’s all explained in there.
By the way, I talked about retain counts here. It’s OK to think about them, but you should never ask an object about it’s retain count, that value is useless, since it’s rarely what you would think.
When should I be releasing [self.activeLocations], which is an NSMutableArray inside my custom object? I am also getting memory leaks in initWithValue.
Also the Location object below. Am I calling this and releasing this properly?
Method in Custom Object.m:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.couponId = [value valueForKey:#"couponId"];
self.couponName = [value valueForKeyPath:#"couponName"];
self.qrCode = [value valueForKeyPath:#"description"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.categoryName = [value valueForKeyPath:#"categoryName"];
self.distance = [value valueForKeyPath:#"distance"];
NSDictionary *activeLocationsDict = [value valueForKeyPath:#"activeLocations"];
//self.activeLocations = [[[NSMutableArray alloc] init] autorelease];
self.activeLocations = [NSMutableArray array];
for (id val in activeLocationsDict) {
// Add JSON objects to array.
Location *l = [[Location alloc] initWithValue:val];
[self.activeLocations addObject:l];
[l release];
}
}
return self;
}
- (void)dealloc {
[super dealloc];
couponId = nil;
couponName = nil;
qrCode = nil;
companyName = nil;
categoryName = nil;
distance = nil;
activeLocations = nil;
}
My Custom Object.h
#interface Coupon : NSObject {
NSNumber *couponId;
NSString *couponName;
NSString *qrCode;
NSString *companyName;
NSString *categoryName;
NSString *distance;
NSMutableArray *activeLocations;
}
#property (nonatomic, copy) NSNumber *couponId;
#property (nonatomic, copy) NSString *couponName;
#property (nonatomic, copy) NSString *qrCode;
#property (nonatomic, copy) NSString *companyName;
#property (nonatomic, copy) NSString *categoryName;
#property (nonatomic, copy) NSString *distance;
#property (nonatomic, retain) NSMutableArray *activeLocations;
- (id)initWithValue:(NSString *)value;
This is how I'm using the above initWithValue:
- (NSMutableArray *)createArrayOfCoupons:(NSString *)value {
NSDictionary *responseJSON = [value JSONValue];
// Loop through key value pairs in JSON response.
//NSMutableArray *couponsArray = [[NSMutableArray alloc] init] autorelease];
NSMutableArray *couponsArray = [NSMutableArray array];
for (id val in responseJSON) {
// Add JSON objects to array.
Coupon *c = [[Coupon alloc] initWithValue:val];
[couponsArray addObject:c];
[c release];
}
return couponsArray;
}
I get memory leaks on initWithValue in the above method as well...
Location Custom Object:
- (id)initWithValue:(NSString *)value {
if ((self = [super init])) {
self.locationId = [value valueForKeyPath:#"locationId"];
self.companyName = [value valueForKeyPath:#"companyName"];
self.street1 = [value valueForKeyPath:#"street1"];
self.street2 = [value valueForKeyPath:#"street2"];
self.suburb = [value valueForKeyPath:#"suburb"];
self.state = [value valueForKeyPath:#"state"];
self.postcode = [value valueForKeyPath:#"postcode"];
self.phoneNo = [value valueForKeyPath:#"phoneNo"];
self.latitude = [value valueForKeyPath:#"latitude"];
self.longitude = [value valueForKeyPath:#"longitude"];
}
return self;
}
- (void)dealloc {
[super dealloc];
locationId = nil;
companyName = nil;
street1 = nil;
street2 = nil;
suburb = nil;
state = nil;
postcode = nil;
phoneNo = nil;
latitude = nil;
longitude = nil;
}
- (id)init {
....
}
Get rid of this. It does nothing.
- (id)initWithValue:(NSString *)value {
[super init];
There's a specific pattern you should use for initialization:
- (id)initWithValue:(NSString *)value {
if (( self = [super init] )) {
// everything except the return
}
return self;
}
Finally, to answer your actual question, assuming you're using retain with your property, there's two places you'll need to release.
Here's the first:
self.activeLocations = [[NSMutableArray alloc] init];
Why: [[NSMutableArray alloc] init] makes your code own the object by retaining it. But the property set also claims ownership by retaining it. You don't really want this NSMutableArray owned by the code and your custom object, you want it owned by your object.
My suggestion is to just use this:
self.activeLocations = [NSMutableArray array];
The second place is in your dealloc:
- (void)dealloc {
self.activeLocations = nil;
// ...and everything else you've set as a property using retain
[super dealloc];
}
(Personally, I've gone back and forth on whether to use dot notation in dealloc rather than [activeLocations release];. I'm favouring setting to nil using the property now, which puts all the memory management rules in a single location.)
Apple has a great document on memory management you should read: Memory Management Programming Guide: Object Ownership and Disposal.
First of all, your overridden -init method is completely unnecessary because by default when a method is invoked, the runtime will perform an upward traversal of the inheritance hierarchy until the specified method is found, so it will find NSObject's -init method and invoke it.
Second, you should invoke release on all of your owned properties (ones with copy or retain) in your overridden -dealloc method.
Third, in your case, when you call the property setter passing in an object that is already owned locally, you must send the object the release message after invoking the setter to correctly hand off ownership of the object to the receiver.
There are two ways to do this:
One way is to create an object that you own using alloc, copy or new, and then invoke the property setter, passing in that object, then send it the release message.
Another way is to pass in an autoreleased object to the property setter, which will then retain or copy its argument and thereby obtain ownership
The answer to when you should be releasing it is a question of whether or not the activeLocations array and all the elements in that array (remember each element in the array is retained by the array itself) are necessary throughout the lifetime of the Location object.
If you use the activeLocations array for some temporary purpose, for example in a method or chain of methods, then don't need it again, or you plan to refresh its members at some later time when you need it next, then it makes sense to release the array (and its elements, which is automatic) when you're done using it, in whatever function last uses the array. You will use the convention
self.activeLocations = nil;
to let the runtime system release the array and set the member to nil.
If, on the other hand, the activeLocations array data is mandatory for the Locations object to function and must exist as long as the Location object exists, then you will want to release the array inside the dealloc method of the Location object, for example:
- (void) dealloc {
[activeLocations release];
[super dealloc];
}
As it happens, you're pretty much always going to want to release member objects such as activeLocations in a dealloc method. This ensures that when the Location object is released the members it contains are cleaned up. Remember that Objective-C does not call methods on null pointers, so if you have previously set activeLocations to nil the call in dealloc is a safe no-op.
Given then that you'll always set things up to release in dealloc, now you really just have to ask yourself if you need a release/recreate phase somewhere in your object lifecycle (again, determined by frequency-of-use requirements).
It depends on what you're asking. In the initWithValue: method that you've shared, you are double-retaining the array. It should be released or autoreleased once within initWithValue:.
The array should be released a second time in the custom object's dealloc method.