Cocoa NSArray/NSSet: -makeObjectsPerformSelector: против быстрого перечисления

Я хочу выполнить одно и то же действие над несколькими объектами, хранящимися в NSSet.

Моя первая попытка заключалась в использовании быстрого перечисления:

for (id item in mySetOfObjects)
    [item action];

который работает очень хорошо. Тогда я подумал:

[mySetOfObjects makeObjectsPerformSelector:@selector(action)];

И теперь я не знаю, что является лучшим выбором. Насколько я понимаю, эти два решения эквивалентны. Но существуют ли аргументы для предпочтения одного решения над другим?

Ответы

Ответ 1

Я бы поспорил с использованием makeObjectsPerformSelector, поскольку он позволяет объекту NSSet позаботиться о его собственной индексации, циклеровании и отправке сообщений. Люди, которые написали код NSSet, скорее всего, узнают лучший способ реализовать этот конкретный цикл.

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

Эта тема кратко упоминается в документе Apple Code Speed ​​Performance в разделе "Развертывание циклов".

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

Ответ 2

Мне тоже был представлен этот вопрос. Я нашел в документах Apple "Темы программирования коллекций" в разделе "Наборы: неупорядоченные коллекции объектов" следующее:

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

Это заставляет меня думать, что Fast Enumeration по-прежнему является наиболее эффективным средством для этого приложения.

Ответ 3

Я бы не использовал makeObjectsPerformSelector по той простой причине, что это тот тип звонка, который вы часто не видите. Вот почему, например, мне нужно добавить код отладки, когда перечисляется массив, и вы действительно не можете сделать это с помощью makeObjectsPerformSelector, если вы не измените, как работает код в режиме Release, что реально нет.

for (id item in mySetOfObjects)
{
    #if MY_DEBUG_BUILD
    if ([item isAllMessedUp])
        NSLog(@"we found that wily bug that has been haunting us"); 
    #endif

    [item action];
}

- Том

Ответ 4

makeObjectsPerformSelector: может быть немного быстрее, но я сомневаюсь, что будет какая-то практическая разница в 99% случаев. Это немного более кратким и читаемым, хотя я бы использовал его по этой причине.

Ответ 5

Если чистая скорость - единственная проблема (т.е. вы создаете какой-то движок рендеринга, где каждый крошечный процессорный цикл подсчитывается), самый быстрый способ итерации по любому из объектов NSCollection (как iOS 5.0 ~ 6.0) - это различные методы "enumerateObjectsUsingBlock". Я понятия не имею, почему это так, но я тестировал его, и это похоже на то, что...

Я написал небольшой тест, создающий коллекции из сотен тысяч объектов, каждый из которых имеет метод, который суммирует простой массив int. Каждая из этих коллекций была вынуждена выполнять различные типы итераций (для цикла, быстрого перечисления, makeObjectsPerformSelector и enumerateObjectsUsingBlock) в миллионы раз, и почти в каждом случае методы "enumerateObjectsUsingBlock" быстро выигрывали в ходе тестов.

Единственное время, когда это было неверно, - это когда память начала заполняться (когда я начал запускать ее с миллионами объектов), после чего она начала терять "makeObjectsPerformSelector".

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