Что лучше, NSSet содержит объект или быстрое перечисление? - PullRequest
5 голосов
/ 18 марта 2011

Мне нужно определить, включен ли объект в отношение Базовые данные ко многим (которое является NSSet), и я пытаюсь решить, какое из двух решений лучше:

Решение 1)

if ([managedObject.items containsObject:itemOfInterest])
    return …

Решение 2)

for (NSManagedObject *item in managedObject.items)
    if ([item == itemOfInterest])
        return …

Решение 1 является более кратким, но ссылка NSSet Class Ref говорит, что быстрое перечисление работает лучше, чем objectEnumerator NSSet.Это также работает лучше, чем содержитObject?

Ответы [ 2 ]

20 голосов
/ 18 марта 2011

Ни.Вы должны использовать NSFetchRequest с предикатом.Ваши шаблоны могут случайно испортить всю взаимосвязь, которая очень дорогая и не нужна просто для проверки того, содержит ли она один объект.Существуют способы быть осторожными и не нарушать отношения в целом, но они хрупкие (небольшие изменения в поиске приводят к огромным изменениям в производительности), и поэтому лучше использовать привычку NSFetchRequest, а не коллекцию для поиска.В этих случаях мне нравится устанавливать fetchLimit на 1, поэтому, как только он его найдет, он перестанет выглядеть.

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

Ваши два решения выше слегка отличаются.Первый проверяет, есть ли в коллекции объект, который isEqual: до itemOfInterest.Ваше второе решение проверяет, есть ли в коллекции объект в той же области памяти, что и itemOfInterest.Для объектов с пользовательской логикой isEqual: они могут возвращать разные результаты.Это означает, что решение 2 может быть немного быстрее для неосновных сборов данных, но это потому, что вы на самом деле тестируете другое, а не из-за перечисления объектов.(На самом деле это верно только для небольших коллекций; см. Ниже.)

Почему вы считаете, что в решении 1 используется -objectEnumerator?

Как указывает @James Raybould, вам обычно следуетНе пытайтесь переписать встроенные методы из соображений производительности.Если бы isEqual: версия Solution 2 была быстрее, чем Solution 1, не думаете ли вы, что Apple реализовала бы -containsObject: с использованием кода в решении 2?

В действительности, базовый CFSet реализованкак хэш, так что проверка на наличие содержимого является логарифмической, а не линейной.Вообще говоря, для больших множеств с разумными хэш-функциями решение 1 будет быстрее.Смотрите код для этого в CFSet.c .Ищите CFSetContainsValue().Конечно, реализация CFSet не обязательно останется прежней, но это полезно для понимания того, как проблемы с производительностью обычно решаются в Какао.

5 голосов
/ 18 марта 2011

Я бы всегда выбрал вариант 1.

Более лаконично, я могу точно сказать, что вы пытаетесь сделать с кодом, и есть вероятность, что в объекте containsObject есть несколько изящных оптимизаций.

...