2010-06-17 2 views
32

У меня есть объект NSMutableArray (сохраненный, синтезированный как все), который инициируется просто отлично, и я могу легко добавить к нему объекты с помощью метода addObject:. Но если я хочу заменить объект с определенным индексом на новый в NSMutableArray, он не работает.Как заменить объект в NSMutableArray по заданному индексу новым объектом

Например:

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 
} 

Однако изменение остается верным только внутри метода. от любого другого метода,

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

дает то же старое значение.

Как я могу фактически заменить старый объект на новый с определенным индексом, чтобы это изменение можно было заметить из любого другого метода.

Я даже изменил метод, как это, но результат тот же:

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

пожалуйста помогите ребята :)

+1

Извините, но вам действительно нужно работать через документацию Objective-C, документы управления памятью (которые превосходны) и главы свойств. Этот код * действительно * багги на всем протяжении ... – Eiko

ответ

8

OK, есть несколько битов путаницы здесь.

Вам не нужно принимать mutableCopy от созданного NSMutableArray, чтобы сделать его изменчивым. Это уже изменчиво - ключ от имени. Вам нужно сделать это только в установщике, если вы хотите, чтобы свойство имело семантику copy (которую вы установили, и, возможно, для этого есть веская причина). Но вам, конечно, не нужно будет делать это, как показано в обновленном коде updateTitle, и делает это утечки localList.

Кроме того, вы смешиваете доступ к собственности через self.list и прямое использование list в том же методе. Это не является недопустимым, но это плохая практика, потому что это означает, что любой другой материал, который делают методы доступа, случайно исключается. Обычно для таких свойств все делается через selfза исключением в самих аксессуарах или в dealloc и, возможно, в init (мнения, по-видимому, отличаются от этого), где вы можете получить доступ к ivar напрямую.

Кроме того, никогда не звоните [self.list release] - аксессуар свойства не предоставляет правообладателю. Выполнение этого закончится слезами, отметьте мои слова.

Ничего из этого не отвечает на реальный вопрос, поэтому ваши изменения исчезают. Исходный код updateTitle не объясняет это, насколько я вижу - он должен работать. Поэтому я подозреваю, что в другом месте вы звоните self.list = theOriginalList и, следовательно, уничтожаете свои изменения.

Update:

Просто ради аргумента, я собираюсь отправить то, что я думаю, что код размещен, вероятно, имел в виду выглядеть.Я сохранил ваше использование строки, чтобы передать индекс updateTitle, но я хотел бы указать, что это так: неправильный. Это номер, вы должны передать его как таковой. Даже если номер поступает из текстового поля или чего-то еще, это вызывает беспокойство вызывающего абонента; интерфейс класса должен указывать число. Точно так же кажущееся изменение индексации от 1 до 0. Пожалуйста, не делайте этого неявно, это рецепт плача и скрежещения зубов.

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 

Это очищает различные вопросы, но обратите внимание, что updateTitle в основном то же самое. Если вы отбросите все это, и изменение все равно не сохранится, вы определенно сбросите list где-нибудь.

+0

Спасибо за советы walkytalky. Я изменил свой код соответственно. Теперь я прошел через свой код, и я не могу найти ни одного вызова self.list = theOriginalList в любом месте. Но мне интересно, вызывает ли метод setList: ', когда используется «replaceObjectAtIndex». Есть идеи? Еще раз спасибо :) – user339076

+1

'replaceObjectAtIndex' определенно не должен вызывать' setList' - это метод в самом массиве, и он не знает и не заботится об аксессуарах свойств объекта (ов), к которому он относится. – walkytalky

+0

Можете ли вы мне рассказать. о методе 'replaceObjectAtIndex'. если я назову 'list [i] = newTitle;' компилировать без ошибок или предупреждений. что-то не так с этим использованием?Спасибо :) – hqt

119

Это делает трюк:

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

не могли бы вы мне рассказать. о методе 'replaceObjectAtIndex'. если я назову 'list [i] = newTitle;' компилировать без ошибок или предупреждений. что-то не так с этим использованием? Спасибо :) – hqt

+9

@Mario Вы даже не прочитали вопрос, не так ли? Но эй, также не было 52 других людей ... – walkytalky

5

Более прямой ответ был бы:

self.list[i] = newTitle; 

Это просто работает как

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

Вы не заметили «копию» в свойстве, из-за чего каждый вариант был неправильным. – gnasher729

0

Посмотрите на этой линии:

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

Копия означает, что всякий раз, когда вы получаете доступ к self.list, вы не получаете переменную экземпляра «_list» вашего объекта, а копию этого списка. Если вы пишете [self.list replaceObjectAtIndex ...], вы заменяете объект в этой копии вашего списка; исходный _лист не изменился. Просто используйте

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

И, чтобы избежать путаницы, удалить «список» переменную экземпляра и оператор @synthesize, а затем использовать _list для доступа к переменной экземпляра.

+0

Если я не ошибаюсь, атрибут «copy» означает, что только на «set» экземпляр создает копию. Но этого не происходит, как вы говорили. См. Https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/EncapsulatingData/EncapsulatingData.html –

+0

@OdedRegev right, атрибут 'copy', как указано в документах, применяется только для вновь созданных свойств. Getters, как я понимаю, вернет исходный объект, но не позволит вам изменить его в классе владельца (он просто останется в исходном -unmodified-property). –

0

Для Swift вы можете попробовать:

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

Наконец Got Some Совершенный код,

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

// Вывод будет как

array = [ 
    { 
    "name": "Kavin", 
    "Age": 25, 
    "is_married": "false" 
    }, 
    { 
    "name": "Kumar", 
    "Age": 25, 
    "is_married": "false" 
    } 
] 
Смежные вопросы