Ошибка автовыделения TableViewCell - PullRequest
0 голосов
/ 09 марта 2010

ОК, вот уже два дня я пытаюсь устранить ошибку, которая у меня есть внутри метода cellForRowAtIndex, начнем с того, что я обнаружил ошибку в этом методе, ошибка [CFDictionary image] или [Not a Тип изображения] сообщение, отправленное на освобожденный экземпляр.

Я знаю о флагах отладки, 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;
}

единственный элемент имеет модальный тип 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 ]

0 голосов
/ 09 марта 2010

Глядя на ваш метод save: в AddItemViewController, я не вижу, где хранится элемент.Он автоматически выпущен, поэтому его нужно где-то сохранить.Возможно, что:

[purchase addItemsObject:item] 

сохранит его, но мне нужно будет увидеть этот код.

РЕДАКТИРОВАТЬ:

Добавьте это в свой метод save:*

[item retain];

Я не вижу, как предмет сохраняется.Так как это автоматически выпущенный предмет, будет плохой указатель, что приведет к вашей ошибке.И так как вы говорите, что ошибка проявляется самостоятельно при выгрузке / загрузке представления, и viewDidLoad: элемент ссылки, я думаю, что это хорошая возможность.Я не совсем уверен, так как я не знаю иерархию классов покупки.

0 голосов
/ 09 марта 2010

Возможно, что-то, что связано с вашим контроллером добавления элементов, приводит к чрезмерному высвобождению изображения в добавленном вами элементе. Затем он освобождается, когда ячейка прокручивается за пределами экрана и используется повторно, а затем падает, когда снова отображается. Если это так, проблема будет лежать вне -cellForRowAtIndexPath:.

Если вы не видите ничего очевидного, вы можете установить постоянные точки останова на [PurchaseItem retain] и [PurchaseItem release] с помощью команды gdb bt 3 (или около того) и посмотреть, что ее выпускает. Вместо этого вам, возможно, придется взглянуть на сохранение и выпуск самого изображения.

Вы пытались запустить статический анализатор кода, чтобы увидеть, обнаруживает ли он связанную ошибку управления памятью?

Еще одна вещь: кажется странным отправлять сообщение-изображение на изображение. Что именно представляет собой класс singleItem.image?

...