NSMutableArray addObject in for loop - memory leak - objective-c

i'm putting strings (which are filenames of files in a certain directory) into an NSMutableArray with a for loop:
h-file:
#import <Three20/Three20.h>
#interface AlbumController : TTThumbsViewController {
NSMutableArray *images;
}
#property (nonatomic, retain) NSMutableArray *images;
#end
m-file:
#import "AlbumController.h"
#import "PhotoSource.h"
#import "Photo.h"
#implementation AlbumController
#synthesize images;
-(void)createPhotos {
NSString *bundleRoot = [[NSBundle mainBundle] bundlePath];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundleRoot error:nil];
NSArray *onlyJPGs = [dirContents filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self ENDSWITH '.jpg'"]];
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
for(int i = 0; i < [onlyJPGs count]; i++)
{
//NSLog([pics objectAtIndex:i]);
NSString *ImgURL = [#"bundle://" stringByAppendingString:[pics objectAtIndex:i]];
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
}
}
-(void)viewDidLoad{
[self createPhotos]; // method to set up the photos array
self.photoSource = [[PhotoSource alloc]
initWithType:PhotoSourceNormal
title:#"Chili Pflanzen"
photos:images
photos2:nil
];
}
#end
i do not have any problem in the simulator but on my iPod...
Error message:
Data FOrmatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
thanks in advance

I think you should use mutableCopy and not copy on your pics array.
so instead of:
NSMutableArray *pics = [[onlyJPGs copy] autorelease];
you should use:
NSMutableArray *pics = [[onlyJPGs mutableCopy] autorelease];
More information about copy/mutablecopy in this question: Copy & mutableCopy?

Looks like the main issue is with
[images addObject:[[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)]];
Here you are alloc'ing Photo but not releasing it. When you add an object to an array it increases the retain count for it.
Try changing it to
Photo *photo = [[Photo alloc] initWithURL:ImgURL smallURL:ImgURL size:CGSizeMake(320, 212)];
[images addObject:photo];
[photo release];
In addition ...
I'd change
self.images = [[[NSMutableArray alloc] init] autorelease];
to
if(!self.images) {
self.images = [[NSMutableArray alloc] init];
}
Otherwise there is the potential for a memory leak if it has already been initialized, as well as that you probably do not want it autoreleased;

Your NSMutableArray instance is autoreleased. You are assigning it to the images ivar. The fact that you have declared it as a retained property doesn't matter, because you aren't assigning it to the property. My guess is that you meant to assign to the property, and the crash is caused by the inadvertent deallocation.
Change:
images = [[[NSMutableArray alloc] init] autorelease];
...to:
self.images = [[[NSMutableArray alloc] init] autorelease];
...or:
images = [[NSMutableArray alloc] init];
Also note that your property is declared as NSArray when you are allocating an instance of NSMutableArray.
Also see the Memory Management Programming Guide.

Related

EXC_BAD_ACCESS when I work with arrays

I always have error when working with arrays (non ARC code).
My code:
#implementation InfoController
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
in ViewDidLoad I do something
- (void)viewDidLoad
{
[super viewDidLoad];
lbCityArray = [[NSMutableArray alloc] initWithCapacity:1];
lbTimeArray = [[NSMutableArray alloc] initWithCapacity:1];
lbCameInArray = [[NSMutableArray alloc] initWithCapacity:1];
lbCameOutArray = [[NSMutableArray alloc] initWithCapacity:1];
lbInArray = [[NSMutableArray alloc] initWithCapacity:1];
lbOutArray = [[NSMutableArray alloc] initWithCapacity:1];
//—add some values to arrays
NSString *City = #"London";
[lbCityArray addObject:City];
//—————————————-----------------------//
}
and always when I click Back button app crash with EXC_BAD_ACCESS. If I comment adding values to array all work, Back button don't crash app. I read if you use non ARC code you must manually release in dealloc.
I add to dealloc
[_InfoTableView release];
[lbCityArray release];
[lbTimeArray release];
[lbCameInArray release];
[lbCameOutArray release];
[lbInArray release];
[lbOutArray release];
[super dealloc];
and nothing changes, app still crash. Where can be problem ?
Solution - I move to ARC and all problems gone. Thanks.
It would help a lot if you made your variables into instance variables instead of global variables.
Change this:
#implementation InfoController
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
into:
#implementation InfoController {
NSMutableArray *lbCityArray;
NSMutableArray *lbTimeArray;
NSMutableArray *lbCameInArray;
NSMutableArray *lbCameOutArray;
NSMutableArray *lbInArray;
NSMutableArray *lbOutArray;
}
Without the curly braces you are actually creating global variables, not instance variables.

issue adding NSMutablearray to other NSMutablearray? [duplicate]

This question already has answers here:
Cannot add items to an NSMutableArray ivar
(4 answers)
Closed 8 years ago.
I'm trying to add NSMutableArray to other NSMutableArray, a mutable array set as instance ivar, but I allways got the array arrayPlayoff empty. Other thing that I have detected, is that when debugging in the attached method, local variables are not shown in the debugger variables section, even selecting "local" option.
-(void)loadGamesPlayoffs{
NSMutableArray *eli1 = [[NSMutableArray alloc] init];
NSMutableArray *eli2 =[[NSMutableArray alloc] init];
NSMutableArray *eli3 = [[NSMutableArray alloc] init];
NSMutableArray *eli4 = [[NSMutableArray alloc] init];
for (NSDictionary *eliminatoria in copaReyArray){
int eli = [[eliminatoria valueForKey:#"eliminatoria"]integerValue];
NSLog(#"eli %d", eli);
if (eli==1){
[eli1 addObject:eliminatoria];
} else if (eli==2){
[eli2 addObject:eliminatoria];
}else if (eli==3){
[eli3 addObject:eliminatoria];
} else if (eli==4){
[eli4 addObject:eliminatoria];
}
}
[arrayPlayOff addObject:eli1];
[arrayPlayOff addObject:eli2];
[arrayPlayOff addObject:eli3];
[arrayPlayOff addObject:eli4];
}
many thanks
If arrayPlayOff is an Instance Variable you could use properties, your .h should look something like this:
#import <UIKit/UIKit.h>
#interface YourClassViewController : UIViewController{
NSMutableArray *arrayPlayOff;
//Some other variables
}
#property (nonatomic, retain) NSMutableArray *arrayPlayOff;
//Some other methods
#end
Then in your .m file you could use:
#implementation YourClassViewController
#synthesize arrayPlayOff;
- (NSMutableArray *)arrayPlayOff{
if(!arrayPlayOff){
arrayPlayOff = [[NSMutableArray alloc] init];
}
return arrayPlayOff;
}
//Your other methods
//Overwrite the dealloc function so you don't have any memory leaks
- (void)dealloc{
[arrayPlayOff release];
[super dealloc];
}
#end
Now you could access your variable as
self.arrayPlayOff
and this way you can be 100% sure that your variable is always initialized.
Your method could look like this (Also you should release your other NSMutableArrays since you are not using after adding them to the arrayPlayOff array):
-(void)loadGamesPlayoffs{
NSMutableArray *eli1 = [[NSMutableArray alloc] init];
NSMutableArray *eli2 =[[NSMutableArray alloc] init];
NSMutableArray *eli3 = [[NSMutableArray alloc] init];
NSMutableArray *eli4 = [[NSMutableArray alloc] init];
for (NSDictionary *eliminatoria in copaReyArray){
int eli = [[eliminatoria valueForKey:#"eliminatoria"]integerValue];
NSLog(#"eli %d", eli);
if (eli==1){
[eli1 addObject:eliminatoria];
} else if (eli==2){
[eli2 addObject:eliminatoria];
}else if (eli==3){
[eli3 addObject:eliminatoria];
} else if (eli==4){
[eli4 addObject:eliminatoria];
}
}
[self.arrayPlayOff addObject:eli1];
[self.arrayPlayOff addObject:eli2];
[self.arrayPlayOff addObject:eli3];
[self.arrayPlayOff addObject:eli4];
//Releasing the NSMutableArrays
[eli1 release];
[eli2 release];
[eli3 release];
[eli4 release];
}

Can't access NSDictionary values

I have an NSDictionary called equiposDic, which I need to retrieve using a value from another NSDictionary (value dip from ) but I can't' access it:
equiposDic = [[NSDictionary alloc] initWithObjectsAndKeys:#"FC Barcelona Regal", #"49", #"Real Madrid", #"50", #"Caja Laboral", #"51", #"Banca Cívica", #"52", #"Gescrap Bizkaia",#"53", #"Valencia Basket", #"13",#"Lucentum Alicante",#"54",#"Lagun Aro GBC",#"4",#"CAI Zaragoza", #"55", #"Assignia Manresa",#"2", #"FIATC Mutua Joventut",#"8",#"Unicaja",#"56",#"Gran Canaria",#"57",#"Mad-Croc Fuenlabrada",#"9",#"Blusens Monbus",#"59",#"UCAM Murcia",#"58", #"Asefa Estudiantes",#"60", #"Blancos de Rueda Valladolid", #"11", nil];
NSDictionary *posicion = [[NSDictionary alloc] initWithDictionary: [ligaArray objectAtIndex:indexPath.row]];
NSString *equipo = [posicion valueForKey:#"idp"];
NSString *idp = [posicion valueForKey:#"idp"];
NSLog(#"equipo %#", [equiposDic objectForKey:#"49"]);
Many thanks
If posicion is a NSDictionary, you have to use objectForKey in order to get the string.
NSString *idp = [posicion objectForKey:#"idp"];
Is ligaArray available in the context ?
I explain, your ligaArray var maynot be available when you expect it. You have to store ligaArray in your class with a retain
.h :
#interface MyClass {
NSMutableArray *ligaArray;
}
.m :
-viewDidLoad{
[super viewDidLoad];
ligaArray = [[NSMutableArray array] retain];
// OR
ligaArray = [[NSMutableArray alloc] init];
}
-dealloc{
[ligaArray release];
}
If this is not the case, try it. If it's already the case, check the retain/release calls.
This way, you will not loose reference to ligaArray values in your tableview methods.

Get & Edit NSMutableArray from different class file

I am trying to access and change a array from a different class file. When using a NSLog, I get a result of (null). Below is my code:
RootViewController.h
NSMutableArray *listOfItems;
#property (nonatomic, retain) NSMutableArray *listOfItems;
RootViewController.m
#synthesize listOfItems;
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
[listOfItems addObject:#"Two"];
[listOfItems addObject:#"Three"];
SecondViewController.m
RootViewController *test = [[RootViewController alloc] init];
NSLog(#"Results: %#", test.listOfItems);
I get the following results in my console: Results: (null)
Thanks in advance,
Coulton
P.S. Obviously I have left out a bunch of code. I just tried to make it easier to read. If you need to see anything else, I would be more than happy to post more. Just ask
EDIT #1:
I am getting hundreds of NSLog Messages that look something like this:
*** __NSAutoreleaseNoPool(): Object 0x4e39020 of class __NSArrayI autoreleased with no pool in place - just leaking
And here's my init code:
- (id) init {
//NSLog(#"%#", theUserID);
// Set up database connection
NSString *myDB = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"database.db"];
database = [[Sqlite alloc] init];
[database open:myDB];
//Initialize the array.
listOfItems = [[NSMutableArray alloc] init];
// Add to array to display in the tableView
NSArray *listOfItemsTwo = [database executeQuery:#"SELECT * FROM albums"];
for (NSDictionary *rowone in listOfItemsTwo) {
NSString *getName = [rowone valueForKey:#"name"];
if (getName != NULL) {
[listOfItems addObject:getName];
[getName release];
}
}
return self;
}
I guess you reversed RootViewController.m and RootViewController.h snippets right?
Are you sure that the
listOfItems = [[NSMutableArray alloc] init];
gets called? Maybe you can put a breakpoint there.
EDIT: Order of RootViewController.m and RootViewController.h has been fixed in the question. It's not clear from the question where the above line is in the code. That's a important piece of information.
EDIT2: Example of init method.
#implementation RootViewController
- (id) init
{
listOfItems = [[NSMutableArray alloc] init];
[listOfItems addObject:#"One"];
return self;
}
#end

Objective C - UITableView after calling reloadData my object properties are null/nil

I have a ViewController defined as follows:
#interface SectionController : UITableViewController {
NSMutableArray *sections;
}
- (void) LoadSections;
When LoadSection is call it makes a call to NSURLConnection to load a url which in turn calls
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[connection release];
[responseData release];
NSDictionary *results = [responseString JSONValue];
NSMutableArray *jSections = [results objectForKey:#"Items"];
sections = [NSMutableArray array];
for (NSArray* jSection in jSections)
{
Section* section = [Section alloc];
section.Id = [jSection objectForKey:#"Id"];
section.Description = [jSection objectForKey:#"Description"];
section.Image = [jSection objectForKey:#"Image"];
section.Parent = [jSection objectForKey:#"Parent"];
section.ProductCount = [jSection objectForKey:#"ProductCount"];
[sections addObject:section];
[section release];
}
[jSections release];
[results release];
[delegate sectionsLoaded];
[self.view reloadData];
}
The data parses correctly and I now have sections filled with many items.
Calling [self.view reloadData] forces a callback to the delegate method cellForRowAtIndexPath which should then present the data into the cell however its at this point that sections is now nil again.
Can someone please point out my mistake? I must admit I am a newbie to objective c and it probably a pointer issue. What is need to do is retain the value of sections after calling reloadData.
Many thanks.
Seeing the new code the problem is obvious:
sections = [NSMutableArray array];
should become
[sections release];
sections = [[NSMutableArray alloc] init];
note that the array does not become again "nil", is instead deallocated and you get an invalid reference, which might (should) generate a crash on dereferencing.
I suggest you to read some articles on reference counted memory management as it might be not obvious if you are new to Objective-C, and often leads to mistake (i.e: autorelease is not magic at all)
best way to avoid all memory leaks here is just simply use #property (nonatomic, retain) NSMutableArray *sections; by using property you can be sure that all men management works will be correctly managed by system. Just don't forget that property retains value when you doing setSections:, so that you need to pass autoreleased object here.
self.sections = [NSMutableArray array];
...
[self.sections addObject:section];
Also to avoid all problem try to make all objects which should live only in this method autorelease. Like this:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
NSDictionary *results = [responseString JSONValue];
NSMutableArray *jSections = [results objectForKey:#"Items"];
self.sections = [NSMutableArray array];
for (NSArray* jSection in jSections) {
Section* section = [[[Section alloc] init] autorelease];
section.Id = [jSection objectForKey:#"Id"];
section.Description = [jSection objectForKey:#"Description"];
section.Image = [jSection objectForKey:#"Image"];
section.Parent = [jSection objectForKey:#"Parent"];
section.ProductCount = [jSection objectForKey:#"ProductCount"];
[self.sections addObject:section];
}
[delegate sectionsLoaded];
[self.view reloadData];
}
And also most of object you trying to release already autoreleased:
all params passed into your method shouldn't be released manually, check I think JSONValue also should returns autoreleased object and anything you getting by enumerating or by call objectForKey: