Memory leaks in NSMutableDictionary - iphone

My coding contains a memory leak, and somehow I can't find the leak.
Leaks points me in the direction of the way I create "ReportDetailItems"
e.g. areaContainer = [[[ReportDetailItem alloc] init] autorelease];
I've been looking at this for hours and I am at a total loss, the objects reported leaking are "ReportDetailItem", and the NSMutableDictionary contained in those objects.
Please advice.
------[ReportDetailItem.h
#interface ReportDetailItem : NSObject
{
NSNumber *total;
NSMutableDictionary *items;
}
#property (nonatomic, retain) NSNumber *total;
#property (nonatomic, retain) NSMutableDictionary *items;
- (NSString *)description;
#end
------[ReportDetailItem.m
#synthesize items, total;
- (id)init {
if (self = [super init]) {
self.items = [NSMutableDictionary dictionaryWithCapacity:0];
DLog("Alloc: %d", [items retainCount]);
}
return self;
}
- (NSString *)description {
return #"ReportDetailItem";
}
- (void)release {
[super release];
}
- (void)dealloc {
[self.items release];
[self.total release];
items = nil;
total = nil;
[super dealloc];
}
#end
------[Leaking code
NSError *error;
NSArray *data = [self.managedObjectContext executeFetchRequest:request error:&error];
if (data == nil || [data count] == 0) {
DLog(#"No data.")
} else {
for (int i=0; i < [data count]; i++) {
TaskEntity *task = [data objectAtIndex:i];
NSString *areaKey = task.activity.project.area.title.text;
NSString *projectKey = task.activity.project.title.text;
NSString *activityKey = task.activity.title.text;
ReportDetailItem *areaContainer;
if (![dataSource objectForKey:areaKey]) {
areaContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
areaContainer = [dataSource objectForKey:areaKey];
}
areaContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [areaContainer.total intValue])];
[dataSource setObject:areaContainer forKey:areaKey];
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
projectContainer = [areaContainer.items objectForKey:projectKey];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
ReportDetailItem *activityContainer;
if (![projectContainer.items objectForKey:activityKey]) {
activityContainer = [[[ReportDetailItem alloc] init] autorelease];
} else {
activityContainer = [projectContainer.items objectForKey:activityKey];
}
activityContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [activityContainer.total intValue])];
[projectContainer.items setObject:activityContainer forKey:activityKey];
}
}

I found it, the leak was located in the way I allocated the "dataSource"
---[Leak
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = [[NSMutableDictionary alloc] init];
[self fetchData];
}
---[No leak
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
self.dataSource = dict;
[dict release];
[self fetchData];
}

I'm pretty skeptic about the two ways u assign pointers to the ReportDetailItem. Why are you trying to autorelease the object in the first place? If not try this
ReportDetailItem *projectContainer;
if (![areaContainer.items objectForKey:projectKey]) {
projectContainer = [[ReportDetailItem alloc] init];
} else {
projectContainer = [[areaContainer.items objectForKey:projectKey] retain];
}
projectContainer.total = [NSNumber numberWithInt:([task.seconds intValue] + [projectContainer.total intValue])];
[areaContainer.items setObject:projectContainer forKey:projectKey];
if(projectContainer) {
[projectContainer release];
projectContainer = nil;
}

Related

AlAssetsLibrary issue, code works in 4.3 but not 5.0

Here's my issue, if I access this class with iOS 4.X, the code works fine.... however whenever I try to access it with iOS 5.0, I get nil values for the groups & assets. What's the best way to get this to work? I'm posting the entire class for a reference...
.h
#import <UIKit/UIKit.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import "DejViewController.h"
#class Event, Venue;
#interface SelectMediaViewController : DejViewController <UITableViewDelegate, UITableViewDataSource> {
Event *event;
Venue *venue;
UITableView *tableView;
NSMutableArray *selectedAssets;
NSMutableArray *allMedia;
ALAssetsLibrary *library;
NSMutableArray *assetGroups;
}
#property (nonatomic, retain) Event *event;
#property (nonatomic, retain) Venue *venue;
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSMutableArray *allMedia;
#property (nonatomic, retain) NSMutableArray *assetGroups;
- (IBAction)continuePressed:(id)sender;
#end
.m
#import <ImageIO/ImageIO.h>
#import "SelectMediaViewController.h"
#import "CaptionAllMediaViewController.h"
#import "MediaItem.h"
#import "CLValueButton.h"
#import "SelectMediaTableViewCell.h"
#define kMediaGridSize 75
#define kMediaGridPadding 4
#define kSelectImageTag 828
#interface SelectMediaViewController(Private)
- (void)setContentForButton:(CLValueButton *)button withAsset:(ALAsset *)asset;
- (void)loadData;
#end
#implementation SelectMediaViewController
#synthesize event, venue;
#synthesize tableView;
#synthesize allMedia,assetGroups;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
selectedAssets = [[NSMutableArray alloc] init];
showNextButton = YES;
}
return self;
}
- (void)dealloc {
[tableView release];
[event release];
[venue release];
[library release];
[allMedia release];
[selectedAssets release];
[assetGroups release];
[super dealloc];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"SelectMediaViewController - viewDidLoad");
}
- (void)viewDidUnload {
NSLog(#"SelectMediaViewController - viewDidUnload");
[self setTableView:nil];
[super viewDidUnload];
}
- (void)viewDidAppear:(BOOL)animated {
NSLog(#"SelectMediaViewController - viewDidAppear");
[super viewDidAppear:animated];
[self setNavTitle:#"Select Media"];
[self loadData];
[self.tableView reloadData];
float contentOffset = self.tableView.contentSize.height - self.tableView.frame.size.height;
if (contentOffset < 0) contentOffset = 0;
[self.tableView setContentOffset:CGPointMake(0, contentOffset) animated:NO];
}
- (void)viewDidDisappear:(BOOL)animated {
NSLog(#"SelectMediaViewController - viewDidDisappear");
self.allMedia = nil;
[selectedAssets removeAllObjects];
[self.tableView reloadData];
}
- (void)loadData {
NSMutableArray *tempArray = [[NSMutableArray array] init];
library = [[ALAssetsLibrary alloc] init];
void (^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) {
if(result != NULL) {
NSLog(#"See Asset: %#", result);
[tempArray addObject:result];
NSLog(#"assets count: %i", tempArray.count);
}
else {
NSLog(#"result nil or end of list");
}
};
void (^assetGroupEnumerator)(ALAssetsGroup *, BOOL *) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
[group enumerateAssetsUsingBlock:assetEnumerator];
NSLog(#"group: %#",group);
}
else {
NSLog(#"group nil or end of list");
}
if (stop) {
self.allMedia = [NSMutableArray arrayWithCapacity:[tempArray count]];
self.allMedia = tempArray;
NSLog(#"Loaded data: %d & %d", [tempArray count], [self.allMedia count]);
}
};
//ALAssetsLibrary *library = [[[ALAssetsLibrary alloc] init] autorelease];
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:assetGroupEnumerator
failureBlock:^(NSError *error) {
}];
//[library release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)continuePressed:(id)sender {
if ([selectedAssets count] > 0) {
CaptionAllMediaViewController *captionVC = [[CaptionAllMediaViewController alloc] initWithNibName:nil bundle:nil];
captionVC.event = self.event;
captionVC.venue = self.venue;
// Create media items
NSMutableArray *mediaItems = [NSMutableArray arrayWithCapacity:[selectedAssets count]];
for (ALAsset *asset in selectedAssets) {
MediaItem *item = [[MediaItem alloc] init];
item.asset = asset;
NSDictionary *metadata = [[asset defaultRepresentation] metadata];
NSDictionary *gpsMeta = [metadata objectForKey:#"{GPS}"];
if (gpsMeta) {
float latitude = [[gpsMeta objectForKey:#"Latitude"] floatValue];
if ([[gpsMeta objectForKey:#"LatitudeRef"] isEqualToString:#"S"]) latitude = latitude * -1;
float longitude = [[gpsMeta objectForKey:#"Longitude"] floatValue];
if ([[gpsMeta objectForKey:#"LongitudeRef"] isEqualToString:#"W"]) longitude = longitude * -1;
item.location = CLLocationCoordinate2DMake(latitude, longitude);
}
[mediaItems addObject:item];
[item release];
}
captionVC.media = mediaItems;
[self.navigationController pushViewController:captionVC animated:YES];
[captionVC release];
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No Images Selected"
message:#"Please select at least one image to continue."
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
- (void)imagePressed:(CLValueButton *)sender {
BOOL currentlySelected = [selectedAssets containsObject:sender.valueObject];
UIImageView *imageView = (UIImageView *)[sender viewWithTag:kSelectImageTag];
if (!currentlySelected) {
[imageView setImage:[UIImage imageNamed:#"image-select-active.png"]];
[selectedAssets addObject:sender.valueObject];
} else {
[imageView setImage:[UIImage imageNamed:#"image-select.png"]];
[selectedAssets removeObject:sender.valueObject];
}
}
#pragma Table view methods
- (int)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Getting table view count: %d", [self.allMedia count]);
if ([self.allMedia count] == 0) return 0;
return ceil([self.allMedia count] / 4.0);
}
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 83;
NSLog(#"return83");
}
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
SelectMediaTableViewCell *cell = (SelectMediaTableViewCell *)[_tableView dequeueReusableCellWithIdentifier:#"MEDIA_CELL"];
if (!cell) {
cell = [[[NSBundle mainBundle] loadNibNamed:#"SelectMediaTableViewCell" owner:nil options:nil] objectAtIndex:0];
// wire up selectors
[cell.image1 addTarget:self action:#selector(imagePressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.image2 addTarget:self action:#selector(imagePressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.image3 addTarget:self action:#selector(imagePressed:) forControlEvents:UIControlEventTouchUpInside];
[cell.image4 addTarget:self action:#selector(imagePressed:) forControlEvents:UIControlEventTouchUpInside];
}
int startIndex = indexPath.row * 4;
for (int i = 0; i < 4; i++) {
ALAsset *thisAsset = (startIndex + i) < [self.allMedia count] ? [self.allMedia objectAtIndex:startIndex + i] : nil;
CLValueButton *button = nil;
switch (i) {
case 0:
button = cell.image1;
break;
case 1:
button = cell.image2;
break;
case 2:
button = cell.image3;
break;
case 3:
button = cell.image4;
break;
default:
break;
}
[self setContentForButton:button withAsset:thisAsset];
UIImageView *imageView = (UIImageView *)[button viewWithTag:kSelectImageTag];
// letse see if it's selected or not...
if ([selectedAssets containsObject:button.valueObject]) {
[imageView setImage:[UIImage imageNamed:#"image-select-active.png"]];
} else {
[imageView setImage:[UIImage imageNamed:#"image-select.png"]];
}
}
return cell;
}
- (void)setContentForButton:(CLValueButton *)button withAsset:(ALAsset *)asset {
button.hidden = asset == nil;
if (asset) {
CGImageRef image = [asset thumbnail];
[button setImage:[UIImage imageWithCGImage:image] forState:UIControlStateNormal];
}
[button setValueObject:asset];
}
#pragma -
#end
Any help would be much appreciated, I've been trying to figure this out for 3 days...
The ALAssetsLibrary page in the online documentation now says "The lifetimes of objects you get back from a library instance are tied to the lifetime of the library instance."

plist segment control save issue

I have a issue with this peice of code, I am trying to save some data to a plist for later use, and if the user reopens the view, it should have the current segment selected for each segment control on my view.
however when I try and save the information, it crashes on the line
[array addObject:gender];
please help :) it gives EXC_BAD_ACCESS
-(IBAction)genderSelection:(id)sender
{
if([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
{
gender = #"Male";
//NSLog(gender);
}
else {
gender = #"Female";
//NSLog(gender);
}
}
-(IBAction)contactTypeSelection:(id)sender
{
if([sender selectedSegmentIndex] == kSwitchesSegmentIndex)
{
contactType = #"a";
//NSLog(gender);
}
else {
contactType = #"b";
//NSLog(gender);
}
}
-(IBAction)saveData:(id)sender
{
NSMutableArray *array = [[NSMutableArray alloc] init];
[array removeAllObjects];
[array addObject:field1.text];
[array addObject:field2.text];
[array addObject:gender];
[array addObject:contactType];
[array writeToFile:[self dataFilePath] atomically:YES];
[array release];
}
-(NSString *)dataFilePath
{
NSArray *path = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [path objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
-(void)viewWillAppear:(BOOL)animated
{
NSString *filePath = [self dataFilePath];
if([[NSFileManager defaultManager] fileExistsAtPath:filePath])
{
NSArray *array = [[NSArray alloc] initWithContentsOfFile:filePath];
field1.text = [array objectAtIndex:0];
field2.text = [array objectAtIndex:1];
gender = [array objectAtIndex:2];
contactType = [array objectAtIndex:3];
if([gender isEqualToString:#"Male"])
{
genderSegment.selectedSegmentIndex = 0;
}
else
{
genderSegment.selectedSegmentIndex = 1;
}
if([contactType isEqualToString:#"a"])
{
}
else
{
}
[array release];
}
}
-(IBAction)textDone:(id)sender
{
[sender resignFirstResponder];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)dealloc
{
[gender release]; //need to release
[contactType release]; //need to release
[field1 release]; //need to release
[field2 release]; //need to release
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
gender = #"Male";
contactType = #"a";
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
gender = nil; //need to release
contactType = nil; //need to release
field1 = nil ; //need to release
field2 = nil; //need to release
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
You didn't didn't initialize your gender property. You need:
- (void)viewDidLoad
{
    [super viewDidLoad];
self.gender=[[NSString alloc]init];
    self.gender = #"Male";
//so something here
    // Do any additional setup after loading the view from its nib.
}
NOTE: If you use the #synthesize compiler directive then you need to the self-dot notation everywhere to refer to the property e.g. self.gender.

Strange crash (EXC_BAD_ACCESS) scrolling UITableView reentering app after background

I'm using an UITableView with standard cell with subtitle and UIImageView. The scrolling is ok till I exit from the app. Then it goes background (I make nothing on delegate backgroun methods) and when I rerun the app, on the same view with the uitable, the scroll it's ok for some rows then the app crash in the method:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
the code of the method is:
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
ALog(#"TRACE");
}
// Configure the cell...
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSDictionary *cellContent = (NSDictionary *)[self.items objectAtIndex:indexPath.row];
Restaurant * r = (Restaurant *)[cellContent valueForKey:#"ristorante"];
cell.textLabel.textColor = [UIColor colorWithRed:245.0 green:245.0 blue:245.0 alpha:0.8];
cell.textLabel.text = r.nome;
cell.detailTextLabel.textColor = [UIColor lightTextColor];
cell.detailTextLabel.text = [r.indirizzo convertToString];
UIImage *img = r.tipo.image; //[UIImage imageNamed:#"loghetto_pne.png"];
cell.imageView.image = img;
//cell.imageView.clipsToBounds = YES;
//cell.imageView.contentMode = UIViewContentModeScaleAspectFit;
float sw= 48/img.size.width;
float sh= 48/img.size.height;
cell.imageView.transform = CGAffineTransformMakeScale(sw,sh);
//[img release];
return cell;
The crash is in the line:
cell.imageView.image = img;
From the stack trace I see that the execution goes on some internal framework code and then crash. The exception is not always the same (often is CATransaction count --> object di not respond to selector etc)
The code for Restaurant and Tipologia:
#import <Foundation/Foundation.h>
#class Zona;
#class Indirizzo;
#class Tipologia;
#interface Restaurant : NSObject {
#private
NSUInteger idx;
NSString *nome;
NSString *telefono;
Indirizzo *indirizzo;
Zona *zona;
Tipologia *tipo;
}
-(id)initWithIdx:(NSUInteger)index name:(NSString *)ristoName tel:(NSString *)ristoTel address:(Indirizzo *)ristoAdd zone:(Zona *)ristoZone;
#property (nonatomic) NSUInteger idx;
#property (nonatomic,retain) NSString *nome;
#property (nonatomic,retain) NSString *telefono;
#property (nonatomic,retain) Indirizzo *indirizzo;
#property (nonatomic,retain) Zona *zona;
#property (nonatomic,retain) Tipologia *tipo;
#end
Restaurant implementation:
#import "Restaurant.h"
#import "Zona.h"
#import "Indirizzo.h"
#import "Macro.h"
#implementation Restaurant
#synthesize idx, nome, indirizzo, telefono, zona, tipo;
-(id)initWithIdx:(NSUInteger)index name:(NSString *)ristoName tel:(NSString *)ristoTel address:(Indirizzo *)ristoAdd zone:(Zona *)ristoZone {
[self init];
bool error = NO;
if (self) {
idx = index;
nome = [ristoName retain];
telefono = [ristoTel retain];
indirizzo = [ristoAdd retain];
zona = [ristoZone retain];
}
return (error) ? nil : self;
}
- (id)init {
self = [super init];
if (self) {
idx = 0;
nome = #"";
telefono = #"";
indirizzo = nil;
zona = nil;
tipo = nil;
}
return self;
}
- (void)dealloc {
[nome release];
[indirizzo release];
[telefono release];
[zona release];
ALog(#"TRACE");
[tipo release];
ALog(#"TRACE");
[super dealloc];
}
#end
Tipologia interface and implementation:
#import <Foundation/Foundation.h>
typedef enum {
kTipoRestUnknown = 0,
kTipoRestRestaurant,
kTipoRestBrunch,
kTipoRestPizza,
kTipoRestRegional,
kTipoRestEthnic
} TipoRest;
#class ImageTest;
#interface Tipologia : NSObject {
#private
NSInteger idx;
NSString *desc;
UIImage *image;
TipoRest type;
}
-(id)initWithIndex:(NSInteger) index description:(NSString *)descr ofType:(TipoRest) type;
#property (nonatomic) NSInteger idx;
#property (nonatomic) TipoRest type;
#property (nonatomic,retain) NSString *desc;
#property (nonatomic,retain) UIImage *image;
#end
#import "Tipologia.h"
#import "Macro.h"
#implementation Tipologia
#synthesize desc, idx, image, type;
#pragma mark -
#pragma mark Memory Management
-(id)initWithIndex:(NSInteger) index description:(NSString *)descr ofType:(TipoRest) type {
self = [super init];
if (self != nil) {
self.idx = index;
self.desc = descr;
self.image = [UIImage imageNamed:#"immagineNA.png"];;
self.type = type;
}
return self;
}
-(void)dealloc {
[desc release];
desc = nil;
ALog(#"TRACE");
[image release];
image = nil;
ALog(#"TRACE");
[super dealloc];
}
-(void)release {
ALog(#"tipo.idx: %i, tipo.count: %i, tipo.imag: %#, tipo.img.count: %i", idx, [self retainCount], image, [image retainCount]);
[super release];
}
EDIT 2 Some other code. The snippet where I initialize the images based on the type
if (sqlite3_prepare_v2(db, queryStrTipo, -1, &query, NULL) == SQLITE_OK) {
restImage = [UIImage imageNamed:#"rest.png"];
pizzaImage = [UIImage imageNamed:#"pizza.png"];
etnImage = [UIImage imageNamed:#"etnico.png"];
brunchImage = [UIImage imageNamed:#"wineglass-blue.png"];
while(sqlite3_step(query) == SQLITE_ROW) {
NSString *desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(query, 1)];
tipo = [[Tipologia alloc] initWithIndex:sqlite3_column_int(query, 0)
description:desc ofType:kTipoRestUnknown];
ALog(#"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
if ([desc compare:kTipoDescRestaurant options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestRestaurant;
tipo.image = restImage;
} else
if ([desc compare:kTipoDescPizza options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestPizza;
tipo.image = pizzaImage;
} else
if ([desc compare:kTipoDescEtnico options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestEthnic;
tipo.image = etnImage;
} else
if ([desc compare:kTipoDescBrunch options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestBrunch;
tipo.image = brunchImage;
} else
if ([desc compare:kTipoDescRegionale options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestRegional;
}
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:tipo.idx], #"index", tipo.desc, #"desc", nil];
[listaTipologie addObject:tipo];
[listaTemp addObject:dictionary];
ALog(#"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
[tipo release];
[dictionary release];
}
[restImage release];
[pizzaImage release];
[etnImage release];
[brunchImage release];
}
You are missing a retain on either r.tipo, or r.tipo.image.
if they are both synthesized properties, check that the property declaration contains a retain.
If you implemented you own getters and/or setters, check that you are retaining and releasing everything properly.
Edit:
I just saw the new code you posted. Your problem is you are releasing UIImages that your code does not own. Excluding all the conditional logic you basically do this:
//Incorrect
UIImage *myImagename = [UIImage imageNamed:#"foo.png"]
yourclass.image = restImage;
[myImagename release];
This is incorrect because you never called alloc, copy or retain on the myImage object. [UIImage imageMamed] returns an autoreleased instance of a UIImage. It is the same as doing this (also incorrect):
//Incorrect
UIImage *myImagename = [[UIImage alloc] initWithImage:#"foo.png"] autorelease];
yourclass.image = restImage;
[myImagename release];
You have two options. Either manage the release yourself:
UIImage *myImagename = [UIImage alloc] initWithImage:#"foo.png"];
yourclass.image = restImage;
[myImagename release];
Or let the autoreleased object do its thing:
UIImage *myImagename = [UIImage imageNamed:#"foo.png"]
yourclass.image = restImage;
//Note: no release needed on yourClass.
In your specific code, you can take the second approach and it will look like this:
if (sqlite3_prepare_v2(db, queryStrTipo, -1, &query, NULL) == SQLITE_OK) {
restImage = [UIImage imageNamed:#"rest.png"];
pizzaImage = [UIImage imageNamed:#"pizza.png"];
etnImage = [UIImage imageNamed:#"etnico.png"];
brunchImage = [UIImage imageNamed:#"wineglass-blue.png"];
while(sqlite3_step(query) == SQLITE_ROW) {
NSString *desc = [NSString stringWithUTF8String:(char *)sqlite3_column_text(query, 1)];
tipo = [[Tipologia alloc] initWithIndex:sqlite3_column_int(query, 0)
description:desc ofType:kTipoRestUnknown];
ALog(#"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
if ([desc compare:kTipoDescRestaurant options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestRestaurant;
tipo.image = restImage;
} else
if ([desc compare:kTipoDescPizza options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestPizza;
tipo.image = pizzaImage;
} else
if ([desc compare:kTipoDescEtnico options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestEthnic;
tipo.image = etnImage;
} else
if ([desc compare:kTipoDescBrunch options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestBrunch;
tipo.image = brunchImage;
} else
if ([desc compare:kTipoDescRegionale options:NSCaseInsensitiveSearch] == NSOrderedSame) {
tipo.type = kTipoRestRegional;
}
dictionary = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:tipo.idx], #"index", tipo.desc, #"desc", nil];
[listaTipologie addObject:tipo];
[listaTemp addObject:dictionary];
ALog(#"tipo.idx: %i, retain count: %i",tipo.idx, [tipo retainCount]);
[tipo release];
[dictionary release];
}
}
Remember, the golden rule of iOS memory management:
If you use any method with the word copy, alloc, or new, you need to have a corresponding release.
And, of course, Apple's Memory Management Programming Guide is the definitive resourse
I resolved the issue.
UIImage imageNamed return an autorelease object (I didn't know about it) and I use it to alloc the 4 image variables that then will be assigned to the property (via . sintax) and I release them after assigning.
Build & Analyze told me that the release statement could be wrong cause I didn't own the object anymore. Commented it out and the crash goes out...
The fault lines was the last in "EDIT 2" snippet of my question.
Thanks to all.

why is the NSMutableArray is being destroyed in this loop?

It is the arrayOfPerformances that is getting broken.
here is the .h for the array:
NSMutableArray * arrayOfPerformances;
}
#property (nonatomic, retain) NSMutableArray * arrayOfPerformances;
and the .m that has the loop:
[dataArray release];
[dataDictionary release];
dataArray = [[NSMutableArray alloc] init];
dataDictionary = [[NSMutableDictionary alloc] init];
NSDate * CurrentDate = start;
int i = 0;
NSMutableArray * arrayOfPerformancesForCurrentDate = [[NSMutableArray alloc] init];
while(YES)
{
i = 0;
if ([arrayOfPerformancesForCurrentDate count] > 0)
{
[arrayOfPerformancesForCurrentDate removeAllObjects];
}
for (i; i < self.arrayOfPerformances.count; i++)
{
Performance * performanceItem = [[Performance alloc] init];
performanceItem = [self.arrayOfPerformances objectAtIndex:i];
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
[performanceItem release];
}
if ([arrayOfPerformancesForCurrentDate count] >= 1)
{
[dataDictionary setObject:arrayOfPerformancesForCurrentDate forKey:CurrentDate];
[dataArray addObject:[NSNumber numberWithBool:YES]];
}
else
{
[dataArray addObject:[NSNumber numberWithBool:NO]];
}
TKDateInformation info = [CurrentDate dateInformation];
info.day++;
CurrentDate = [NSDate dateFromDateInformation:info];
if([CurrentDate compare:end]==NSOrderedDescending) break;
}
Any help would be appreciated. I dont understand why this is happening?
This part doesn't look right:
Performance * performanceItem = [[Performance alloc] init]; <--
performanceItem = [self.arrayOfPerformances objectAtIndex:i]; <--
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
[performanceItem release]; <--
You alloc+init performanceItem but then set it to an object in arrayOfPerformances and then you release it (while it's pointing to the object in arrayOfPerformances).
Change that section to this:
Performance *performanceItem = [self.arrayOfPerformances objectAtIndex:i];
NSString * sPerformanceDate = [performanceItem.sDate substringToIndex:10];
NSString * sCurrentDate = [CurrentDate dateDescription];
if([sPerformanceDate isEqualToString:sCurrentDate])
{
[arrayOfPerformancesForCurrentDate addObject:performanceItem];
}
//don't release performanceItem
I don't think arrayOfPerformances of being destroyed. It appears you aren't even initializing it anywhere.

Code refactoring of 2 duplicate methods

Basically I have 2 methods that are similar in functionality. The only difference is the class container that are different. What I am trying to achieve is to unify these 2 methods and somehow have the container be dynamic.
here are the 2 methods:
-(NSMutableArray*) parseRequest:(NSArray*)elements {
NSMutableArray *currentStruct = [NSMutableArray array];
for (id element elemets) {
// This is where the difference is
FriendRequest *friend = [[FriendRequest alloc] init];
if(nickname != nil) {
friend.nickname = [element objectAtIndex:0];
}
[currentStruct addObject:friend];
[friend release];
}
return currentStruct;
}
Second:
-(NSMutableArray*) parseRequest:(NSArray*)elements {
NSMutableArray *currentStruct = [NSMutableArray array];
for (id element elemets) {
// This is where the difference is
Friend *friend = [[Friend alloc] init];
if(nickname != nil) {
friend.nickname = [element objectAtIndex:0];
}
[currentStruct addObject:friend];
[friend release];
}
return currentStruct;
}
Make that class a parameter.
-(NSMutableArray*) parseRequest:(NSArray*)elements withClass:(Class)friendClass {
NSMutableArray *currentStruct = [NSMutableArray array];
for (id element elemets) {
// This is where the difference is
id friend = [[friendClass alloc] init]; // <---
if(nickname != nil) {
[friend setNickname:[element objectAtIndex:0]];
}
[currentStruct addObject:friend];
[friend release];
}
return currentStruct;
}
...
-(NSMutableArray*) parseRequest:(NSArray*)elements {
return [self parseRequest:elements withClass:[Friend class]];
}
Or you can use the factory pattern:
-(NSMutableArray*) parseRequest:(NSArray*)elements factory:(SEL)factory {
NSMutableArray *currentStruct = [NSMutableArray array];
for (id element elemets) {
NSObject *friend = [self performSelector:factory];
if(nickname != nil) {
[friend performSelector:#selector(setNickname) withObject:[element objectAtIndex:0]];
}
[currentStruct addObject:friend];
}
return currentStruct;
}
-(Friend*) friendFactory {
return [[[Friend alloc] init] autorelease];
}