2009-07-07 12 views
5

Ok, tengo una UIViewTable y una UISearchBar con dos botones de alcance. La idea es que cuando presiono un botón de alcance, se cambia el origen de datos para UIViewTable, pero obtengo el error EXC_BAD_ACCESS.iphone EXC_BAD_ACCESS con NSMutableArray

he el código siguiente en mi 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 
} 

en mi SearchViewController.h tengo:

@property (nonatomic,retain) NSMutableArray *listData; 

en mi Data.m tengo:

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

Se bloquea en:

self.listData = [delegate.data getListTwo]; 

Comprobé que es cuando estoy estableciendo la propiedad que se bloquea. Tengo entendido que cuando creo el nuevo NSMutableArray en Data.m lo asigno de manera automática como debería.

Cuando se carga la vista, la asigno a mi listData y como estoy accediendo a la propiedad que se ha retenido, el recuento de referencias se incrementa (por lo que ahora es 2 autorizaciones pendientes).

Cuando presiono el botón para cambiar la fuente de datos, compruebo también si aparece listData (que siempre lo hará), suéltelo para que el contador NSMutableArray antiguo sea 0 (suponiendo que se haya producido la liberación automática).

Luego obtengo un nuevo NSMutableArray y lo configuro en esta propiedad ... ¿es correcto mi entendimiento? He gastado demasiado tiempo en este simple problema :(

oh también creé otro NSMutableArray que no estaba conectado a tableView y todavía tengo el mismo problema, también si no lo lanzo en mi sentencia if el problema no existe, pero entonces tendrá una pérdida de memoria ?? yo siempre podría simplemente mantener la matriz y eliminar/añadir objetos, pero quiero saber por qué esto no está funcionando :) aplausos

+0

Al igual que un consejo de estilo, puede simplificar sus métodos getListOne/getListTwo de varias maneras. Por ejemplo, podría combinar las últimas 2 líneas de cada una en retorno [lista de liberación automática]. Puede condensarlo en una sola línea devolviendo una matriz liberada automáticamente generada con + arrayWithObjects en lugar de + alloc y -initWithObjecs: - significa lo mismo pero es un poco más corto. :-) –

Respuesta

7

ésta es su problema:

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

No necesita hacer este control - en virtud del hecho de que declaró el listData propiedad con la propiedad retain, el colocador sintetizado se ocupa automáticamente de release con el valor anterior. El colocador sintetizado sería algo como esto:

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

Nota algunas cosas aquí: el valor antiguo es liberado, y está retenido el nuevo valor. Además, la retención ocurre antes de la versión, en caso de autoasignación: si asigna el mismo valor, no desea que se desasigne prematuramente. También tenga en cuenta que si el valor nuevo o antiguo es nil, no pasa nada malo, ya que Objective-C explícitamente le permite enviar mensajes al nil, sin tener ningún efecto.

Por lo tanto, esto significa que cada vez que establezca la propiedad, no tiene que preocuparse por liberar el valor anterior; el colocador lo hace por usted. Debido a que está realizando una versión extra, el objeto será desasignado antes de que realmente termine de usarlo, por lo que tan pronto como lo use después de que haya sido desasignado, obtendrá el EXC_BAD_ACCESS.

+0

+1 - Puede eliminar ese bloque de código por completo, ya que está configurando self.listData en la rama if o else. Para el que pregunta: no te sientas frustrado por el tiempo que pasaste clasificando esto; es un error honesto y una buena experiencia de aprendizaje. Todo el mundo hace algo como esto en algún momento, y entender cómo funcionan las propiedades sintetizadas puede ser complicado a veces. :-) –

+0

ah sí ahora veo =) No me di cuenta de lo que el setter sintetizado estaba haciendo detrás de las escenas. ¡animo amigos! – Allan

Cuestiones relacionadas