2009-07-07 7 views
5

私はUIViewTableと2つのスコープボタンを持つUISearchBarを持っています。私がスコープボタンを押すと、UIViewTableのデータソースが変更されますが、私は取得しているというアイデアです EXC_BAD_ACCESSエラー。iphone EXC_BAD_ACCESS with NSMutableArray

私は私のUIViewController SearchViewController.mに次のコードを持っている:私は私のSearchViewController.hで

- (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 
} 

を:

私は私のData.mで
@property (nonatomic,retain) NSMutableArray *listData; 

-(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; 
} 

クラッシュする:

私はクラッシュするプロパティを設定していることを確認しました。私の理解は、私がDataMに新しいNSMutableArrayを作成するとき、私はそれをautoreleaseに割り当てるべきだということです。

ビューが読み込まれるとき、私はそれをmyListDataに割り当てます。保持しているプロパティにアクセスしているので、参照カウントが増えます(現在は2回の自動リリースが保留されています)。

ボタンを押してデータソースを変更すると、listDataが存在するかどうかをチェックします(常にそうです)。古いNSMutableArrayカウンタが0になるように解放します(自動解放が発生したと仮定します)。

次に、新しいNSMutableArrayを取得し、このプロパティに設定しました。私の理解は正しいですか?私はこの単純な問題ではあまりにも長い時間を費やしました:(

ああ私はtableViewに接続されていない別のNSMutableArrayを作成しても私は私のif文でそれを解放しない場合、問題は存在しませんが、メモリリークが発生しますか?オブジェクトを削除したりオブジェクトを削除したりすることはできますか? 歓声

+0

スタイルヒントと同様に、いくつかの点でgetListOne/getListTwoメソッドを単純化することができます。たとえば、それぞれの最後の2行を組み合わせて、[list autorelease]を返すことができます。 + allocと-initWithObjecsの代わりに+ arrayWithObjectsで生成されたオートレンダリングされた配列を返すことで、1行に集約することができます。これは同じことを意味しますが、少し短くなります。 :-) –

答えて

7

これは問題です:

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

と宣言したことで、このチェックを行う必要はありません。 210プロパティにretainプロパティを設定すると、合成されたセッターは自動的に古い値をreleaseの世話をします。合成されたセッターは次のようになります。

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

古い値が解放され、新しい値が保持されます。さらに、自己割り当ての場合は、の前にのリリースが発生します。同じ値を割り当てた場合、早期に割り当てを解除する必要はありません。また、Objective-Cがメッセージをnilに送信することを明示的に許可するので、新しい値または古い値のいずれかがnilの場合、何も悪いことは起こりません。

これは、プロパティを設定するたびに古い値を解放することを心配する必要がないことを意味します。セッターはそれを行います。余分なリリースを行っているので、実際に使用する前にオブジェクトの割り当てが解除されます。割り当てが解除された後すぐにEXC_BAD_ACCESSが取得されます。

+0

+1 - ifまたはelseブランチのいずれかにself.listDataを設定しているので、そのブロックを完全に削除することができます。尋問者に:あなたがこれを整理するのに費やした時には、挫折しないでください。それは正直な間違いであり、良い学習経験です。誰もがこのようなことをいつかやって、合成されたプロパティがどのように機能するかを理解することは時々難しいかもしれません。 :-) –

+0

ああ、今私は見る=)合成されたセッターが何をしているのか分からなかった。元気いっぱい! – Allan