Objective-c addObject in loop causes memory leak - objective-c

I have found a similar issue:
NSMutableArray addObject in for loop - memory leak
But none of those suggestions seem to fix my problem.
I have a simple loop where I'm creating an object and adding it to an array. When I try to release the object at the end of each loop the app crashes with "EXC_BAD_ACCESS". If I don't release the object I get leaked memory:
In .h
NSMutableArray *mainlist;
...
#property (nonatomic, retain) NSMutableArray *mainList;
In .m
#synthesize mainlist;
...
for (int i = 0; i < [self.objects count]; i++) {
MyObj *myObj = [[MyObj alloc] init];
myObj.title = [[self.objects objectAtIndex: i] valueForKey: #"title"];
[self.mainlist addObject:myObj];
[myObj release]; // crashes with release
}
MyObj just has some properties:
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) NSString *date_text;
...
#synthesize title;
#synthesize date_text;
- (void)dealloc
{
[super dealloc];
[title release];
[date_text release];
}
#end
Any help would be much appreciated.
Thanks.

Crashes cause you first call dealloc of superclass and then try to release attributes. Change this to:
- (void)dealloc
{
[title release];
[date_text release];
[super dealloc];
}
And also: I'm almost certain that your self.mainlist is nil, when you're adding objects there. Creating a property doesn't mean that the attribute would be initialized automatically.

Related

ARC - alloc into a strong property. Creates leak?

In ARC, does it create a memory leak to alloc into a #property (strong)
// MyClass.h
#property (strong) NSString *myString;
// MyClass.m
#synthesize myString=_myString;
- (void)viewDidLoad
{
self.myString = [[NSString alloc] initWithFormat:#"Test %#", otherString];
}
I know that in manual memory management, the equivalent would create a leak
// MyClass.h
#property (retain) NSString *myString;
// MyClass.m
#synthesize myString=_myString;
- (void)viewDidLoad
{
self.myString = [[NSString alloc] initWithFormat:#"Test %#", otherString];
}
- (void)dealloc
{
[_myString release];
}
Is ARC able to handle the top example correctly? Does it optimize away one of the retains? Or maybe release twice in the dealloc?
This is perfectly valid under ARC.
I would recommend reading the ARC documentation to get more comfortable with trusting what it has to offer. http://clang.llvm.org/docs/AutomaticReferenceCounting.html and Mike Ash has a great blog post on how it works http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html

Mutable array contents are lost between methods

I have this code in my .m file, which is a Cocos 2D CCLayer class. I initialize an array in the init method and then I try to use contents of this array in the nextFrame method. But when the nextFrame method gets called, the contents of the array seem empty. When I try to get the first item, I receive an error message saying:
Program received signal "EXC_BAD_ACCESS"
How can I successfully access the contents of this array in my nextFrame method?
NSMutableArray *cars;
-(id) init {
cars = [NSMutableArray array];
Car *car;
car = [[Car alloc] init];
[cars addObject:car];
self.isTouchEnabled = YES;
}
- (void) nextFrame:(ccTime)dt {
Car *car = [cars objectAtIndex:i]; // Program received signal "EXC_BAD_ACCESS"
}
Car.h
#import <Foundation/Foundation.h>
#import "cocos2d.h";
#interface Car : NSObject {
NSInteger type;
CCSprite *sprite;
}
#property (readwrite, assign) NSInteger type;
#property (retain) CCSprite *sprite;
#end
Car.m
#import "Car.h"
#implementation Car
#synthesize type;
#synthesize sprite;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void) dealloc {
[sprite release];
[super dealloc];
}
#end
You're assigning the result of [NSMutableArray array] to an instance variable. That is an autoreleased object, which essentially means it doesn't have any owners and thus will feel free to go away after the current runloop iteration*. You need to retain it if you want it to stick around (or just use [[NSMutableArray alloc] init], which returns an object you own).
* Basically. You should see the Cocoa memory mangement guide for more details. It's pretty short but full of essential information.

Yet another EXC_BAD_ACCESS - However with zombie (instruments), never exe_bad_access

I have spent hours on this and read everybit on the web about memory management, zombies. leaks (tried instruments). But I cannot figure this one out. Does someone has a clue? I am getting a EXC_BAD_ACCESS at the following like of code on popping the ChildViewController.
[profileVO release]; profileVO = nil;
I strongly feel I have followed all memory management best practices!
Details:
I have a model file. (CachedProfileVO)
CachedProfileVO.h
#interface CachedProfileVO : NSObject {
NSString *name;
NSString *email;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic, retain) NSString *email;
#end
CachedProfileVO.m
#synthesize name, email;
- (void) dealloc
{
[super dealloc];
[name release]; name= nil;
[email release]; email = nil;
}
Now I have a UINavigationController. The ParentViewController and the ChildViewController.
I invoke the ChildViewController as follows:
[self.navigationCntroller pushViewcontroller:childViewcontroller animated:YES];
In the ChildViewController, I basically use the model CachedProfileVO. However when this view controller is popped (back button on UI), it gives a EXC_BAD_ACCESS
ChildViewController.h
#interface ChildViewcontroller : UITableViewController {
CachedProfileVO *profileVO;
}
#property (nonatomic, retain) CachedProfileVO *profileVO;
#end
ChildViewController.m
#synthesize profileVO;
- (void) dealloc
{
[super dealloc];
[profileVO release]; profileVO = nil; ****** GETTING EXE_BAD_ACCESS here
}
- (void) viewDidLoad
{
CachedProfileVO *vo = [CachedProfileVO alloc] init];
self.profileVO = vo;
[vo release];
}
//responseString looks like this: [Murdoch, murdoch#email.com][other data][more data]
- (void) populateProfile:(NSString *) responseString
{
NSMutableString *str = [[NSMutableString alloc] initWithCapacity:20];
[str setString:responseString];
[str deleteCharactersInRange: NSMakeRange(0,1)];
[str deleteCharactersInRange: NSMakeRange([str length]-1,1)];
NSArray *tempArray = [str componentsSeparatedByString: #"]["];
NSString *tempStr = (NSString*)[tempArray objectAtIndex:0];
NSArray *bioArray = [tempStr componentsSeparatedByString:#","];
self.profileVO.name = (NSString*)[bioArray objectAtIndex:0];
self.profileVO.email= (NSString*)[bioArray objectAtIndex:1];
[str release]; str = nil;
}
Note that the function populateProfile is called after some event. I know it is called. And dealloc then causes the problem. Also this does not happen in every pop. I have to try several times to reproduce. It is never reproduced using zombies in instruments!!!
You are calling [super dealloc]; first in your examples. That should always be the last call otherwise you are accessing instance variables that belong to a now deallocated class. The following should work fine if you followed memory management rules elsewhere.
- (void) dealloc
{
[profileVO release];
[super dealloc];
}

Having problems with adding objects to NSMutableArray

I am having problem with adding objects to NSMutableArray *array.
// Controller.m
#import "Controller.h"
#implementation Controller
- (void)parser:(NSString *)string{
[array addObject:string];
NSLog(#"answerArray(1): %#",[array objectAtIndex:1]);
[array retain];
}
#end
// Controller.h
#import <Foundation/Foundation.h>
#interface Controller : NSObject {
NSMutableArray *array;
}
- (void)parser:(NSString *)string;
#end
NSLog(#"answerArray(1): %#",[array objectAtIndex:1]);
Results: answerArray(1): (null)
First off, you're over-retaining the array.
Second, you didn't provide the code for initializing the array, so I guess it's not allocated and initialized. This will cause the code to message a nil object and thus return nil.
You should create an init method for the Controller object, and allocate a new NSMutableArray object (and retain it).
Also, a proper dealloc to release the array.
NSMutabaleArray starts at index 0
Here is the method I added to Controller class:
- (id)init {
self = [super init];
if(self){
array = [[NSMutableArray alloc] init];
}
return self;
}
- (void)dealloc {
[array release];
[super dealloc];
}

Share NSArray Contents between multiple methods in a single class

What am I doing wrong? My code crashes when I try to log the array. Here is my class:
#interface ArrayTestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
NSArray *array;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) NSArray *array;
-(IBAction)buttonPressed;
#end
#implementation ArrayTestAppDelegate
#synthesize window, array;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
array = [NSArray arrayWithObjects:#"Banana", #"Apple", #"Orange", #"Pear", #"Plum", nil];
[window makeKeyAndVisible];
}
-(IBAction)buttonPressed {
NSLog(#"%#", array);
}
- (void)dealloc {
[window release];
[array release];
[super dealloc];
}
#end
This is a common memory management error in Cocoa. The arrayWithObjects method of the NSArray class returns an autoreleased object. By the time you try to log the array in the buttonPressed method, the array has already been released and you get a crash. The fix is easy:
array = [[NSArray alloc] initWithObjects:#"Banana", #"Plum", nil];
Or:
array = [[NSArray arrayWithObjects:#"Banana", #"Plum", nil] retain];
I guess the first one is better, the retain on the end of the second example is easy to miss. I would suggest that you read some more on memory management in Cocoa.