iphone - "EXC_BAD_ACCESS", "-[CFString retain]: message sent to deallocated instance"在表格中滚动时

标签 iphone xcode uitableview exc-bad-access

应用程序描述:我是一名新的 iPhone 开发人员。我正在开发一个使用两个 TableView 然后一个详细 View 的应用程序。第一级表格 View 呈现几个类别,当选择一个类别时,将显示与该类别相关的主题列表。选择主题后,将显示与该主题相关的详细 View 。

当我在模拟器中运行应用程序时,一切似乎都工作正常(但只是短暂!):

  • 第一级表格 View :此带有类别的 View 加载良好且工作正常,没有任何问题。
  • 主题 ListView :此 View 似乎也可以正常工作,但只是短暂的。它加载所有正确的主题,我什至可以快速上下滚动浏览整个主题列表 - 但这只能在滚动时持续几秒钟(之后应用程序崩溃)。我还可以选择任何主题,并且详细 View 会成功加​​载。
  • 详细 View :工作正常,没有问题。

我在应用程序中使用两个 Nib :MainWindow.xib 显示第一级和主题 View 表。 TopicDetail.xib 用于显示主题的详细信息。

数据: 第一级 View 从包含字符串数组的 plist 中获取数据。主题 ListView 从字典 plist 中获取数据。每个字典由五个字符串组成。这些字符串之一包含与主题相关的类别的“标签”。当选择第一级 View 中的类别时,主题 View 会选择与所选类别匹配的带有“标签”的主题,并将它们显示在主题 View 表中。

问题:我的问题是第二个“主题 View ”。我导致崩溃的几种方式:

  • 如果我快速上下滚动主题列表,几秒钟内一切正常,然后应用程序就会崩溃。

  • 如果我将一个单元格滚动出屏幕,我可以毫无问题地将同一单元格滚动回屏幕上。如果我重复此操作(再次将同一单元格从屏幕上滚动,然后尝试将其滚动回屏幕上),则当将单元格滚动回屏幕上时,应用程序会崩溃。

错误消息:返回的初始错误消息是EXC_BAD_ACCESS。当我启用 NSZombieEnabled 时,我收到错误消息“-[CFString keep]:消息发送到已解除分配的实例

根据这些错误消息和我的研究,我相信我遇到了内存分配问题,即在已释放的对象上调用“retain”,但我无法弄清楚发生这种情况的位置以及如何解决它!任何帮助将不胜感激 - 提前谢谢您!!

代码:

第一级 View Controller .h:

#import 
@class TopicListController;

@interface FirstLevelViewController : UITableViewController {
    NSArray *controllers;
    TopicListController *childController;
}
@property (nonatomic, retain) NSArray *controllers;
@end

第一级 View Controller .m:


#import "FirstLevelViewController.h"
#import "TopicListController.h"
#import "TopicAppDelegate.h"

@implementation FirstLevelViewController
@synthesize controllers;

- (void)viewDidLoad
{
    self.title = @"Categories"; 
    NSString *path = [[NSBundle mainBundle] pathForResource:@"TopicCategoryList" ofType:@"plist"];  
    NSMutableArray *array = [[NSMutableArray alloc] initWithContentsOfFile:path];   
    self.controllers = array;
    [array release];
    [super viewDidLoad];
}

- (void)viewDidUnload
{
    self.controllers = nil;
    [childController release];
    childController = nil;
    [super viewDidUnload];
}

- (void) dealloc
{
    [controllers release];
    [childController release];
    [super dealloc];
}

#pragma mark -
#pragma mark Table Data Source Methods

- (NSInteger)tableView:(UITableView *)tableview numberOfRowsInSection:(NSInteger)section
{
    return [self.controllers count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *FirstLevelCell = @"FirstLevelCell";    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:FirstLevelCell];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:FirstLevelCell] autorelease];
    }
    NSUInteger row = [indexPath row];
    cell.textLabel.text = [controllers objectAtIndex:row];
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
    return cell;
}

#pragma mark -
#pragma mark Table View Delegate Methods

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (childController == nil) {
        childController = [[TopicListController alloc] init];
    }

    childController.title = @"Topics";
    NSUInteger row = [indexPath row];

    NSString *selectedCategory = [self.controllers objectAtIndex:row];
    childController.selectedCategory = selectedCategory;
    [self.navigationController pushViewController:childController animated:YES];
}                            

@end

主题列表Controller.h:

#import 
@class TopicDetailController;

@interface TopicListController : UITableViewController {

    NSArray *list;
    NSString *selectedCategory;
    TopicDetailController *childController;

}

@property (nonatomic, retain) NSArray *list;
@property (nonatomic, retain) NSString *selectedCategory;

@end

主题列表 Controller .m

#import "TopicListController.h"
#import "TopicAppDelegate.h"
#import "TopicDetailController.h"
#import "NSArray-MutableDeepCopy.h"
#import "TopicConstants.h"

@implementation TopicListController

@synthesize list;
@synthesize selectedCategory;

- (void)viewWillAppear:(BOOL)animated
{
    NSString *path = [[NSBundle mainBundle] pathForResource:@"TopicContent" ofType:@"plist"];

    NSMutableArray *fullArray = [[NSMutableArray alloc] initWithContentsOfFile:path];   
    NSMutableArray *fullArrayCopy = [fullArray mutableDeepCopy];

    NSUInteger items = [fullArrayCopy count];
    NSUInteger item=0;

        for (item; item /*less than*/ items; item++) {
            if ([[[fullArrayCopy objectAtIndex:item] objectForKey:CATEGORIES_KEY] 
             rangeOfString:selectedCategory 
             options:NSCaseInsensitiveSearch].location == NSNotFound) 
        {
            [fullArrayCopy removeObjectAtIndex:item];
            item--;
            items--;
        }
    }

    self.list = fullArrayCopy;
    [fullArray release];
    [self.tableView reloadData];
    [super viewWillAppear:animated];
}

- (void)viewDidUnload
{
    self.list = nil;
    self.selectedCategory = nil;
    [childController release];
    childController = nil;
}

- (void)dealloc
{
    [list release];
    [selectedCategory release];
    [childController release];
    [super dealloc];
}

#pragma mark -
#pragma mark Table Data Source Methods

- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger) section
{
    return [list count];
}

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
    static NSString *DisclosureButtonCellIdentifier = @"DisclosureButtonCellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:DisclosureButtonCellIdentifier];

    if (cell==nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:DisclosureButtonCellIdentifier]
                autorelease];
    }

    NSUInteger row = [indexPath row];
    NSString *rowString = [[list objectAtIndex:row] objectForKey:TITLE_KEY];
    NSString *rowDetailString = [[list objectAtIndex:row] objectForKey:SUBTITLE_KEY];
    cell.textLabel.text = rowString;
    cell.detailTextLabel.text = rowDetailString;
    cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
    [rowString release];
    [rowDetailString release];
    return cell;
}

#pragma mark -
#pragma mark Table Delegate Methods

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (childController == nil) {
        childController = [[TopicDetailController alloc] initWithNibName:@"TopicDetail" bundle:nil];
    }


    NSUInteger row = [indexPath row];

    NSString *selectedTopicInformation = [[list objectAtIndex:row] objectForKey:INFORMATION_KEY];
    NSString *selectedTopicTitle = [[list objectAtIndex:row] objectForKey:TITLE_KEY];
    NSString *selectedTopicSubtitle = [[list objectAtIndex:row] objectForKey:SUBTITLE_KEY];
    NSString *selectedTopicTips = [[list objectAtIndex:row] objectForKey:TIPS_KEY];

    NSString *detailMessageInformation  = [[NSString alloc] initWithFormat:@"%@.", selectedTopicInformation];
    NSString *detailMessageTitle = [[NSString alloc] initWithFormat:@"%@", selectedTopicTitle];
    NSString *detailMessageSubtitle = [[NSString alloc] initWithFormat:@"%@", selectedTopicSubtitle];
    NSString *detailMessageTips = [[NSString alloc] initWithFormat:@"%@", selectedTopicTips];

    childController.messageInformation = detailMessageInformation;
    childController.messageTitle = detailMessageTitle;
    childController.messageSubTitle = detailMessageSubtitle;
    childController.messageTips = detailMessageTips;

    childController.title = @"Topic Detail";

    [detailMessageInformation release];
    [detailMessageTitle release];
    [detailMessageSubtitle release];
    [detailMessageTips release];
    [self.navigationController pushViewController:childController animated:YES];


}

- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
    if (childController == nil) {
        childController = [[TopicDetailController alloc] initWithNibName:@"TopicDetail" bundle:nil];
    }

    NSUInteger row = [indexPath row];

    NSString *selectedTopicInformation = [[list objectAtIndex:row] objectForKey:INFORMATION_KEY];
    NSString *selectedTopicTitle = [[list objectAtIndex:row] objectForKey:TITLE_KEY];
    NSString *selectedTopicSubtitle = [[list objectAtIndex:row] objectForKey:SUBTITLE_KEY];
    NSString *selectedTopicTips = [[list objectAtIndex:row] objectForKey:TIPS_KEY];

    NSString *detailMessageInformation  = [[NSString alloc] initWithFormat:@"%@.", selectedTopicInformation];
    NSString *detailMessageTitle = [[NSString alloc] initWithFormat:@"%@", selectedTopicTitle];
    NSString *detailMessageSubtitle = [[NSString alloc] initWithFormat:@"%@", selectedTopicSubtitle];
    NSString *detailMessageTips = [[NSString alloc] initWithFormat:@"%@", selectedTopicTips];

    childController.messageInformation = detailMessageInformation;
    childController.messageTitle = detailMessageTitle;
    childController.messageSubTitle = detailMessageSubtitle;
    childController.messageTips = detailMessageTips;

    childController.title = @"Topic Detail";

    [detailMessageInformation release];
    [detailMessageTitle release];
    [detailMessageSubtitle release];
    [detailMessageTips release];
    [self.navigationController pushViewController:childController animated:YES];
}

@end

最佳答案

您的问题出在tableView:cellForRowAtIndexPath:中。您不应发布以下内容:

[rowString release];
[rowDetailString release];

当你得到如下字符串时:

NSString *rowString = [[list objectAtIndex:row] objectForKey:TITLE_KEY];
NSString *rowDetailString = [[list objectAtIndex:row] objectForKey:SUBTITLE_KEY];

它们作为自动释放的对象返回。你应该只释放你拥有的东西,即你从 new 开始的方法中分配、保留或获取的东西。解释这一点的好文章是 objective-c memory management for lazy people 。但引用重要的部分:

  • You own it if you alloc it.
  • You own it if you copy it.
  • You own it if you new it. (New is simply a shortcut for alloc/init).

关于iphone - "EXC_BAD_ACCESS", "-[CFString retain]: message sent to deallocated instance"在表格中滚动时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4412067/

相关文章:

iphone - 删除最后一个字符 UITextField

iphone - 我的文本字段不可编辑

iphone - iPhone是否有任何手写识别库?

iphone - Swift - 自定义键盘高度

xcode - 如何在 Mac OS X 上更新 LLVM 和 Clang

iphone - NSXMLParser可以用来解析HTML吗

ios - Obj-C 获取服务器响应参数并将其放入数组中

ios - Xcode 4和kalviewcontroller

ios - 回收时自定义 iOS UITableViewCells 不会重新布局

ios - UITableViewController 偶尔调整 TableView 的大小