2010-06-17 9 views
32

Mam obiekt NSMutableArray (zachowany, zsyntetyzowany jak wszystkie), który jest inicjowany poprawnie i mogę z łatwością dodawać do niego obiekty za pomocą metody addObject:. Ale jeśli chcę zamienić obiekt na określonym indeksie na nowy w tym NSMutableArray, to nie działa.Jak zamienić obiekt w obiekcie NSMutableArray na danym indeksie na nowy obiekt?

Na przykład:

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 
} 

Jednak zmiana pozostaje prawdą tylko wewnątrz metody. z dowolnej innej metody, daje taką samą starą wartość.

W jaki sposób mogę faktycznie zastąpić stary obiekt nowym na konkretny indeks, aby zmiana mogła zostać zauważona również w ramach dowolnej innej metody.

nawet zmodyfikowane metody takiego, ale wynik jest taki sam:

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

pomóż chłopaki :)

+1

Przepraszamy, ale naprawdę trzeba pracować poprzez dokumentację Objective-C, dokumenty zarządzania pamięcią (które są świetne) i rozdziały własności. Ten kod * naprawdę * jest buggy na całym ... – Eiko

Odpowiedz

8

ok, istnieje kilka bitów zamieszania tutaj.

Nie trzeba pobierać mutableCopy z nowo utworzonego NSMutableArray, aby można było go zmienić. Jest już zmienna - wskazówka znajduje się w nazwie. Musisz to zrobić tylko w seterze, jeśli chcesz, aby obiekt posiadał semantykę copy (którą ustawiłeś i oczywiście masz ku temu dobry powód). Ale na pewno nie musiałbyś tego robić, jak pokazano w zaktualizowanym kodzie updateTitle, i robi to przeciekając localList.

Łączymy również dostęp do nieruchomości przez self.list i bezpośrednio używamy list w tej samej metodzie. Nie jest to nieważne, ale jest to zła praktyka, ponieważ oznacza to, że inne rzeczy, które robi metoda accessor, są losowo ominięte. Zwykle takie właściwości robią wszystko poprzez self, z wyjątkiem w samych akcesorach, lub w dealloc, i prawdopodobnie w init (opinie wydają się różnić w tym zakresie), gdzie można uzyskać bezpośredni dostęp do ivar.

Ponadto, nigdy nie wywołuj [self.list release] - narzędzie do udostępniania właściwości nie nadaje swojej tożsamości dzwoniącemu. Czynienie tego zakończy się łzami, zaznacz moje słowa.

Żadne z tych odpowiedzi na prawdziwe pytanie, dlatego Twoja zmiana znika. Oryginalny kod updateTitle nie wyjaśnia tego, o ile widzę - powinien działać. Podejrzewam, że gdzieś indziej dzwonisz pod numer self.list = theOriginalList i tym samym cofasz zmianę.

Aktualizacja:

tylko ze względu na argument, mam zamiar pisać, co myślę, że kod, który pisał prawdopodobnie oznaczało wyglądać.Zachowałem twoje użycie ciągu do przekazania indeksu do updateTitle, ale chciałbym zaznaczyć, że robienie tego w ten sposób jest błędne. To numer, powinieneś go przekazać jako taki. Nawet jeśli liczba pochodzi z pola tekstowego lub czegoś takiego, to jest to obawa wywołującego; interfejs klasy powinien określać liczbę. Podobnie widoczna zmiana z indeksowania opartego na 1 na 0. Proszę, nie rób tego w sposób pośredni, to przepis na płacz i zgrzytanie zębów.

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 

ten czyści różne problemy, ale należy pamiętać, że updateTitle jest w większości takie same. Jeśli zrzucisz to wszystko i zmiana wciąż nie przetrwa, definitywnie zresetujesz gdzieś list.

+0

Dzięki za poradę walkytalky. Poprawiłem mój kod odpowiednio. Teraz przejrzałem mój kod i nie mogę znaleźć pojedynczego wywołania self.list = theOriginalList. Zastanawiam się jednak, czy metoda setList: zostanie wywołana, gdy prawdopodobnie użyty zostanie element "replaceObjectAtIndex". Jakieś pomysły? Jeszcze raz dziękuję :) – user339076

+1

'replaceObjectAtIndex' zdecydowanie nie powinien nazywać' setList' - jest to metoda na samej tablicy, a ona nie zna i nie dba o właściwości, które są akcesorami obiektu (ów), do których przynależą. – walkytalky

+0

możesz mi powiedzieć. o metodzie 'replaceObjectAtIndex'. jeśli wywołasz 'list [i] = newTitle;' skompiluj bez błędów i ostrzeżeń. czy coś jest nie tak z tym użyciem?Dzięki :) – hqt

119

To załatwia sprawę:

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

możesz mi powiedzieć. o metodzie 'replaceObjectAtIndex'. jeśli wywołasz 'list [i] = newTitle;' skompiluj bez błędów i ostrzeżeń. czy coś jest nie tak z tym użyciem? Dzięki :) – hqt

+9

@Mario Nie przeczytałeś nawet tego pytania, prawda? Ale hej, nie było też 52 innych osób ... – walkytalky

5

Bardziej prosto odpowiedź byłaby:

self.list[i] = newTitle; 

To po prostu działa jak

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

Nie zauważyłeś "kopii" w nieruchomości, która powoduje, że każda odmiana źle się zachowuje. – gnasher729

0

spojrzeć na tej linii:

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

Kopia copy oznacza, że ​​za każdym razem, gdy uzyskujesz dostęp do self.list, nie dostajesz zmiennej instancji "_list" obiektu, ale kopię tej listy. Jeśli napiszesz [self.list replaceObjectAtIndex ...], zamienisz obiekt w tej kopii twojej listy; oryginalna lista jest niezmieniona. Wystarczy użyć

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

i uniknąć nieporozumień, należy usunąć „list” instancji zmiennej oraz oświadczenie @synthesize, a następnie użyć _list dostęp do zmiennej instancji.

+0

Jeśli się nie mylę, atrybut "kopia" oznacza, że ​​tylko przy "ustawieniu" instancja tworzy kopię. Ale tak się nie dzieje "na", jak wspomniałeś. Zobacz https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWoundObjectiveC/EncapsulatingData/EncapsulatingData.html –

+0

@OdedRegev po prawej, atrybut 'copy', ponieważ dokumenty są stosowane tylko w przypadku nowo utworzonych właściwości. Jak rozumiem, Getters zwróci oryginalny obiekt, ale nie pozwoli ci go zmodyfikować w klasie właściciela (pozostanie on po prostu w pierwotnej niezmienionej właściwości). –

0

Dla Swift można spróbować:

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

wreszcie jakiś kod doskonały,

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

// Wyjście będzie jak

array = [ 
    { 
    "name": "Kavin", 
    "Age": 25, 
    "is_married": "false" 
    }, 
    { 
    "name": "Kumar", 
    "Age": 25, 
    "is_married": "false" 
    } 
] 
Powiązane problemy