xcode “EXC_BAD_ACCESS”,“-[CFString 保留]:在表格中滚动时发送到释放实例的消息”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4412067/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
"EXC_BAD_ACCESS", "-[CFString retain]: message sent to deallocated instance" when scrolling in a table
提问by Taz
APPLICATION DESCRIPTION: I am a new iPhone developer. I am working on an application which used two table views then a detail view. The first level table view presents a few categories, when a category is selected a list of topics related to that category is displayed. When a topic is selected a detail view is presented related to that topic.
应用程序描述:我是一名新的 iPhone 开发人员。我正在开发一个应用程序,该应用程序使用两个表视图和一个详细信息视图。The first level table view presents a few categories, when a category is selected a list of topics related to that category is displayed. 选择主题后,将显示与该主题相关的详细信息视图。
When I run the app in the simulator everything seems to work fine (but only briefly!):
当我在模拟器中运行应用程序时,一切似乎都正常(但只是短暂的!):
- First Level Table View:this view with the categories loads fine and works without any problems.
- Topic List View:This view also appears to work fine, but only briefly. It loads all of the correct topics, and I can even quickly scroll up and down through the entire list of topics - but this only works for a couple of seconds while scrolling (after which the application crashes). I can also select any of the topics and the detail view loads successfully.
- Detail View:works fine, no problems.
- 第一级表视图:带有类别的此视图可以正常加载并且可以正常工作。
- 主题列表视图:此视图似乎也工作正常,但只是短暂的。它加载了所有正确的主题,我什至可以在整个主题列表中快速上下滚动 - 但这仅在滚动时工作几秒钟(之后应用程序崩溃)。我还可以选择任何主题并成功加载详细信息视图。
- 详细视图:工作正常,没有问题。
I am using two nibs for the application: MainWindow.xib displays the First Level and Topic View tables. A TopicDetail.xib is used to display the detail information for a topic.
我为应用程序使用了两个笔尖:MainWindow.xib 显示第一级和主题视图表。TopicDetail.xib 用于显示主题的详细信息。
DATA:The First Level View gets its data from a plist which consists of an array of strings. The Topic List View gets its data from a plist of dictionaries. Each dictionary consists of five strings. One of these strings contains "Tags" of categories which relate to the topic. When a category from the First Level View is selected, the Topic View selects the topics with "Tags" which match the selected category, and displays them on the Topic View Table.
数据:第一级视图从由字符串数组组成的 plist 中获取数据。主题列表视图从字典 plist 中获取其数据。每个字典由五个字符串组成。这些字符串之一包含与主题相关的类别的“标签”。当从第一级视图中选择一个类别时,主题视图选择具有与所选类别匹配的“标签”的主题,并将它们显示在主题视图表上。
PROBLEM:My problem is with the second "Topic View." A couple of ways in which I have been able to cause the crash:
问题:我的问题是第二个“主题视图”。我能够导致崩溃的几种方式:
If I quickly scroll up and down through the topic list, for a couple of seconds everything works normally, then the application crashes.
If I scroll one cell off of the screen, I can scroll the same cell back onto the screen without a problem. If I repeat this (scroll the same cell off of the screen a second time then try to scroll it back onto the screen), the app crashes when scrolling the cell back onto the screen.
如果我在主题列表中快速上下滚动,几秒钟后一切正常,然后应用程序崩溃。
如果我从屏幕上滚动一个单元格,我可以毫无问题地将同一个单元格滚动回屏幕。如果我重复此操作(再次将同一单元格从屏幕上滚动,然后尝试将其滚动回屏幕),则在将单元格滚动回屏幕时应用程序会崩溃。
ERROR MESSAGES:The initial error message that was returned was EXC_BAD_ACCESS. When I enabled NSZombieEnabled I got the error message "-[CFString retain]: message sent to deallocated instance"
错误消息:返回的初始错误消息是EXC_BAD_ACCESS。当我启用 NSZombieEnabled 时,我收到错误消息“ -[CFString retain]: message sent to deallocated instance”
Based on these error messages and my research, I believe I have a memory allocation problem where "retain" is being called on an object that has been released, but I can't figure out where this occuring and how to resolve it! Any help would be greatly appreciated - thank you in advance!!
根据这些错误消息和我的研究,我相信我有一个内存分配问题,其中在已释放的对象上调用了“retain”,但我无法弄清楚发生这种情况的位置以及如何解决它!任何帮助将不胜感激 - 在此先感谢您!!
CODE:
代码:
First Level View Controller.h:
一级视图 Controller.h:
#import
@class TopicListController;
@interface FirstLevelViewController : UITableViewController {
NSArray *controllers;
TopicListController *childController;
}
@property (nonatomic, retain) NSArray *controllers;
@end
First Level View Controller.m:
一级视图 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
Topic List Controller.h:
主题列表 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
Topic List Controller.m
主题列表 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
回答by Robert H?glund
Your problem is in tableView:cellForRowAtIndexPath:
. You shouldn't release the following:
你的问题在tableView:cellForRowAtIndexPath:
. 您不应该发布以下内容:
[rowString release];
[rowDetailString release];
when you get the string like:
当你得到这样的字符串时:
NSString *rowString = [[list objectAtIndex:row] objectForKey:TITLE_KEY];
NSString *rowDetailString = [[list objectAtIndex:row] objectForKey:SUBTITLE_KEY];
They are returned as autoreleased objects. You should only ever release something you own, i.e. something you have alloced, retained or gotten from a method starting with new. A good article explaining this is objective-c memory management for lazy people. But to quote the important part:
它们作为自动释放的对象返回。你应该只释放你拥有的东西,即你已经分配、保留或从一个以 new 开始的方法中获得的东西。一篇解释这一点的好文章是针对懒人的objective-c 内存管理。但要引用重要的部分:
- 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).
- 如果你分配它,你就拥有它。
- 如果你复制它,你就拥有它。
- 如果你是新的,你就拥有它。(New 只是 alloc/init 的快捷方式)。