OK, for two days now i have been trying to solve an error i have inside the cellForRowAtIndex method, let start by saying that i have tracked down the bug to this method, the error is [CFDictionary image] or [Not a Type image] message sent to deallocated instance.
I know about the debug flags, NSZombie, MallocStack, and others, they helped me narrow it down to this method and why, but I do not know how to solve besides a redesign of the app UI.
SO what am i trying to do, well for this block of code, displays a purchase detail, which contains items, the items are in there own section, now when in edit mode, there appears a cell at the bottom of the items section with a label of "Add new Item", and this button will present a modal view of the add item controller, item is added and the view returns to the purchase detail screen, with the just added item in the section just above the "add new Item" cell, the problem happens when i scroll the item section off screen and back into view the app crashes with EXC_BAD_ACCESS, or even if i don't scroll and instead hit the back button on the navBar, still the same error.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
switch (indexPath.section)
{
case PURCHASE_SECTION:
{
static NSString *cellID = @"GenericCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2
reuseIdentifier:cellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
switch (indexPath.row)
{
case CATEGORY_ROW:
cell.textLabel.text = @"Category:";
cell.detailTextLabel.text = [self.purchase.category valueForKey:@"name"];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case TYPE_ROW:
cell.textLabel.text = @"Type:";
cell.detailTextLabel.text = [self.purchase.type valueForKey:@"name"];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case VENDOR_ROW:
cell.textLabel.text = @"Payment:";
cell.detailTextLabel.text = [self.purchase.vendor valueForKey:@"name"];
cell.accessoryType = UITableViewCellAccessoryNone;
cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
break;
case NOTES_ROW:
cell.textLabel.text = @"Notes";
cell.editingAccessoryType = UITableViewCellAccessoryNone;
break;
default:
break;
}
break;
}
case ITEMS_SECTION:
{
NSUInteger itemsCount = [items count];
if (indexPath.row < itemsCount)
{
static NSString *itemsCellID = @"ItemsCell";
cell = [tableView dequeueReusableCellWithIdentifier:itemsCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:itemsCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
singleItem = [self.items objectAtIndex:indexPath.row];
cell.textLabel.text = singleItem.name;
cell.detailTextLabel.text = [singleItem.amount formattedDataDisplay];
cell.imageView.image = [singleItem.image image];
}
else
{
static NSString *AddItemCellID = @"AddItemCell";
cell = [tableView dequeueReusableCellWithIdentifier:AddItemCellID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:AddItemCellID] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
cell.textLabel.text = @"Add Item";
}
break;
}
case LOCATION_SECTION:
{
static NSString *localID = @"LocationCell";
cell = [tableView dequeueReusableCellWithIdentifier:localID];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:localID] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}
cell.textLabel.text = @"Purchase Location";
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.editingAccessoryType = UITableViewCellAccessoryNone;
break;
}
default:
break;
}
return cell;
}
the singleItem is of Modal Type PurchaseItem for core data
now that i know what is causing the error, how do i solve it, I have tried everything that i know and some of what i dont know but still, no progress, please any suggestions as to how to solve this without redesign is my goal, perhaps there is an error i am doing that I cannot see, but if it's the nature of autorelease, than i will redesign.
UPDATE: adding the AddItemController
//
// AddItemViewController.m
// spendTrac
//
// Created by iAm on 3/5/10.
// Copyright 2010 heariamStudios. All rights reserved.
//
#import "AddItemViewController.h"
#import "Purchase.h"
#import "PurchaseItem.h"
#import "FormattedDataDisplay.h"
#import "ModalAlert.h"
#import "UtilityBelt.h"
@implementation AddItemViewController
@synthesize purchase, item, itemAmount, itemImage;
@synthesize amountPadBtn, nameAlertBtn, addImageBtn;
@synthesize amountLab, itemNameLab;
@synthesize itemImageView;
#pragma mark -
#pragma mark IBAction Methods
- (void)cancel:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)save:(id)sender
{
NSManagedObjectContext *context = purchase.managedObjectContext;
if (!item)
{
itemImage = [NSEntityDescription insertNewObjectForEntityForName:@"Image" inManagedObjectContext:context];
item = [NSEntityDescription insertNewObjectForEntityForName:@"PurchaseItem" inManagedObjectContext:context];
[purchase addItemsObject:item];
item.displayOrder = [NSNumber numberWithInteger:[purchase.items count]];
}
NSString *stringAmt = [UtilityBelt charStripper:self.amountLab.text];
NSDecimalNumber *amount = [NSDecimalNumber decimalNumberWithString:stringAmt];
[itemImage setValue:self.itemImageView.image forKey:@"image"];
item.image = itemImage;
item.name = itemNameLab.text;
item.amount = amount;
NSError *error = nil;
if (![context save:&error])
{
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
[self.navigationController popViewControllerAnimated:YES];
}
- (void)amountPadButtonTapped:(id)sender
{
AmountPad *amountPad = [[AmountPad alloc]initWithNibName:@"AmountPad" bundle:nil];
amountPad.delegate = self;
[self.navigationController presentModalViewController:amountPad animated:YES];
[amountPad release];
}
- (void)nameAlertButtonTapped:(id)sender
{
NSString *answer = [ModalAlert ask:@"Name This Item" withTextPrompt:@"item name"];
if (answer)
{
self.itemNameLab.text = [NSString stringWithFormat:@"%@", answer];
}
else
{
[ModalAlert say:@"What, You Don't Know!"];
}
}
- (void)photoButtonTapped:(id)sender
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.allowsEditing = YES;
imagePicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:imagePicker.sourceType];
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
else {
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
}
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)selectedImage
editingInfo:(NSDictionary *)editingInfo
{
// Create a thumbnail version of the image for the item object.
CGSize size = selectedImage.size;
CGFloat ratio = 0;
if (size.width > size.height) {
ratio = 277.3 / size.width;
} else {
ratio = 277.3 / size.height;
}
CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
UIGraphicsBeginImageContext(rect.size);
[selectedImage drawInRect:rect];
self.itemImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self dismissModalViewControllerAnimated:YES];
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark View Controller Methods
- (void)viewDidLoad
{
if (self.item)
{
self.itemImage = self.item.image;
self.itemImageView.image = [self.item.image image];
self.itemNameLab.text = self.item.name;
self.amountLab.text = [self.item.amount formattedDataDisplay];
}
UINavigationItem *navigationItem = self.navigationItem;
navigationItem.title = @"Item";
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self
action:@selector(cancel:)];
self.navigationItem.leftBarButtonItem = cancelButton;
[cancelButton release];
UIBarButtonItem *saveButton = [[UIBarButtonItem alloc] initWithTitle:@"Save"
style:UIBarButtonSystemItemSave
target:self
action:@selector(save:)];
self.navigationItem.rightBarButtonItem = saveButton;
[saveButton release];
[super viewDidLoad];
}
- (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.
}
- (void)viewDidUnload
{
// Release any retained subviews of the main view.
self.amountLab = nil;
self.itemNameLab = nil;
self.addImageBtn = nil;
self.nameAlertBtn = nil;
self.amountPadBtn = nil;
[super viewDidUnload];
}
#pragma mark -
#pragma mark AmountPadDelegate Method
- (void)amountPadDidPressDoneButton:(NSString *)amount
{
NSDecimalNumber *itemAmt = [NSDecimalNumber decimalNumberWithString:amount];
self.amountLab.text = [itemAmt formattedDataDisplay];
[self dismissModalViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark Memory Management
- (void)dealloc
{
[addImageBtn release];
[nameAlertBtn release];
[amountPadBtn release];
[itemAmount release];
[purchase release];
[item release];
[itemImage release];
[itemImageView release];
[amountLab release];
[itemNameLab release];
[super dealloc];
}
@end