При вызове методов setByAddingX от NSSet объекты какого набора выигрывают ничью? - PullRequest
1 голос
/ 04 марта 2011

Я поднимаю это, потому что объекты, которые сравнивают то же самое с isEquals: не обязательно идентичны. Некоторые (многие) объекты сравнивают только определенные свойства, чтобы определить равенство.

Это делает важным точное поведение следующих методов NSSet:

setByAddingObject:
setByAddingObjectsFromArray:
setByAddingObjectsFromSet:

В документации не указывается, что происходит, когда получатель и параметр содержат эквивалентные объекты. Будет ли полученный NSSet содержать объект от получателя или объект от «другого» параметра?

Обратите внимание, что в NSMutableSet он НЕ определяет поведение своих методов добавления - объекты НЕ будут добавлены, если в наборе уже существует "равный" объект.

Ответы [ 2 ]

1 голос
/ 04 марта 2011

Документация по методу NSMutableSet addObject: , используемая для покрытия аналогичного случая:

Если anObject уже присутствует в наборе, этот метод не влияет ни на набор, ни на anObject.

Но, как видно из ссылки, текущая версия даже не говорит этого. И даже это утверждение действительно охватывает только попытки добавить один и тот же объект; в нем конкретно не говорится о добавлении другого, но равного объекта.

Полагаться на наблюдаемое, но не документированное поведение опасно не только потому, что оно может меняться в зависимости от версии ОС, но и потому, что оно может меняться в одном и том же процессе. Это потому, что NSSet является кластером класса , что означает, что может быть несколько реализаций. Какой из них вы получите, зависит от того, как вы создали набор; нет способа гарантировать, что конкретная реализация будет выбрана или даже существует. *

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

Тот же принцип применим к вашим объектам. Они равны! По этой причине не должно иметь значения, какой из них находится в наборе. Если это имеет значение, то они на самом деле не равны, и вам нужно сделать определение равенства объектов более жестким. (Не забудьте обновить isEqual: и hash.)

В зависимости от того, для чего вы используете набор, вы можете захотеть сделать это еще дальше и убедиться, что не может быть двух одинаковых объектов. Для этого переместите владение, обслуживание и использование набора в класс объектов-членов и пусть он всегда возвращает соответствующий объект вместо создания нового, когда это возможно и уместно.

* И даже если бы вы могли выбрать одну из реализаций, нет никакой гарантии, что она будет иметь поведение, которое вы наблюдали вечно - возможно, и Мерфи говорит, что, вероятно, будет другим в другой версии ОС.

0 голосов
/ 04 марта 2011

Я проверил это с помощью следующего кода. SomeClass определен так, что propertyA является единственным свойством, рассмотренным в хэше, и isEquals:

SomeClass *objectA = [[[SomeClass alloc] init] autorelease];
objectA.propertyA = @"test";
objectA.propertyB = @"objectA";

SomeClass *objectB = [[[SomeClass alloc] init] autorelease];
objectB.propertyA = @"test";
objectB.propertyB = @"objectB";

NSSet *setA = [NSSet setWithObject:objectA];
NSSet *setB = [NSSet setWithObject:objectB];
NSSet *setC = [setA setByAddingObjectsFromSet:setB];

NSLog(@"Set A\n%@", [setA description]);
NSLog(@"Set B\n%@", [setB description]);
NSLog(@"Set C\n%@", [setC description]);

Вывод при запуске этого кода:

2011-03-03 16:35:15.041 temp[50311:207] Set A
{(
    {SomeClass propertyA:test propertyB:objectA}
)}
2011-03-03 16:35:15.041 temp[50311:207] Set B
{(
    {SomeClass propertyA:test propertyB:objectB}
)}
2011-03-03 16:35:15.042 temp[50311:207] Set C
{(
    {SomeClass propertyA:test propertyB:objectA}
)}

Это демонстрирует, что вновь созданный NSSet будет содержать объекты из RECEIVER в случае, если параметр содержит эквивалентные объекты.

РЕДАКТИРОВАТЬ - Я отмечаю это как ответ, потому что это прямо отвечает на вопрос под рукой. Я хотел бы, однако, указать на ответ Питера ниже и обеспокоенность, которую он высказывает. Такое поведение является недокументированным, и поэтому маловероятно, что эти базовые классы изменятся в этом отношении, стоит указать на этот риск. Если вы пишете код, предполагающий такое поведение, возможно , что он сломается в следующем выпуске. Будьте бдительны.

...