2010-06-17 12 views
32

Tengo un objeto NSMutableArray (retenido, sintetizado como todos) que se inicia muy bien y puedo agregar objetos fácilmente mediante el método addObject:. Pero si deseo reemplazar un objeto en un índice determinado con uno nuevo en ese NSMutableArray, no funciona.Cómo reemplazar un objeto en un NSMutableArray en un índice dado con un nuevo objeto

Por ejemplo:

ClassA.h:

@interface ClassA : NSObject { 
    NSMutableArray *list; 
} 

@property (nonatomic, copy, readwrite) NSMutableArray *list; 

@end 

ClassA.m:

#import "ClassA.h" 

@implementation ClassA 

@synthesize list; 

- (id)init 
{ 
    [super init]; 
    NSMutableArray *localList = [[NSMutableArray alloc] init]; 
    self.list = localList; 
    [localList release]; 
    //Add initial data 
    [list addObject:@"Hello "]; 
    [list addObject:@"World"]; 
} 


// Custom set accessor to ensure the new list is mutable 
- (void)setList:(NSMutableArray *)newList 
{ 
    if (list != newList) 
    { 
     [list release]; 
     list = [newList mutableCopy]; 
    } 
} 

-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex 
{ 
    int i = [theIndex intValue]-1; 
    [self.list replaceObjectAtIndex:i withObject:newTitle]; 
    NSLog((NSString *)[self.list objectAtIndex:i]); // gives the correct output 
} 

Sin embargo, el cambio sigue siendo cierto sólo dentro del método. desde cualquier otro método, el

NSLog((NSString *)[self.list objectAtIndex:i]); 

da el mismo valor anterior.

¿Cómo puedo reemplazar el objeto viejo con uno nuevo en un índice específico para que el cambio también se note desde cualquier otro método?

incluso modificó el método como este, pero el resultado es el mismo:

-(void)updateTitle:(NSString *)newTitle:(NSString *)theIndex 
{ 
    int i = [theIndex intValue]-1; 

    NSMutableArray *localList = [[NSMutableArray alloc] init]; 
    localList = [localList mutableCopy]; 
    for(int j = 0; j < [list count]; j++) 
    { 
     if(j == i) 
     { 
      [localList addObject:newTitle]; 
      NSLog(@"j == 1"); 
      NSLog([NSString stringWithFormat:@"%d", j]); 
     } 
     else 
     { 
      [localList addObject:(NSString *)[self.list objectAtIndex:j]]; 
     } 
    } 
    [self.list release]; 
    //self.list = [localList mutableCopy]; 
    [self setList:localList]; 
    [localList release]; 
} 

por favor ayuda a chicos :)

+1

Lo sentimos, pero que realmente necesita para trabajar a través de la documentación de Objective-C, los documentos de gestión de memoria (que son geniales) y los capítulos de propiedad. Este código * realmente * tiene errores en todas partes ... – Eiko

Respuesta

8

OK, hay algunas cosas de la confusión aquí.

No es necesario tomar un mutableCopy de un recién creado NSMutableArray para hacerlo mutable. Ya es mutable, la clave está en el nombre. Solo necesita hacer eso en el colocador si desea que la propiedad tenga semántica copy (que ha establecido, y puede que tenga una buena razón, por supuesto). Pero ciertamente no necesitarías hacerlo como se muestra en tu código actualizado updateTitle, y al hacerlo se filtra localList.

Además, está mezclando el acceso a la propiedad a través de self.list y el uso directo de list en el mismo método. Esto no es inválido, pero es una mala práctica, ya que significa que cualquier otra cosa que hagan los métodos de acceso se omite aleatoriamente. Es común que propiedades como esta hagan todo por selfexcepto en los accesos mismos, o en dealloc, y posiblemente en init (las opiniones parecen diferir sobre esto), donde accederían directamente al ivar.

Además, nunca llame al [self.list release] - el acceso a la propiedad no otorga la propiedad de la persona que llama. Hacer esto terminará en lágrimas, marca mis palabras.

Nada de esto responde a la pregunta real, por lo que su cambio desaparece. El código original updateTitle no lo explica por lo que puedo ver, debería funcionar. Entonces sospecho que en otro lugar está llamando al self.list = theOriginalList y por lo tanto, deshaciendo su cambio.

Actualización:

Sólo por el bien de la discusión, voy a publicar lo que yo creo que el código que envió es probablemente significaba para que parezca.He conservado el uso de una cadena para pasar el índice a updateTitle, pero me gustaría señalar que hacerlo de esta manera es incorrecto. Es un número, debes pasarlo como tal. Incluso si el número proviene de un campo de texto o algo así, esa es la preocupación de quien llama; la interfaz de clase debe especificar un número. De manera similar, el aparente cambio de indexación basada en 1 a 0. Por favor, no hagas este tipo de cosas implícitamente, es una receta para llorar y rechinar de dientes.

ClassA.h:

#import <Cocoa/Cocoa.h> 
@interface ClassA : NSObject 
{ 
    NSMutableArray* list; 
} 
- (void) setList:(NSMutableArray*)newList; 
- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex; 
@property (nonatomic, copy, readwrite) NSMutableArray* list; 
@end 

ClassA.m:

#import "ClassA.h" 

@implementation ClassA 
@synthesize list; 

- (id) init 
{ 
    if (self = [super init]) 
    { 
     list = [[NSMutableArray alloc] init]; 
     [list addObject:@"Hello "]; 
     [list addObject:@"World"]; 
    } 
    return self; 
} 

- (void) setList:(NSMutableArray*) newList 
{ 
    if (list != newList) 
    { 
     [list release]; 
     list = [newList mutableCopy]; 
    } 
} 

- (void) updateTitle:(NSString*)newTitle forIndex:(NSString*)theIndex 
{ 
    int i = [theIndex intValue] - 1; 
    [self.list replaceObjectAtIndex:i withObject:newTitle]; 
} 

- (void) dealloc 
{ 
    [list release]; 
    [super dealloc]; 
} 

@end 

Esto limpia diversas cuestiones, pero tenga en cuenta que updateTitle es prácticamente el mismo. Si deja caer todo esto y el cambio aún no sobrevive, definitivamente está reiniciando list en alguna parte.

+0

Gracias por el consejo walkytalky. He modificado mi código en consecuencia. Ahora, he revisado mi código y no puedo encontrar una sola llamada a self.list = theOriginalList en ningún lado. Pero me pregunto si el método 'setList:' se llama cuando el 'replaceObjectAtIndex' se usa quizás. ¿Algunas ideas? Gracias de nuevo :) – user339076

+1

'replaceObjectAtIndex' definitivamente no debería llamar' setList' - es un método en la matriz en sí, y no sabe ni le importan los elementos de acceso a la propiedad del objeto (s) al que pertenece. – walkytalky

+0

me puedes decir. sobre el método 'replaceObjectAtIndex'. si llamo 'list [i] = newTitle;' compile sin errores ni advertencias. ¿Hay algo mal con este uso?Gracias :) – hqt

119

Esto hace el truco:

[myMutableArray replaceObjectAtIndex:index withObject:newObject]; 
+0

me puedes decir. sobre el método 'replaceObjectAtIndex'. si llamo 'list [i] = newTitle;' compile sin errores ni advertencias. ¿Hay algo mal con este uso? Gracias :) – hqt

+9

@Mario Ni siquiera leíste la pregunta, ¿o sí? Pero bueno, tampoco lo hicieron otras 52 personas ... – walkytalky

5

Una respuesta más directa sería:

self.list[i] = newTitle; 

Esto sólo funciona como

[self.list replaceObjectAtIndex:i withObject:newTitle]; 
+0

No notó la "copia" en la propiedad que hace que cada variación se comporte mal. – gnasher729

0

mirada a esta línea:

@property (nonatomic, copy, readwrite) NSMutableArray *list; 

La copia significa que cada vez que acceda a self.list, no obtendrá la variable de instancia "_list" de su objeto, sino una copia de esa lista. Si escribe [self.list replaceObjectAtIndex ...], reemplace un objeto en esa copia de su lista; la _list original no ha cambiado. Sólo tiene que utilizar

@property (nonatomic, strong, readwrite) NSMutableArray *list; 

Y para evitar confusiones, retire la "lista" variable de instancia y la declaración @synthesize, a continuación, utilizar _list acceder a la variable de instancia.

+0

Si no me equivoco, el atributo "copiar" significa que solo en "establecer" la instancia crea una copia. Pero no sucede en "get" como mencionaste. Consulte https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html –

+0

@OdedRegev right, el atributo 'copy', como dice el documento, solo se aplica a las propiedades recién creadas. Getters, según tengo entendido, devolverá el objeto original pero no le permitirá modificarlo en la clase del propietario (simplemente permanecerá en la propiedad original sin modificar). –

0

Para Swift podría intentar:

//if you have indexPath 
    self.readArray.removeAtIndex((indexPath?.row)!) 
    self.readArray.insert(tempDict, atIndex: (indexPath?.row)!) 
//tempDict is NSDictionary object. 
0

Finalmente consiguió un poco de código perfecto,

let DuplicateArray: NSArray = array 
let DuplicateMutableArray: NSMutableArray = [] 
DuplicateMutableArray.addObjectsFromArray(DuplicateArray as [AnyObject]) 
var dic = (DuplicateMutableArray[0] as! [NSObject : AnyObject]) 
dic["is_married"] = "false" 
DuplicateMutableArray[self.SelectedIndexPath] = dic 
array = [] 
array = (DuplicateMutableArray.copy() as? NSArray)! 

// salida será igual

array = [ 
    { 
    "name": "Kavin", 
    "Age": 25, 
    "is_married": "false" 
    }, 
    { 
    "name": "Kumar", 
    "Age": 25, 
    "is_married": "false" 
    } 
] 
Cuestiones relacionadas