[英]Objective-C/iOS : Message sent to deallocated instance
这是我在stackoverflow.com上的第一篇文章,所以请善待(倒带);)
我有一个基于导航的应用程序,其目的是在表视图中显示博客帖子(标题)(使用JSON)。 我遇到的问题发生在一个单元格离开屏幕然后重新进入时。我得到了一个EXC_BAD_ACCESS(因为我向一个解除分配的实例发送了一条消息),所以我很难理解它来自哪里,我终于找到了一个解。 但事实是我并不完全理解问题是如何发生的。 这就是为什么我需要有人来启发我,我认为这是基本的理解!
当与JSON Web服务的连接完成加载后,我解析JSON代码以获取博客帖子列表(recentPosts),然后我为每个帖子(blogArticle)创建一个BlogArticle对象,将其存储在MutableArray iVar(allEntries)中并在表视图中插入一行:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
[responseData release];
NSError *error;
SBJsonParser *json = [[SBJsonParser new] autorelease];
NSDictionary *recentPostsData = [json objectWithString:responseString error:&error];
[responseString release];
NSArray *recentPosts = [recentPostsData objectForKey:@"posts"];
int i = 0;
for (NSDictionary *post in recentPosts) {
BlogArticle *blogArticle = [[BlogArticle alloc] initWithDictionary:post];
[allEntries insertObject:blogArticle atIndex:i];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:i inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
i++;
}
}
这是BlogArticle对象的初始化,它变成了问题的根源:
- (id)initWithDictionary:(NSDictionary *)article
{
if (self = [super init])
{
// title = [[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML] copy];
// title = [[NSString alloc] initWithString:[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML]];
title = [[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML];
}
return self;
}
因此,每个没有像我一样乏味的Objective-C程序员都能够告诉标题在被分配之前从未被分配过。 如果我取消注释上面两行中的一行,它将起作用。 当我尝试使用该标题变量初始化单元格时,程序完全崩溃,这里:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSLog(@"indexPath.row = %i", indexPath.row);
// Configure the cell.
BlogArticle *article = [allEntries objectAtIndex:indexPath.row];
cell.textLabel.text = article.title;
return cell;
}
现在,我需要理解的是,为什么它在没有分配iVar的情况下进行编译/工作,以及它究竟导致了什么问题(或者确切地说释放了标题的内容导致程序崩溃)。 关于iOS环境中的内存管理的任何好资源(noob友好)将非常感激。
提前致谢 :)
这条线
title = [[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML];
正在分配一个自动释放的字符串。 从本质上讲,可以认为自动释放的字符串将在方法结束时释放(尽管它可以持续更长时间,以这种方式考虑它是有用的)。
您知道字符串是自动释放的,因为方法gtm_stringByUnescapingFromHTML
的名称不是以alloc
, new
, copy
或mutableCopy
开头的。
您可以为此添加retain
以阻止它自动释放:
title = [[[article valueForKey:@"title"] gtm_stringByUnescapingFromHTML] retain];
现在你拥有了这个字符串,直到你说出来它才会被释放。
我知道的最好的总结是苹果公司自己的文档在这里 。
嗯,问题是,如果你想自己管理它的内存,你必须初始化你的对象。 你为什么要现在管理标题的记忆?
非常简单:存储在数组,集合,字典等中的每个对象引用都由数组,字典和集管理。
如果您现在只在单元格中使用此引用(通过编写:“title = ...”),则还会将引用添加到单元格中。 现在,单元格也负责对象引用。 因此,如果tableView想要释放你的单元格,这将不时发生以节省内存,单元格将释放你的标题对象。 这会导致NSDitionary非常难过,因为NSDictionary想要关注存储在其自身内的对象。
所以你可以在tableView-method中编写以下内容:
cell.textLabel.text = [article.title retain];
或者您自己方法的注释行。 这意味着,您将“提升”对象的存储级别,如果它被释放,存储级别本身将减少一个。 如果存储级别将达到零,它将被完全释放(如果你的tablecell被释放并且你的NSDIctionary会发生这种情况)
我希望我能帮到你一点:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.