Ошибка автовыделения TableViewCell
Хорошо, вот уже два дня я пытаюсь устранить ошибку, которая у меня есть внутри метода cellForRowAtIndex, начнем с того, что я обнаружил ошибку в этом методе, ошибка [CFDictionary image] или [Not a Type image] сообщение отправлено на освобожденный экземпляр.
Я знаю о флагах отладки, NSZombie, MallocStack и других, они помогли мне сузить его до этого метода и почему, но я не знаю, как решить, кроме редизайна пользовательского интерфейса приложения.
Итак, что я пытаюсь сделать, хорошо для этого блока кода, отображает детали покупки, которая содержит элементы, элементы находятся в собственном разделе, теперь, когда в режиме редактирования, в нижней части раздела элементов появляется ячейка с метка "Добавить новый элемент", и эта кнопка представит модальное представление контроллера добавления элементов, элемент будет добавлен, и представление вернется к экрану сведений о покупке, с только что добавленным элементом в разделе чуть выше "Добавить новый". Элемент "ячейка", проблема возникает, когда я прокручиваю раздел элемента за пределами экрана и возвращаюсь к представлению, приложение вылетает с EXC_BAD_ACCESS, или даже если я не прокручиваю и вместо этого нажимаю кнопку "Назад" на navBar, все та же ошибка.
- (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;
}
singleItem имеет модальный тип PurchaseItem для основных данных
Теперь, когда я знаю, что является причиной ошибки, как я могу ее решить, я перепробовал все, что знаю, и кое-что из того, чего не знаю, но все же, никакого прогресса, пожалуйста, любые предложения относительно того, как решить эту проблему без редизайна, является моей целью., возможно, есть ошибка, которую я делаю, которую я не вижу, но если это природа авто-релиза, то я изменю дизайн.
ОБНОВЛЕНИЕ: добавление 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
2 ответа
Глядя на ваш метод save: в AddItemViewController, я не вижу, где хранится элемент. Он автоматически выпущен, поэтому его нужно где-то сохранить. Возможно, что:
[purchase addItemsObject:item]
сохраняет его, но я должен увидеть этот код.
РЕДАКТИРОВАТЬ:
Добавьте это к вашему сохранению: method:
[item retain];
Я не вижу, как предмет сохраняется. Так как это автоматически выпущенный предмет, будет плохой указатель, что приведет к вашей ошибке. И так как вы говорите, что ошибка проявляется как iself, когда вы выгружаете / загружаете представление, и viewDidLoad: элемент ссылки, я думаю, что это хорошая возможность. Я не совсем уверен, так как я не знаю иерархию классов покупки.
Возможно, что-то, что связано с вашим контроллером добавления элементов, может привести к чрезмерному высвобождению изображения в добавленном вами элементе SingleItem. Затем он освобождается, когда ячейка прокручивается за пределами экрана и используется повторно, а затем вылетает при повторном отображении. Если это так, проблема будет лежать вне -cellForRowAtIndexPath:.
Если вы не видите ничего очевидного, вы можете установить постоянные точки останова на [PurchaseItem retain] и [PurchaseItem release] с помощью команды gdb bt 3 (или около того) и посмотреть, что ее выпускает. Вместо этого вам, возможно, придется взглянуть на сохранение и выпуск самого изображения.
Вы пытались запустить статический анализатор кода, чтобы увидеть, обнаруживает ли он связанную ошибку управления памятью?
Еще одна вещь: кажется странным отправлять сообщение-изображение на изображение. Что именно представляет собой класс singleItem.image?