2009-07-07 59 views
5

好iphone EXC_BAD_ACCESS让我有一种UIViewTable和一个UISearchBar有两个范围的按钮。这个想法是,当我按下范围按钮时,UIViewTable的数据源被更改,但我得到了 EXC_BAD_ACCESS错误。与NSMutableArray的

我在我的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(假定发生autorelease)。

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

哦,我也没有创建另一个NSMutableArray没有连接到tableView,仍然得到同样的问题,如果我不释放它在我的if语句中不存在问题,但后来我将有一个内存泄漏??我总是可以只保留阵列和删除/添加对象,但我想知道这是为什么不工作:) 欢呼

+0

就像样式提示一样,您可以通过几种方法简化getListOne/getListTwo方法。例如,你可以将每一行的最后两行合并到return [list autorelease]中。您可以通过返回使用+ arrayWithObjects而不是+ alloc和-initWithObjecs生成的自动释放数组来将它浓缩为一行: - 它意味着同样的事情,但有点短。 :-) – 2009-07-07 15:08:29

回答

7

这是你的问题:

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

您不需要执行此检查 - 凭借您宣布listData财产与retain财产,合成设置器会自动处理旧值。合成的setter将如下所示:

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

请注意以下几件事:旧值被释放,并且新值被保留。此外,在自我分配的情况下,保留发生在之前:如果您分配相同的值,则不希望它过早释放。还要注意,如果新值或旧值是nil,没有什么不好的事情发生,因为Objective-C明确允许你发送消息到nil,没有任何效果。

因此,这意味着只要您设置的属性,您不必担心释放旧值 - 二传手会替你。因为你正在做一个额外的发布版本,所以在你实际使用它之前,这个对象会被释放,所以只要你在释放它之后使用它,你就会得到EXC_BAD_ACCESS

+0

+1 - 您可以完全删除该代码块,因为您在if或else分支中设置self.listData。对提问者:不要因为你把这些东西排除在外而感到沮丧;这是一个诚实的错误和良好的学习经验。每个人在某个时候都会这样做,并且了解综合属性的工作方式有时会非常棘手。 :-) – 2009-07-07 15:15:35