0

OK、2日間、cellForRowAtIndexメソッド内にあるエラーを解決しようとしています。まず、このメソッドのバグを追跡したと言いましょう。エラーは[CFDictionary画像]または[タイプ画像ではありません]です割り当て解除されたインスタンスにメッセージが送信されました。

デバッグ フラグ、NSZombie、MallocStack などについては知っていますが、この方法とその理由に絞り込むのに役立ちましたが、アプリの UI を再設計する以外に解決方法がわかりません。

SO 私がやろうとしているのは、このコード ブロックでは、アイテムを含む購入の詳細が表示され、アイテムは独自のセクションにあり、編集モードでは、アイテム セクションの下部にセルが表示されます。 「新しいアイテムを追加」のラベル。このボタンはアイテム追加コントローラーのモーダル ビューを表示します。アイテムが追加され、ビューは購入の詳細画面に戻り、「新しいアイテムを追加」のすぐ上のセクションに追加されたアイテムが表示されます。アイテム」セル、アイテム セクションを画面外にスクロールしてビューに戻ると問題が発生し、アプリが EXC_BAD_ACCESS でクラッシュします。または、スクロールせずにナビゲーション バーの戻るボタンを押しても、同じエラーが発生します。

- (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 は、コア データの Modal Type 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 保持] と [PurchaseItem 解放] に継続的なブレークポイントを配置し、何が解放されているかを確認できます。代わりに、イメージ自体の保持と解放を確認する必要がある場合があります。

静的コード アナライザーを実行して、関連するメモリ管理エラーが検出されるかどうかを確認しましたか?

もう 1 つ: メッセージ -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 に答える