I'm wondering if I am managing the memory of an Array correctly. Below I use this array with a tableView, so I want to keep it around for the life of the ViewController. Since I create it as a property I'm a little confused on the retain count and how to handle it since I'm alloc'ing it in the code. Below is how I currently have it coded.
in .h
#property (nonatomic, retain) NSMutableArray *mutableArray;
in .m
self.mutableArray = [NSMutableArray alloc] init];
//fill with object I'm going to be using throughout the life of the viewController
- (void) dealloc {
[mutableArray release];
[super dealloc];
}
Thank you!
You will leak your array if you're doing it that way. because your property is set to retain, self.mutableArray = [[NSMutableArray alloc] init]; is the same as mutableArray = [[[NSMutableArray alloc] init] retain];.
So change it to
self.mutableArray = [NSMutableArray array];
iOS will do memory management by itself. Here is Apple Arc Documentation. There is also an excellent condensed information about memory management from Mikeash Friday Q&A blog
Related
Is my following code contains a memory leak?
please help me here!
NSMutableArray *arrInfo = [[NSMutableArray alloc] init];
appDelegate.arrAppInfo = arrInfo;
[arrInfo release];
What you did is perfectly valid in a non-ARC environment IF the property arrAppInfo is declared as a retain (or strong) property. In fact what ARC does in a similar situation is just putting a release when it detect that the arrInfo property is no longer used in the current scope.
To go deep:
NSMutableArray *arrInfo = [[NSMutableArray alloc] init]; //arrInfo retain count = 1
appDelegate.arrAppInfo = arrInfo; //arrInfo retain count = 2
[arrInfo release]; //arrInfo retain count = 1
If you weren't releasing the arrInfo variable after assigning it to a retained property you would have caused a memory leak in the future when reassigning or releasing the arrAppInfo property, since its retain count wouldn't be 0.
It depends on how arrAppInfo is defined in appDelegate.
If its a strong reference, this would be good as long as appDelegate releases arrAppInfo at some point.
#property (nonatomic, retain) NSMutableArray *arrAppInfo; //All good
If its a weak reference, then you will get an error when you try to access arrAppInfo because its been released.
#property (nonatomic, assign) NSMutableArray *arrAppInfo; //Trouble
I am using the iPhone SDK and have an issue doing something simple. I am trying to add an NSNumber object to an NSMutableArray instance variable. I tried adding NSNumber card to NSMutableArray viewedCardsArray, however without breaking, it does not get added to the array. Here is the code.
/////////////////////////////////////////////////////
// Inside the header file Class.h
#interface MyViewController : UIViewController {
NSMutableArray *viewedCardsArray;
//snip ...
}
#property (nonatomic, retain) NSMutableArray *viewedCardsArray;
#end
/////////////////////////////////////////////////////
// Inside the methods file Class.m
#import "StudyViewController.h"
#implementation StudyViewController
#synthesize viewedCardsArray
//snip ...
- (IBAction)doShowCard {
//snip ...
NSNumber *cardIdObject = [[NSNumber alloc] initWithInt:(int)[self.currentCard cardId]];
[viewedCardsArray addObject: cardIdObject];
[cardIdObject release];
}
So this code executes, and does not seem to leak (according to the Leaks performance tool). However when stepping through the code, at no point does CardIdObject appear in viewedCardsArray.
Looking through SO, I know these basic questions are pretty common to ObjC newbies (like me) so apologies in advance!
Have you initialized your viewedCardsArray? If not you need to somewhere - this is usually done in the init method for your class:
- (id)init
{
self = [super init];
if(self) {
viewedCardsArray = [[NSMutableArray alloc] init];
}
return self;
}
Then it is released in the dealloc method:
- (void)dealloc
{
[viewedCardsArray release];
[super dealloc];
}
Perspx has outlined one way of initializing the array. However, you can also use the class methods provided by NSArray:
self. viewedCardsArray = [NSMutableArray array];
This can go in init or elsewhere.
Note: The object will be autoreleased.
In my iOS project i am creating an NSArray that can contains integer values. There are several functions in this class that do their task on that NSArray. So i thought to create NSArray as private attribute of that class. In viewDidLoad i am allocating memory to this array i.e
myArray = [[NSArray alloc] init];
myArray will be used in several method of this class. When i analyze my code it shows memory leak as i am allocating myArray and not releasing it.
If i write [myArray release] in dealloc or viewDidUnload warning still there. If i release myArray in last method of class that is using this array, xCode wont allow me to do.
Here is How i am declaring it in my class
.h file
#interface FightVC : UIViewController
{
NSArray *myArray;
}
I want to know what is possible solution of this. other then using autorelease . I don't want to make it public so i am not writing this array as property.
Thanks in advance
Using a private #property as mentioned in the other answer is probably the nicest and cleanest way to do this. Raw instance variables aren’t a very modern way of doing things. However, if you are going down that road, you can implement a getter for your ivar in which you release the old ivar and retain the new one:
- (void)setMyArray:(NSArray *)array {
[myArray release];
myArray = [array retain];
}
That’s the typical pattern anyway (which is what having an #property does for you automatically).
After that, you can create the array, use the setter, and then release the object:
NSArray *newArray = [[NSArray alloc] init];
[self setMyArray:newArray];
[newArray release];
That should keep the analyzer from squawking at you. A few things stick out to me though:
1) [[NSArray alloc] init] isn’t likely to do what you want it to do. It’s going to create an empty, immutable array. You probably either want an NSMutableArray, or you want to instantiate it with objects already in it using a different initializer.
2) NSArrays aren’t really suited for holding integers themselves, they hold objects. You can either use an NSPointerArray or you can put the integers into NSNumbers and put them into an NSArray.
To make a property private, you have to create an anonymous category.
In your .m file:
#interface myClass ()
#property (nonatomic, retain) NSArray *myPrivateArray;
#end
#implementation myClass
// Class code here
#end
To release your array, simply set the property to nil.
self.myPrivateArray = nil;
When I first read Beginning iOS 3 Development before ARC, I remember seeing patterns like this in some ViewController class:
.h
#property (nonatomic, retain) NSArray *myArray;
.m
in viewDidLoad:
NSArray *tempArray = [[NSArray alloc] init];
self.myArray = tempArray;
[tempArray release];
I remember reading that you did this so the properties could handle the memory for you if you used the property setters/getters. So now with ARC, I'm wondering if you still follow that kind of variable creation. For example, if you start a new project in iOS 6, in the AppDelegate, they do
.h
#property (strong, nonatomic) ViewController *viewController;
.m
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
The temp variable is not created in this case. I was wondering why and if I should be following that pattern instead of the first one. Thanks!
They are the same pattern except now ARC properly handles the release for you. The 2nd block of code is just fine with ARC. That's what makes ARC so nice.
Yes you should. ARC optimizes away the unnecessary retain and release automatically for you.
I'm using leaks tool of instruments. It says that I have some leaks in the init method. It shows that NSMutableArray has leak.
I don't see any leaks.
#interface BookSettings : NSObject
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSMutableArray *authors;
#end
- (id)init
{
self = [super init];
if(self)
{
title = [[NSString stringWithString:#""] retain];
authors = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc
{
[title release];
[authors release];
[super dealloc];
}
The provided code is OK, the problem is somewhere else where authors is retained without a balancing release. Leaks just points to the place ivar is created, not where the missing release should be. Check all the places where the retain count is increased.
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the problem code to run, stop recording, search for there ivar of interest, drill down and you will be able to see where all retains, releases and autoreleases occurred.
Seriously consider using ARC, there is little reason not to, ARC supports back to iOS 4.x.
BTW:
title = [[NSString stringWithString:#""] retain];
can be more compactly written:
title= #"";
I think it's from title.
You already have that property nonatomic, retain, so it this means a retain count of 1.
Then you specify another retain, making the retain count 2.
In the dealloc, you release it once, decreasing the retain count to 1. So this 1 reference that keeps retaining the string is the leak.
I don't understand why you are initialising the string like that anyway...