web-dev-qa-db-fra.com

Comment remplacer un objet dans NSMutableArray à un index donné par un nouvel objet

J'ai un objet NSMutableArray (retenu, synthétisé comme tout) qui est lancé parfaitement et je peux facilement y ajouter des objets en utilisant la méthode addObject:. Mais si je veux remplacer un objet à un certain index par un nouvel dans cette NSMutableArray, cela ne fonctionnera pas.

Par exemple:

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
}

Cependant, le changement reste vrai seulement dans la méthode. de toute autre méthode, le 

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

donne la même valeur ancienne.

Comment puis-je réellement remplacer l'ancien objet par le nouvel objet à un index spécifique, de sorte que le changement puisse également être observé depuis n'importe quelle autre méthode.

J'ai même modifié la méthode comme ceci, mais le résultat est le même:

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

S'il vous plaît aider les gars :)

34
user339076

Cela fait le tour:

[myMutableArray replaceObjectAtIndex:index withObject:newObject];
124
Mário Carvalho

OK, il y a un peu de confusion ici.

Vous n'avez pas besoin de prendre une mutableCopy d'une nouvelle NSMutableArray pour la rendre mutable. C'est déjà mutable - l'indice est dans le nom. Vous ne devez le faire dans le sélecteur que si vous voulez que la propriété ait la sémantique copy (que vous avez définie, et qui peut bien entendu avoir de bonnes raisons). Mais vous n’auriez certainement pas besoin de le faire comme indiqué dans votre code updateTitle mis à jour et, ce faisant, fuit localList.

De plus, vous mélangez ensemble l'accès aux propriétés via self.list et l'utilisation directe de list dans la même méthode. Ce n'est pas invalide, mais c'est une mauvaise pratique, car cela signifie que tout ce que font les méthodes d'accès est ignoré de manière aléatoire. Il est courant que des propriétés comme celle-ci fassent tout par selfsauf dans les accesseurs eux-mêmes, ou dans dealloc, et éventuellement dans init (les opinions semblent différer), où vous accéderiez directement à ivar.

En outre, n'appelez jamais [self.list release] - l'accesseur de propriété ne confère pas à l'appelant la propriété de l'appelant. Cela se terminera dans les larmes, marquez mes mots.

Rien de tout cela ne répond à la vraie question, c'est pourquoi votre changement est en train de disparaître. Le code updateTitle original n'explique pas cela autant que je sache, il devrait fonctionner. Je suppose donc que vous appelez quelque part self.list = theOriginalList et annulez ainsi votre modification.

Mettre à jour:

Juste pour les besoins de l’argumentation, je vais publier ce que je pense que le code que vous avez posté est probablement destiné à ressembler. J'ai préservé votre utilisation d'une chaîne pour transmettre l'index à updateTitle, mais j'aimerais souligner que le faire de cette façon est mauvais. C'est un numéro, vous devriez le passer comme tel. Même si le numéro provient d'un champ de texte ou de quelque chose, c'est la préoccupation de l'appelant; l'interface de classe doit spécifier un nombre. De même, le changement apparent de l'indexation basée sur 1 à celle basée sur 0. S'il vous plaît ne faites pas ce genre de chose implicitement, c'est une recette pour pleurer et grincer des dents.

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

Cela résout divers problèmes, mais notez que updateTitle est essentiellement le même. Si vous laissez tomber tout cela et que le changement ne survit toujours pas, vous réinitialisez définitivement list quelque part.

8
walkytalky

Une réponse plus directe serait:

self.list[i] = newTitle;

Cela fonctionne juste comme

[self.list replaceObjectAtIndex:i withObject:newTitle];
6
antonio081014

Pour Swift, vous pouvez essayer:

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

Enfin obtenu un code parfait,

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)!

// la sortie sera comme

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

Regardez cette ligne: 

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

Le copy signifie que chaque fois que vous accédez à self.list, vous n'obtenez pas la variable d'instance "_list" de votre objet, mais une copie de cette liste. Si vous écrivez [self.list replaceObjectAtIndex ...], vous remplacez un objet dans cette copie de votre liste. la _list d'origine est inchangée. Juste utiliser

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

Et pour éviter toute confusion, supprimez la variable d'instance "list" et l'instruction @synthesize, puis utilisez _list pour accéder à la variable d'instance. 

0
gnasher729