【问题标题】:iphone EXC_BAD_ACCESS with NSMutableArrayiphone EXC_BAD_ACCESS 与 NSMutableArray
【发布时间】:2009-07-07 12:35:57
【问题描述】:

好的,所以我有一个 UIViewTable 和一个带有两个范围按钮的 UISearchBar。这个想法是,当我按下范围按钮时,UIViewTable 的数据源会发生变化,但我得到了 EXC_BAD_ACCESS 错误。

我的 UIViewController SearchViewController.m 中有以下代码:

- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange: (NSInteger) selected scope
{
    MyAppDelegate *delegate = (MyAppDelegate *) [[UIApplicationsharedApplication] delegate];
    if (self.listData != nil) {
        [self.listData release];
    }
    if (selectedScope == 0) {
        self.listData = [delegate.data getListOne];
    }
    else {
        self.listData = [delegate.data getListTwo];
    }
}

- (void) viewDidLoad {
    MyAppDelegate *delegate = (MyAppDelegate*) [[UIApplication sharedApplication] delegate];
    self.listData = [delegate.data getListOne];

    //some other unrelated code
}

在我的 SearchViewController.h 中有:

@property (nonatomic,retain) NSMutableArray *listData;

在我的 Data.m 中有:

-(NSMutableArray *) getListOne {
     NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:@"test1",
                                                                    @"test2",
                                                                    nil];
     [list autorelease];
     return list;
}

-(NSMutableArray *) getListTwo {
     NSMutableArray *list = [[NSMutableArray alloc] initWithObjects:@"test3",
                                                                    @"test4",
                                                                    nil];
     [list autorelease];
     return list;
}

它崩溃了:

self.listData = [delegate.data getListTwo];

当我设置它崩溃的属性时,我检查了它。我的理解是,当我在 Data.m 中创建新的 NSMutableArray 时,我应该将其分配为 autorelease。

当视图加载时,我将其分配给我的 listData,并且由于我正在访问已保留的属性,因此引用计数会增加(因此它现在是 2 个挂起的自动释放)。

当我按下按钮更改数据源时,我也会检查 listData 是否存在(它总是存在),释放它以便旧的 NSMutableArray 计数器为 0(假设发生了自动释放)。

然后我得到一个新的 NSMutableArray 并将其设置为这个属性......我的理解是否正确?我在这个简单的问题上花了太长时间:(

哦,我还创建了另一个未连接到 tableView 的 NSMutableArray 并且仍然遇到同样的问题,如果我没有在我的 if 语句中释放它,问题不存在但我会出现内存泄漏? ?我总是可以保留数组并删除/添加对象,但我想知道为什么这不起作用:) 干杯

【问题讨论】:

  • 作为一种风格提示,您可以通过几种方式简化您的方法 getListOne/getListTwo。例如,您可以将每行的最后 2 行组合成 return [list autorelease]。您可以通过返回使用 +arrayWithObjects 而不是 +alloc 和 -initWithObjecs 生成的自动释放数组来将其压缩为一行: - 它的含义相同,但更短一些。 :-)

标签: iphone objective-c


【解决方案1】:

这是你的问题:

if (self.listData !=nil)
{
    [self.listData release];
}

您不需要执行此检查 - 由于您使用 retain 属性声明了 listData 属性,因此合成的 setter 会自动处理 release 旧值。合成的 setter 看起来像这样:

- (void) setListData:(NSMutableArray *)listData
{
    [listData retain];
    [self->listData release];
    self->listData = listData;
}

这里注意几点:旧值被释放,新值被保留。此外,保留发生在发布之前,以防自分配:如果您分配相同的值,您不希望它被过早地释放。另请注意,如果新值或旧值是 nil,则不会发生任何不良情况,因为 Objective-C 明确允许您向 nil 发送消息,但没有任何效果。

因此,这意味着无论何时设置属性,您都无需担心释放旧值——setter 会为您完成这些工作。因为您正在执行额外的释放,所以对象在您实际使用它之前就被释放了,所以一旦您在它被释放后使用它,您就会得到EXC_BAD_ACCESS。

【讨论】:

  • +1 — 您可以完全删除该代码块,因为您在 if 或 else 分支中设置了 self.listData。对提问者:不要因为你花时间整理这些而感到沮丧;这是一个诚实的错误,也是一次很好的学习经历。每个人在某些时候都会做这样的事情,理解合成属性的工作原理有时会很棘手。 :-)
  • 啊是的,现在我明白了 =) 我没有意识到合成二传手在幕后做了什么。伙计们干杯!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-07
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多