В iOS 4 Apple представила блоки для iOS. Проще говоря, блок — это тип переменной, в которой хранится исполняемый код. Этот быстрый совет предоставит краткий общий обзор блоков и научит их использовать для перечисления объектов.
Обзор блоков
Как программист, вы привыкли к таким типам данных, как String
, который является типом переменной для текста. Нам также известны такие вещи, как int
, float
и double
, которые являются типами переменных для хранения числовых значений. Наконец, мы знаем о таких вещах, как NSObject
, который является классом базового уровня, который позволяет нам объединять различные коллекции как типов данных, так и методов (или функций). Блоки вносят в таблицу что-то значительно другое, предоставляя тип данных для хранения исполняемого кода.
Если это не имеет смысла для вас, не волнуйтесь: блоки могут быть жесткими. Их цель и функции становятся намного более ясными после просмотра примеров их использования. Одним из наиболее популярных типов шаблонов, в которых используются блоки, является предоставление «блоков завершения» для объектов, которые выполняют какую-то асинхронную операцию. Ниже приведен пример подписи метода, предоставленной в моем UIView, которая использует прием блока завершения от пользователя:
1
|
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
|
Этот последний параметр завершения есть блок. Как и во всех методах Objective-C, метод имеет именованные параметры. Анимации и параметр завершения являются блоками. Вы можете сказать из-за символа ^. Этот символ используется для определения блока. В то время как тип переменной блока содержит исполняемый код, сам тип блока должен быть определен. Как и при написании кода в методе, блоки могут предоставлять объекты в код, который он содержит. Здесь мы видим блок анимации, определенный первым:
1
|
animations:(void (^)(void))animations
|
Мы можем видеть, что этот блок возвращает void и предоставляет void. В этом блоке вы изменили бы все свойства анимации UIKit, которые вы хотели бы. Блок завершения немного отличается.
1
|
completion:(void (^)(BOOL finished))completion
|
В этом блоке мы все еще можем видеть, что мы будем возвращать void. Однако на этот раз наш блок будет возвращать завершающую BOOL, чтобы мы могли использовать ее, если захотим. Реализуя этот метод в XCode, IDE выполняет большую часть работы, чтобы избавиться от несколько резкого синтаксиса блоков. После перехода на вкладку параметра для блока при вызове метода, в Xcode 4 и выше, нажмите enter, и Xcode создаст схему блока для вас.
Очевидно, вы могли бы представить предоставление этой функциональности через шаблон делегата, но сейчас здесь есть блоки, которые обеспечивают большую гибкость и станут более популярными только в будущих версиях SDK.
Образец кода
Загрузите образец кода для этого проекта на GitHub . Поиграйте с кодом самостоятельно, следуя инструкциям этого урока.
перечисление
Итак, блоки потрясающие. Вы увидите их как разработчика iOS. Одна очень распространенная операция, которую можно выполнить с блоками, — это перечисление. Есть три основных объекта Foundation, которые вы бы хотели перечислить.
- NSArray / NSMutableArray: упорядоченная коллекция объектов
- NSDictionary / NSMutableDictionary: неупорядоченная коллекция объектов значения ключа.
- NSSet / NSMutableSet: неупорядоченная коллекция уникальных объектов
NSDictionaries
Каждый из этих объектов имеет различные логические правила, применяемые для достижения различных функций. В результате, перечисление через каждого немного отличается. Мы рассмотрим, как iOS 4 и выше предоставляет возможности перечисления блоков, чтобы вы могли ими воспользоваться. Давайте сначала начнем с определения образца словаря для использования.
1
2
3
4
5
6
7
|
NSDictionary *sampleDictionary = [NSDictionary dictionaryWithObjectsAndKeys:@»Hello World», @»Test String 1″,
@»How are you?», @»Test String 2″,
@»I am fine.», @»Test String 3″,
@»Let’s have lunch!», @»Test String 4″,
@»Open the pod bay doors HAL.», @»Test String 5″,
@»I am fine.», @»Test String 6″,
nil];
|
Отлично. Поэтому, когда мы перечисляем словарь, нам нужно предоставить каждый ключ и значение и, надеюсь, иметь возможность выйти из перечисления, если мы выберем. Поскольку словари не упорядочены, нам не будет предоставлен индекс. Это именно то, что мы находим, глядя на новый блочный метод перечисления для словарей.
1
|
— (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block
|
В этом случае в блок, который мы предоставляем, будет введен указатель key, obj и stop BOOL. Это должно дать нам все инструменты, которые мы должны перечислить через этот словарь. Давайте перечислим все ключи и значения и распечатаем их.
1
2
3
4
|
NSLog(@»Printing my dictionary out by enumerating:»);
[sampleDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(@»\tKey: %@ Value: %@», key, obj);
}];
|
И вот вывод:
1
2
3
4
5
6
7
|
2011-11-24 07:42:35.562 MobileTutsBlockEnumerationExample[42652:f803] Printing my dictionary out by enumerating:
2011-11-24 07:42:35.564 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 4 Value: Let’s have lunch!
2011-11-24 07:42:35.565 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 2 Value: How are you?
2011-11-24 07:42:35.565 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 5 Value: Open the pod bay doors HAL.
2011-11-24 07:42:35.566 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 3 Value: I am fine.
2011-11-24 07:42:35.567 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 1 Value: Hello World
2011-11-24 07:42:35.567 MobileTutsBlockEnumerationExample[42652:f803] Key: Test String 6 Value: I am fine.
|
NSArrays
Большой! Перечисление словаря было простым. Давайте проверим перечисление массива сейчас. Давайте возьмем массив, возвращенный методом allKeys в нашем примере словаря, и сначала поработаем с ним.
1
|
NSArray *sampleArray = [sampleDictionary allKeys];
|
Массив — это упорядоченная коллекция объектов. Поэтому при перечислении через массив имело бы смысл предоставить объект, его индекс и способ выйти из перечисления. Давайте посмотрим на подпись метода экземпляра NSArray для перечисления.
1
|
— (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block
|
Похоже, именно то, что нам нужно. Наш блок содержит объект, его индекс и указатель Stop BOOL для исключения перечисления. Этот специфический метод перечисления также позволяет нам передавать NSEnumerationOption. Чтобы продемонстрировать это, я собираюсь передать опцию, чтобы сделать перечисление в обратном порядке. Имея это в виду, мы должны видеть распечатки от самого высокого индекса до самого низкого. Давайте перечислим этот массив и распечатаем все его объекты вместе с их экземплярами.
1
2
3
4
|
NSLog(@»Printing my array out by enumerating:»);
[sampleArray enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(@»\tValue: %@ Index: %d», obj, idx);
}];
|
И вот вывод:
1
2
3
4
5
6
7
|
2011-11-24 07:42:35.568 MobileTutsBlockEnumerationExample[42652:f803] Printing my array out by enumerating:
2011-11-24 07:42:35.568 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 6 Index: 5
2011-11-24 07:42:35.569 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 1 Index: 4
2011-11-24 07:42:35.570 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 3 Index: 3
2011-11-24 07:42:35.571 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 5 Index: 2
2011-11-24 07:42:35.576 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 2 Index: 1
2011-11-24 07:42:35.577 MobileTutsBlockEnumerationExample[42652:f803] Value: Test String 4 Index: 0
|
NSSets
Хорошо, два вниз с одним, чтобы пойти. Наборы NSS похожи на массивы, за исключением того, что они неупорядочены и содержат уникальный набор объектов. Это означает, что вы не можете иметь более одного объекта в коллекции. В нашем оригинальном словаре было два разных «У меня все хорошо». ценности. Итак, давайте создадим набор из провайдера массива allValues в нашем словаре.
1
|
NSSet *sampleSet = [NSSet setWithArray:[sampleDictionary allValues]];
|
Теперь, когда у нас есть набор для работы, мы должны перечислить его. Поскольку набор представляет собой неупорядоченную коллекцию уникальных объектов, будет иметь смысл, что наш блок перечисления будет снабжен только объектом и способом, позволяющим нам избежать перечисления.
1
|
— (void)enumerateObjectsUsingBlock:(void (^)(id obj, BOOL *stop))block
|
Выглядит идеально. Давайте перечислим множество и распечатаем значения. Помните, у нас должно быть напечатано только 5 значений, потому что набор содержит только уникальные значения, и у нас было повторное значение в нашем словаре.
И вот вывод:
1
2
3
4
5
6
|
2011-11-24 07:42:35.577 MobileTutsBlockEnumerationExample[42652:f803] Printing my set out by enumerating:
2011-11-24 07:42:35.578 MobileTutsBlockEnumerationExample[42652:f803] Value: How are you?
2011-11-24 07:42:35.579 MobileTutsBlockEnumerationExample[42652:f803] Value: Open the pod bay doors HAL.
2011-11-24 07:42:35.579 MobileTutsBlockEnumerationExample[42652:f803] Value: Let’s have lunch!
2011-11-24 07:42:35.580 MobileTutsBlockEnumerationExample[42652:f803] Value: I am fine.
2011-11-24 07:42:35.581 MobileTutsBlockEnumerationExample[42652:f803] Value: Hello World
|
Экранирование Перечисления
Так что все это выглядит довольно просто в использовании. Но как насчет этого BOOL * указателя остановки, который мы продолжаем видеть. Это флаг, который вы можете установить, чтобы остановить ваше перечисление. Перечисление на основе блоков проверяет этот флаг в каждом цикле перед продолжением. Для последнего примера давайте снова пройдемся по нашему массиву. На этот раз давайте не будем делать это задом наперед и остановимся, как только мы доберемся до индекса 1. Мы выполним это с помощью:
1
2
3
4
5
6
7
8
9
|
NSLog(@»Printing my array out by enumerating and stopping at index 1:»);
[sampleArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if(idx == 1) {
*stop = YES;
}
NSLog(@»\tValue: %@ Index: %d», obj, idx);
}];
|
Следует отметить, что когда вы установите флаг в значение true, блок будет выполняться до самого дна. Перечисление сбрасывается только перед началом следующего. Вы можете видеть это в выходных данных ниже, потому что, хотя мы устанавливаем наш флаг остановки перед NSLog, мы все равно видим журнал для индекса 1. Вот результат:
1
2
3
|
2011-11-24 09:36:01.989 MobileTutsBlockEnumerationExample[43039:f803] Printing my array out by enumerating and stopping at index 1:
2011-11-24 09:36:01.989 MobileTutsBlockEnumerationExample[43039:f803] Value: Test String 4 Index: 0
2011-11-24 09:36:01.990 MobileTutsBlockEnumerationExample[43039:f803] Value: Test String 2 Index: 1
|