Наборы: неупорядоченные коллекции объектов

Cocoa

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

Рисунок 1 Наборы

Cocoa NSSet
Информация по производительности:
    На практике:
  • Доступ к элементу набора занимает постоянное время.
  • Установка и удаление занимает постоянное время.

Эти показатели предполагают адекватную реализацию для хэш-методов определенных для объектов. При плохой реализации хэш-функций, доступ и редактирование выполняется за линейное время.

Основы наборов

Объект NSSet управляет неизменным набором различных объектов, то есть после создания набора, вы не можете добавлять, удалять или заменять объекты. Можно, однако, изменить отдельные объекты сами (если они поддерживают изменения). Изменчивость коллекции не влияет на изменчивость объектов в коллекции. Вы должны использовать неизменный набор если он измененяется в редких случаях или изменения носят массовый характер.

NSMutableSet, подкласс NSSet, является изменяемым набором различных объектов, который позволяет добавлять и удалять записи в любое время, автоматически выделяя память по мере необходимости. Вы должны использовать изменяемые наборы, если они меняются постепенно, или очень большые, так как большие коллекции занимают больше времени для инициализации.

NSCountedSet, подкласс NSMutableSet, является изменяемым набором, в который можно добавить определенный объект несколько раз, другими словами, элементы набора не обязательно различны. NSCountedSet также известен как мешок. Набор хранит счетчик, связанный с каждым отдельным вставленным объектом. Объекты NSCountedSet отслеживают, сколько раз объекты вставляются и требует, чтобы объекты были удалены тоже количество раз, чтобы полностью удалить объект из набора. Таким образом, существует только один экземпляр объекта учитываемый набором, даже если объект был добавлен несколько раз. Метод countForObject: возвращает количество раз, которое указанный объект был добавлен к этому набору.

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

NSSet предоставляет ряд методов инициализаторов, такие как setWithObjects, и initWithArray:, которые возвращают NSSet объект, содержащий элементы (если таковые имеются), которые вы передаете в качестве аргумента. Объекты добавляются в набор и не копируются (если только вы не передаете YES в качестве аргумента initWithSet:copyItems:). Скорее всего, объект добавляется непосредственно в набор. В среде управления памятью, объект получает retain сообщение, когда он добавлен. Для получения дополнительной информации о копировании и управлении памятью смотрите раздел "Копирование коллекций".

Наборы, за исключением NSCountedSet, являются предпочтительными коллекциими, если вы хотите быть уверены, что объект не предстанет больше, чем один раз, и нет прямого эффекта при добавлении объекта несколько раз.

Изменяемые наборы

Вы можете создать NSMutableSet объект с помощью любого из инициализаторов предоставляемых NSSet. Вы можете создать NSMutableSet объект из экземпляра NSSet (или наоборот) с помощью setWithSet: или initWithSet:.

Класс NSMutableSet предоставляет следующие методы для добавления объектов в набор:

  • addObject: добавляет один объект в набор.
  • addObjectsFromArray: добавляет все объекты из заданного массива в набор.
  • unionSet: добавляет все объекты из другого набора которого уже нет.

NSMutableSet класс дополнительно предоставляет следующие методы для удаления объектов из набора:

  • intersectSet: удаляет все объекты, которые не находятся в другом наборе.
  • removeAllObjects удаляет все объекты из набора.
  • removeObject: удаляет конкретный объект из множества.
  • minusSet: удаляет все объекты, которые находятся в другом наборе.

Поскольку NSCountedSet является подклассом NSMutableSet, он наследует все эти методы. Тем не менее, некоторые из них ведут себя немного по-другому с NSCountedSet. Например:

  • unionSet: добавляет все объекты из другого набора, даже если они уже присутствуют.
  • intersectSet: удаляет все объекты, которые не находятся в другом наборе. Если имеется несколько экземпляров одного и того же объекта в любом множестве, результирующий набор содержит этот объект столько раз, сколько набор с меньшим количеством экземпляров.
  • minusSet: удаляет все объекты, которые находятся в другом наборе. Если объект представлен более одного раза в NSCountedSet, то удаляется только один экземпляр.

В среде управления памятью, когда объект удаляется из изменяемого набора он получает release сообщение. Если этот объект принадлежит только этоve наборe (стандартные правила управления памятью) объект будет освобожден, после того, как он будет удален. Если вы хотите использовать объект после его удаления, вы должны отправить ему retain сообщение, прежде чем он будет удален из набора. Например, если (в листинге 1) aSet является единственным владельцем anObject, третий результат в заявлении сообщит об ошибке выполнения.

Листинг 1. Доступ к объекту после его удаления опасен

id anObject = [aSet anyObject];
[aSet removeObject:anObject];
// если объектом владел только aSet, то следующая строка приведет к ошибке выполнения
[anObject someMessage];

Если вы хотите использовать объект после его удаления из набора, вы должны сначала его сохранить, как показано в листинге 2.

Листинг 2. Сохранение объектов перед удалением дает вам право собственности

id anObject = [[aSet anyObject] retain];
[aSet removeObject:anObject];
[anObject someMessage];
// не забудьте послать anObject сообщение release когда закончите с ним работать

Использование наборов

Класс NSSet предоставляет следующие методы для запроса элементов набора:

  • allObjects возвращает массив, содержащий объекты в наборе.
  • anyObject возвращает некоторый объект в наборе. (Объект выбирается преимуществом, а не случайно.)
  • count возвращает количество объектов в настоящее время в наборе.
  • member: возвращает объект в наборе, эквивалентный указанному объекту.
  • intersectsSet: проверяет два набора на разделение по крайней мере одного объекта.
  • isEqualToSet: проверяет два множества на эквивалентность.
  • isSubsetOfSet: проверяет все объекты, содержащиеся в наборе на присутствие и в другом наборе.

Метод класса NSSet objectEnumerator позволяет обходить элементы множества по одному. Методы themakeObjectsPerformSelector: и makeObjectsPerformSelector:withObject: используются для отправки сообщений на отдельные объекты в наборе. В большинстве случаев, следует использовать быстрое перечисление, потому что это быстрее и гибче, чем при использовании NSEnumerator или метода makeObjectsPerformSelector:. Более подробную информацию о перечислении см. в разделе "Перечисление. Обход элементов коллекции".

Таблицы хэшей

IOS Примечание: класс NSHashTable не доступен в IOS.

NSHashTable класс по умолчанию настроен хранить объекты так же, как это делает NSMutableSet. Он также позволяет дополнительные опции для хранения данных, которые вы можете приспособить для конкретных случаев, например, когда вам нужны продвинутые варианты управления памятью, или, если вы хотите держать определенный тип указателя. Например, карта таблица на рисунке 2 настроена на хранение слабых ссылок на ее элементы. Вы также можете указать, хотите ли вы скопировать объекты, которые вошли в набор.

Рисунок 2 Хэш таблица владения объектами

Cocoa NSHashTable

Вы можете использовать NSHashTable объект, если вы хотите получить неупорядоченный набор элементов, которые используют слабые ссылки в среде сборки мусора. Например, предположим, у вас есть глобальная хеш-таблица, которая содержит некоторые объекты. Поскольку глобальные объекты не собираются, ни один из его содержимых объектов не может быть освобожден, если они проводятся слабо. Хэш-таблицы настроенные для хранения объектов слабо (weak) не владеют их содержимым. Если нет сильных ссылок на объекты в такой хэш-таблице, эти объекты могут быть освобождены. Например, хэш-таблица на рисунке 2, имеет слабые ссылки на ее содержимое. В следующей коллекции, объекты A, C и Z, освобождены, а остальные объекты остаются. Если это должным образом не учитывать, такая практика может привести к непредсказуемому поведению.

Для создания хэш-таблицы, инициализируйте ее с помощью метода initWithOptions:capacity: и соответствующего указателя функции опций. Кроме того, вы можете инициализировать ее с помощью initWithPointerFunctions:capacity:, и соответствующего экземпляра NSPointerFunctions.

NSHashTable класс также определяет конструктор hashTableWithWeakObjects, удобный для создания хэш-таблиц со слабыми (weak) ссылками на его содержание. Она должна использоваться только если вы храните объекты.

Важно только параметры, перечисленные в NSHashTableOptions гарантируют то, что остальная часть API будет работать правильно, в том числе копирование, архивирование и быстрое перечисление. В то время как другие варианты NSPointerFunctions используются для определенных конфигураций, таких, как хранение произвольных указателей, не все комбинации параметров являются действительными. С некоторыми комбинациями, карты таблицы могут работать неправильно или не могут даже правильно инициализироваться.

Для настройки хэш-таблицы использующей произвольные указатели, инициализируйтк ее с параметрами NSPointerFunctionsOpaqueMemory и NSPointerFunctionsOpaquePersonality. При использовании хэш-таблицы содержащих произвольные указатели, должны быть использованы API C функции для указателей void *. Например, вы можете добавить указатель на целочисленное значение, используя подход показанный в листинге 3.

Листинг 3 хэш-таблица настроенная на nonobject указатели

NSHashTable *hashTable=[[NSHashTable alloc] initWithOptions:
    NSPointerFunctionsOpaqueMemory |NSPointerFunctionsOpaquePersonality
    capacity: 1];

NSHashInsert(hashTable, someIntPtr);

//Не забудьте послать release сообщение к hashTable когда закончите с ним работать

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

 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac