NSMutableArray добавить объект только в качестве указателя? - PullRequest
5 голосов
/ 30 марта 2009

У меня есть этот маленький код

 NSMutableArray *myArray = [[NSMutableArray alloc] init]; 
 NSNumber *myNumber = [NSNumber numberWithDouble:752.65];

 [myArray addObject:myNumber];

С этим кодом я храню объекты в массиве. Но теперь у меня есть два независимых друг от друга объекта.

Если я изменю myNumber после его добавления в массив, значение внутри массива не изменится. Как я могу заархивировать это? Я пытался дать указатель только на массив, но он не работал.

Ответы [ 4 ]

16 голосов
/ 30 марта 2009

Вы не можете поместить переменную в массив, и вот что такое myNumber: переменная. Переменная является контейнером, а также массивом; разница в том, что переменная также не является объектом *, как массив, и вы можете помещать объекты только в массив.

То, что вы передаете addObject:, это не переменная myNumber, а объект, который она содержит. Это то, что вы добавляете в массив.

Чтобы добавить переменную вместо объекта внутри нее, вам нужно будет сделать addObject:&myNumber, чтобы передать указатель на саму переменную. Но это не сработает по двум причинам:

  1. Как я уже говорил, переменная не является объектом, и вы можете добавлять только объекты.
  2. Поскольку это локальная переменная, она исчезнет при выходе из функции; тогда у вас есть указатель на мертвую память внутри вашего массива. Когда вы обращаетесь к тому, что находится по этому указателю, ваша программа падает.

Есть три решения, которые будут работать:

  1. Как предлагает f3lix, создайте изменяемый класс чисел и создайте свой числовой объект из этого класса вместо NSNumber. Вам нужно будет переопределить все примитивные методы NSValue, как описано в документации NSNumber .
  2. Заменить объект в массиве вместо того, чтобы изменять его. Конечно, для этого требуется доступ к массиву везде, где вы хотите изменить номер.
  3. Создайте класс объектов модели, у которого в качестве свойства указан номер.

Это последнее решение, на мой взгляд, правильное. Я сомневаюсь, что вы управляете только списком чисел; Скорее всего, вы показываете пользователю список того, что имеет номер в качестве свойства. Смоделируйте это в своем коде, и все станет намного проще.

Ваш код после замены пустых NSNumbers объектами модели будет выглядеть примерно так:

MyModelObject *myModelObject = [[[MyModelObject alloc] init] autorelease];
[myModelObject setNumber:[NSNumber numberWithDouble:42.0]];
[myArray addObject:myModelObject];

//Some time later, you decide to change the number.
[[myArray objectAtIndex:idx] setNumber:[NSNumber numberWithDouble:43.0]];
//Or:
for (MyModelObject *obj in myArray) {
    [obj setNumber:1000.0];
}

* Я имею в виду объекты Какао. Язык C называет любой указатель, int и т. Д. «Объектом», но это другое определение.

10 голосов
/ 30 марта 2009

Ваша проблема в том, что NSNumber объекты неизменны ; Это означает, что вы не можете изменить их значение. Таким образом, чтобы изменить значение, вы должны создать новый объект NSNumber. Например:

myNumber = [NSNumber numberWithDouble:[myNumber doubleValue]+1.0]

Теперь, конечно, у вас есть myNumber, указывающий на объект, отличный от того, который вы добавили в массив. Поэтому вы должны обновить массив, заменив измененный объект NSNumber:

[myArray replaceObjectAtIndex:0 withObject:myNumber]

Ну, это оставляет вас с проблемой, что вы должны хранить индекс вместе с каждым NSNumber, чтобы иметь возможность обновлять массив. Что неудобно, если вы хотите передать объект NSNumber и разрешить изменение значения.

Вы можете решить эту проблему, введя объект-оболочку, который вы оберните вокруг NSNumber, чтобы разрешить прозрачные обновления, или вы можете просто создать свой собственный класс, который обрабатывает ваше doubleValue (несколько изменяемый класс NSNumber).

3 голосов
/ 30 марта 2009

Если вы измените указатель myNumber, то, как вы сказали, значение, сохраненное в массиве, не изменится. Однако указатель, хранящийся в массиве, является копией myNumber, поэтому если вы измените объект, на который указывает myNumber, на объект, на который указывает элемент массива, это изменение будет отражено, поскольку это тот же объект.

То, что вы, похоже, хотите сделать, - это сделать так, чтобы массив указывал на другой объект (всякий раз, когда вы меняете myNumber). Вам придется сделать это вручную, используя, например, -replaceObjectAtIndex: withObject :, например, так:

NSNumber *myNumber = [NSNumber numberWithDouble: 3.141592];
int myNumberIndex = [myArray count];
[myArray addObject: myNumber];

myNumber = ...; //whatever
[myArray replaceObjectAtIndex: myNumberIndex withObject: myNumber];

Что этот код делает, по сути, сохраняет индекс объекта, который вы помещаете в myArray, а затем заменяете этот объект новым.

2 голосов
/ 23 сентября 2012

Звучит так, будто вы хотите что-то вроде NSPointerArray ...

NSPointerArray, вероятно, является одним из наиболее мощных (этих) специализированных классов коллекций. Это указывает на NSArray -подобный интерфейс, но допускает вставку нулевых значений (и произвольных указателей). Кроме того, указав определенные параметры при создании экземпляра NSPointerArray, вы можете настроить свой массив на использование определенных политик управления памятью в отношении объектов, хранящихся в нем.

Вы указываете параметры для своего экземпляра NSPointerArray при его создании с использованием методов -initWithOptions: или -initWithPointerFunctions:. При использовании метода -initWithOptions: `, вы указываете, что создаваемый вами массив будет подчиняться политикам, заданным параметрами, которые вы передаете в качестве параметра. Параметры, которые задаются с помощью побитового или, задают определенные политики или «личности» для массива.

и это продолжается ...

Когда вы передаете этот экземпляр в NSPointerArray, он будет использовать функции, которые вы определили при вставке, удалении и т. Д., Вместо обычных методов сохранения, освобождения и других методов, которые могут быть используется в нормальном NSArray.

Источник (но я бы посмотрел в другом месте, если вы хотите узнать больше)

...