0

好的,这两天我一直在尝试解决我在 cellForRowAtIndex 方法中遇到的错误,首先说我已经找到了这个方法的错误,错误是 [CFDictionary image] 或 [Not a Type image]消息发送到解除分配的实例。

我知道调试标志、NSZombie、MallocStack 等,它们帮助我将范围缩小到这种方法以及为什么,但除了重新设计应用程序 UI 之外,我不知道如何解决。

所以我想做什么,对于这个代码块,显示一个购买详细信息,其中包含项目,项目在自己的部分中,现在在编辑模式下,项目部分底部出现一个单元格“添加新商品”的标签,此按钮将呈现添加商品控制器的模式视图,添加商品并返回购买详细信息屏幕,刚刚添加的商品在“添加新商品”上方的部分项目”单元格,当我将项目部分滚动到屏幕外并返回查看应用程序崩溃时出现问题,或者即使我不滚动而是点击导航栏上的后退按钮,仍然是同样的错误。

- (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
4

2 回答 2

0

与您的添加项目控制器有关的事情可能会过度释放您添加的 singleItem 中的图像。然后,当单元格滚动到屏幕外并被重用时,它会被释放,然后在重新显示时崩溃。如果这是真的,那么问题就出在 -cellForRowAtIndexPath: 之外。

如果您没有看到任何明显的东西,您可以使用 gdb 命令 bt 3(左右)在 [PurchaseItem retain] 和 [PurchaseItem release] 上放置连续断点,并查看释放它的内容。您可能不得不查看图像本身的保留和释放。

您是否尝试运行静态代码分析器以查看它是否发现相关的内存管理错误?

另一件事:将消息 -image 发送到图像似乎很奇怪。singleItem.image 的类到底是什么?

于 2010-03-09T07:51:47.497 回答
0

查看 AddItemViewController 中的 save: 方法,我看不到项目保留在哪里。它是自动发布的,因此需要保留在某个地方。有可能:

[purchase addItemsObject:item] 

保留它,但我必须查看该代码。

编辑:

将此添加到您的 save: 方法中:

[item retain];

我看不到项目是如何保留的。由于它的自动发布项目将是一个错误的指针,从而导致您的错误。而且由于您说在卸载/加载视图时会出现错误,并且 viewDidLoad: 引用项目,我认为这是一个很好的可能性。我不完全确定,因为我不知道购买的类层次结构。

于 2010-03-09T16:06:28.500 回答