Перечисление: Обход элементов коллекции

Cocoa

Cocoa содержит три основных способа перечисления содержимого коллекции. К ним относятся быстрое перечисление и блочное перечисление. Существует также NSEnumerator класс, хотя в целом был замещен быстрым перечислением.

Быстрое перечисление

Быстрое перечисление является предпочтительным методом перечисления содержимого коллекции, поскольку оно обеспечивает следующие преимущества:

  • Перечисление является более эффективным, чем использование NSEnumerator напрямую.
  • Синтаксис краток
  • Перечислитель вызывает исключение, если вы измените коллекции при перечислении.
  • Вы можете выполнять несколько перечислений одновременно.

Поведение для быстрого перечисления немного отличается в зависимости от типа коллекции. Массивы и наборы перечисляют их содержимое, а словари перечисляют свои ключи. NSIndexSet и NSIndexPath не поддерживают быстрое перечисление. Вы можете использовать быстрое перечисление с коллекцией объектов, как показано в листинге 1.

Листинг 1 Использование быстрого перечисления со словарем

for (NSString *element in someArray) {
   NSLog(@"element: %@", element);
}

NSString *key;
for(key in someDictionary){
   NSLog(@"Key: %@, Value %@", key, [someDictionary objectForKey: key]);
}

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

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

Листинг 2 перечисление массива на основе блока

NSArray *anArray=[NSArray arrayWithObjects:@"A", @"B", @"D",@"M",nil];
NSString *string=@"c";

[anArray enumerateObjectsUsingBlock:^(id obj, NSUInteger index, BOOL *stop){
     if([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame){
          NSLog(@"Object Found: %@ at index: %i",obj, index);
          *stop=YES;
     }
} ];

Для объекта NSSet, вы можете использовать код подобный, показанному в листинге 3.

Листинг 3 перечисления набора на основе блока

NSSet *aSet=[NSSet setWithObjects: @"X", @"Y", @"Z", @"Pi", nil];
NSString *aString=@"z";

[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop){
     if([obj localizedCaseInsensitiveCompare:aString]==NSOrderedSame){
          NSLog(@"Object Found: %@", obj);
          *stop=YES;
     }
} ];

Для перечисления NSArray, параметр index полезен для одновременного перечисления. Без этого параметра, единственный способ получить доступ к индексу был бы использованием метода indexOfObject:, который является неэффективным. stop параметр важен для производительности, так как он позволяет остановить перечисление раньше, на основе некоторого условия, определяемого в пределах блока. Методы перечисления на основе блока в других коллекциях, немного отличаются по названию.

Использование перечислителя

NSEnumerator простой абстрактный класс, подклассы перечисляют коллекции других объектов. Коллекции объектов, таких как массивы, множества, словари, обеспечивают специальные NSEnumerator объекты, с которыми NSEnumerator перечисляет их содержимое. Вы отправляете nextObject, чтобы вновь созданный объект NSEnumerator возвращал следующий объект в оригинальной коллекции. Когда коллекция будет исчерпана, то возвращается nil. Вы не можете "сбросить" перечислитель после того, как он исчерпал свои коллекции. Для перечисления коллекции, вы должны создать новый перечислитель.

Классы коллекций , такие как NSArray, NSSet и NSDictionary включают методы, которые возвращают Перечислитель соответствующего типа коллекции. Например, NSArray имеет два метода, которые возвращают объект NSEnumerator: objectEnumerator и reverseObjectEnumerator. Класс NSDictionary также имеет два метода, которые возвращают объект NSEnumerator: keyEnumerator и objectEnumerator. Эти методы позволяют перечислить содержимое NSDictionary объект по ключу или по значению, соответственно.

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

Листинг 4 Перечисление словаря и удаление объектов

NSMutableDictionary *myMutableDictionary = ... ;
NSMutableArray *keysToDeleteArray =
    [NSMutableArray arrayWithCapacity:[myMutableDictionary count]];
NSString *aKey;
NSEnumerator *keyEnumerator = [myMutableDictionary keyEnumerator];
while (aKey = [keyEnumerator nextObject])
{
    if ( /* Проверка критериев для ключа или значения */ ) {
        [keysToDeleteArray addObject:aKey];
    }
}
[myMutableDictionary removeObjectsForKeys:keysToDeleteArray];
close

Блок объект Читать более подробно

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

Объявление блока

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

float (^aBlock)(const int*, int, float);

Создание блока

Вы можете использовать вставки (^) оператора для обозначения начала и точку с запятой, чтобы обозначить конец блока выражения. В следующем примере объявляется простой блок и относит его к ранее объявленной блоком переменной (oneFrom):

int (^oneFrom)(int);

oneFrom = ^(int anInt) {
    return anInt - 1;
};

Закрытие точкой с запятой требуется в качестве стандарта C конца линии маркера.

Если вы явно не объявляете возвращаемое значение выражения блока, оно может автоматически выводится из содержимого блока.

Блок-изменяемые переменные

Вы можете использовать __block модификатор хранения c переменными, объявленными локально с вложениями лексической области, чтобы обозначить, что такие переменные должны быть предоставлены по ссылке в блоке и являются изменяемыми. Любые изменения находят свое отражение в окружающей лексической области, в том числе любых других блоков, определенных в той же ограждающей лексической области.

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

Если вы объявляете блок в качестве переменной, вы можете использовать его так же, как функцию. В следующем примере печатается 9.

printf("%d\n", oneFrom(10));

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

В следующем примере определяется, содержит ли объект NSSet слово, указанное в локальной переменной и задает значение другой локальной переменной (found) в YES (и прекращает поиск), если он выполняется. В этом примере, found объявлена ​​как переменная __block.

__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string = @"gamma";

[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
    if ([obj localizedCaseInsensitiveCompare:string] == NSOrderedSame) {
        *stop = YES;
        found = YES;
    }
}];

// В этой точке, found == YES

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

Операции сравнения

Одной из наиболее распространенных операций, которые вы выполняете с блоками в среде Cocoa сравнение двух объектов, сортировка содержимого массива. Среда выполнения Objective-C определяет блок типа NSComparator для использования этих сравнений.

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