繁体   English   中英

Objective-C / iOS:发送到解除分配的实例的消息

[英]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的名称不是以allocnewcopymutableCopy开头的。

您可以为此添加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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM