Короткое практическое руководство по блокам
Блоки являются мощной функцией языка C, которая является частью разработки приложений Какао. Они подобны «закрытиям» и «лямбдам», которые можно найти на языках сценариев и языках программирования, таких как Ruby, Python и Lisp. Несмотря на то, что синтаксис и сведения о ресурсе хранения блоков могли бы на первый взгляд казаться загадочными, Вы найдете, что фактически довольно просто включить блоки в код Ваших проектов.
Следующее обсуждение дает высокоуровневое исследование функций блоков и иллюстрирует типичные пути, которыми они используются. Обратитесь к Блокам, Программируя Темы для категорического описания блоков.
Содержание:
Почему использование блокирует?
Блоки являются объектами, инкапсулирующими единицу работы — или, в менее абстрактных понятиях, сегменте кода — который может быть выполнен в любое время. Они - чрезвычайно переносимые и анонимные функции, в которых можно передать как параметры методов и функций, или это может быть возвращено из методов и функций. Сами блоки имеют введенный список аргументов и, возможно, вывели или объявили возвращенный тип. Можно также присвоить блок переменной и затем вызвать его так же, как Вы были бы функция.
Символ вставки (^) используется в качестве синтаксического маркера для блоков. Например, следующий код объявляет основную переменную, берущую два целых числа и возвращающую целочисленное значение. Это обеспечивает список параметров после второго каре и кода реализации в фигурных скобках, и присваивает их Multiply
переменная:
int (^Multiply)(int, int) = ^(int num1, int num2) { |
return num1 * num2; |
}; |
int result = Multiply(7, 4); // Result is 28. |
Как аргументы метода или аргументы функции, блоки являются типом обратного вызова и могли считаться формой делегации, ограниченной методом или функцией. Путем передачи в блоке код вызова может настроить поведение метода или функции. Когда вызвано, метод или функция выполняют некоторую работу и, в надлежащие моменты, перезванивают к коду вызова — через блок — чтобы запросить дополнительную информацию или получить специализированное поведение из него.
Преимущество блоков как функция и параметры метода состоит в том, что они позволяют вызывающей стороне обеспечить код обратного вызова при вызове. Поскольку этот код не должен быть реализован в отдельном методе или функции, Ваш код реализации может быть более простым и легким для понимания. Возьмите уведомления о NSNotification
разнообразие как пример. В «традиционном» подходе объект добавляет себя как наблюдатель уведомления и затем реализует отдельный метод (идентифицированный селектором в addObserver:..
метод) для обработки уведомления:
- (void)viewDidLoad { |
[super viewDidLoad]; |
[[NSNotificationCenter defaultCenter] addObserver:self |
selector:@selector(keyboardWillShow:) |
name:UIKeyboardWillShowNotification object:nil]; |
} |
- (void)keyboardWillShow:(NSNotification *)notification { |
// Notification-handling code goes here. |
} |
С addObserverForName:object:queue:usingBlock:
метод можно консолидировать обрабатывающий уведомление код с вызовом метода:
- (void)viewDidLoad { |
[super viewDidLoad]; |
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification |
object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { |
// Notification-handling code goes here. |
}]; |
} |
Еще более ценное преимущество блоков по другим формам обратного вызова состоит в том, что блок совместно использует данные в локальном лексическом контексте. Если Вы реализуете метод, и в том методе определяют блок, блок имеет доступ к локальным переменным и параметрам метода (включая переменные штабеля), а также к функциям и глобальным переменным, включая переменные экземпляра. Если Вы объявляете переменную с, этот доступ только для чтения по умолчанию, но __block
модификатор, можно изменить его значение в блоке. Даже после метода или функции, включающей блок, возвратился, и его локальный объем уничтожается, локальные переменные сохраняются как часть блочного объекта, пока существует ссылка на блок.
Блоки в системной платформе APIs
Одна очевидная мотивация для использования блоков - то, что растущее число методов и функции системных платформ берут блоки в качестве параметров. Можно различить приблизительно полдюжину вариантов использования для блоков в методах платформы:
Обработчики завершения
Обработчики уведомления
Обработчики ошибок
Перечисление
Анимация представления и переходы
Сортировка
Следующие разделы описывают каждый из этих случаев. Но прежде чем мы добираемся, к которому, вот быстрый обзор интерпретации блочных объявлений в методах платформы. Рассмотрите следующий метод NSSet
класс:
- (NSSet *)objectsPassingTest:(BOOL (^)(id obj, BOOL *stop))predicate |
Блочное объявление указывает, что метод передает в блок (для каждого перечислимого элемента) объект с динамическим контролем типов и булево значение ссылкой; блок возвращает булево значение. (Для чего эти параметры и возвращаемое значение фактически, покрыты Перечислением.) При указании блока, начните с каре (^
) и заключенный в скобки список аргументов; следуйте за этим с самим блочным кодом, включенный фигурными скобками.
[mySet objectsPassingTest:^(id obj, BOOL *stop) { |
// Code goes here: Return YES if obj passes the test and NO if obj does not pass the test. |
}]; |
Завершение и обработчики ошибок
Обработчики завершения являются обратными вызовами, позволяющими клиенту выполнять некоторое действие, когда метод платформы или функция выполняют свою задачу. Часто клиент использует обработчик завершения для свободного состояния, или обновите пользовательский интерфейс. Несколько методов платформы позволяют Вам реализовать обработчики завершения как блоки (вместо, скажем, методов делегации или обработчиков уведомления).
UIView
класс имеет несколько методов класса для анимаций и переходов представления, имеющих блочные параметры обработчика завершения. (Анимация представления и Переходы дают обзор этих методов.) Пример в Перечислении 1-1 показывает реализацию animateWithDuration:animations:completion:
метод. Обработчик завершения в этом примере сбрасывает анимированное представление назад к его исходному расположению и прозрачности (альфа) значение спустя несколько секунд после того, как закончится анимация.
- (IBAction)animateView:(id)sender { |
CGRect cacheFrame = self.imageView.frame; |
[UIView animateWithDuration:1.5 animations:^{ |
CGRect newFrame = self.imageView.frame; |
newFrame.origin.y = newFrame.origin.y + 150.0; |
self.imageView.frame = newFrame; |
self.imageView.alpha = 0.2; |
} |
completion:^ (BOOL finished) { |
if (finished) { |
// Revert image view to original. |
self.imageView.frame = cacheFrame; |
self.imageView.alpha = 1.0; |
} |
}]; |
} |
Некоторые методы платформы имеют обработчики ошибок, которые являются блочными параметрами, подобными обработчикам завершения. Метод вызывает их (и передает в NSError
объект), когда это не может выполнить свою задачу из-за некоторого состояния ошибки. Вы обычно реализуете обработчик ошибок для информирования пользователя об ошибке.
Обработчики уведомления
NSNotificationCenter
метод addObserverForName:object:queue:usingBlock:
позволяет Вам реализовать обработчик для уведомления в точке, Вы устанавливаете наблюдение. Перечисление 1-2 иллюстрирует, как Вы могли бы вызвать этот метод, определив блочный обработчик для уведомления. Как с методами обработчиков уведомления, NSNotification
объект передается в. Метод также берет NSOperationQueue
экземпляр, таким образом, Ваше приложение может указать контекст выполнения, на котором можно выполнить блочный обработчик.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { |
opQ = [[NSOperationQueue alloc] init]; |
[[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted" |
object:nil queue:opQ |
usingBlock:^(NSNotification *notif) { |
NSNumber *theNum = [notif.userInfo objectForKey:@"NumberOfItemsProcessed"]; |
NSLog(@"Number of items processed: %i", [theNum intValue]); |
}]; |
} |
Перечисление
Классы набора платформы Основы —NSArray
, NSDictionary
, NSSet
, и NSIndexSet
— объявите методы, выполняющие перечисление определенного типа набора и указывающие блоки для клиентов к коду поставки, чтобы обработать или протестировать каждый перечислимый элемент. Другими словами, методы выполняют эквивалент конструкции быстрого перечисления:
for (id item in collection) { |
// Code to operate on each item in turn. |
} |
Существует две общих формы методов перечисления, берущих блоки. Первыми являются методы, имена которых начинаются enumerate
и не возвращайте значение. Блок для этих методов выполняет некоторую работу над каждым перечислимым элементом. Блочным параметром второго типа метода предшествуют passingTest
; этот вид метода возвращает целое число или NSIndexSet
объект. Блок для этих методов выполняет тест на каждом перечислимом элементе и возвратах YES
true
если элемент проходит тест. Целочисленный или индексный набор идентифицирует объект или объекты в исходном наборе, прошедшем тест.
Код в Перечислении 1-3 вызывает NSArray
метод каждого из этих типов. Блок первого метода (“передающий тест” метод) возвраты YES
true
для каждой строки в массиве, имеющем определенный префикс. Код впоследствии создает временный массив с помощью индексного набора, возвращенного из метода. Блок второго метода отрезает префикс от каждой строки во временном массиве и добавляет его к новому массиву.
NSString *area = @"Europe"; |
NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames]; |
NSMutableArray *areaArray = [NSMutableArray arrayWithCapacity:1]; |
NSIndexSet *areaIndexes = [timeZoneNames indexesOfObjectsWithOptions:NSEnumerationConcurrent |
passingTest:^(id obj, NSUInteger idx, BOOL *stop) { |
NSString *tmpStr = (NSString *)obj; |
return [tmpStr hasPrefix:area]; |
}]; |
NSArray *tmpArray = [timeZoneNames objectsAtIndexes:areaIndexes]; |
[tmpArray enumerateObjectsWithOptions:NSEnumerationConcurrent|NSEnumerationReverse |
usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { |
[areaArray addObject:[obj substringFromIndex:[area length]+1]]; |
}]; |
NSLog(@"Cities in %@ time zone:%@", area, areaArray); |
stop
параметр в каждом из этих методов перечисления (который не используется в примере) позволяет блоку передавать YES
true
ссылкой назад на метод, чтобы сказать ему выходить из перечисления. Вы делаете это, когда Вы просто хотите найти первый элемент в наборе, соответствующем некоторые критерии.
Даже при том, что это не представляет набор, NSString
класс также имеет два метода с блочными параметрами, имена которых начинаются enumerate
: enumerateSubstringsInRange:options:usingBlock:
и enumerateLinesUsingBlock:
. Первый метод перечисляет строку единицей текста указанной гранулярности (строка, абзац, слово, предложение, и т.д.); второй метод перечисляет его с методической точностью только. Перечисление 1-4 иллюстрирует, как Вы могли бы использовать первый метод.
NSString *musician = @"Beatles"; |
NSString *musicDates = [NSString stringWithContentsOfFile: |
@"/usr/share/calendar/calendar.music" |
encoding:NSASCIIStringEncoding error:NULL]; |
[musicDates enumerateSubstringsInRange:NSMakeRange(0, [musicDates length]-1) |
options:NSStringEnumerationByLines |
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { |
NSRange found = [substring rangeOfString:musician]; |
if (found.location != NSNotFound) { |
NSLog(@"%@", substring); |
} |
}]; |
Анимация представления и переходы
UIView
класс в iOS 4.0 представил несколько методов класса для переходов анимации и представления, берущих блоки. Блочные параметры являются двумя видами (не, все методы берут оба вида):
Блоки, изменяющие свойства представления, которые будут анимированы
Обработчики завершения
Перечисление 1-5 показывает вызов animateWithDuration:animations:completion:
, метод, имеющий оба вида блочных параметров. В этом примере анимация заставляет представление исчезнуть (путем указания нулевой альфы), и обработчик завершения удаляет его из своего суперпредставления.
[UIView animateWithDuration:0.2 animations:^{ |
view.alpha = 0.0; |
} completion:^(BOOL finished){ |
[view removeFromSuperview]; |
}]; |
Прочее. UIView
методы класса выполняют переходы между двумя представлениями, включая зеркальные отражения и завихрения. Вызов в качестве примера transitionWithView:duration:options:animations:completion:
в Перечислении 1-6 анимирует замену подпредставления как оставленный зеркальному отражению переход. (Это не реализует обработчик завершения.)
[UIView transitionWithView:containerView duration:0.2 |
options:UIViewAnimationOptionTransitionFlipFromLeft |
animations:^{ |
[fromView removeFromSuperview]; |
[containerView addSubview:toView] |
} |
completion:NULL]; |
Сортировка
Платформа Основы объявляет NSComparator
введите для сравнения двух элементов:
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2); |
NSComparator
тип блока, берущий два объекта и возвращающийся NSComparisonResult
значение. Это - параметр в методах NSSortDescriptor
, NSArray
, и NSDictionary
и используется экземплярами тех классов для сортировки. Перечисление 1-7 дает пример своего использования.
NSArray *stringsArray = [NSArray arrayWithObjects: |
@"string 1", |
@"String 21", |
@"string 12", |
@"String 11", |
@"String 02", nil]; |
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch | |
NSWidthInsensitiveSearch | NSForcedOrderingSearch; |
NSLocale *currentLocale = [NSLocale currentLocale]; |
NSComparator finderSort = ^(id string1, id string2) { |
NSRange string1Range = NSMakeRange(0, [string1 length]); |
return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale]; |
}; |
NSLog(@"finderSort: %@", [stringsArray sortedArrayUsingComparator:finderSort]); |
Этот пример взят от Блоков, Программируя Темы.
Блоки и параллелизм
Блоки являются переносимыми и анонимными объектами, инкапсулирующими единицу работы, которая может быть выполнена асинхронно в более позднее время. Из-за этого существенного факта блоки являются центральной функцией и Grand Central Dispatch (GCD) и NSOperationQueue
класс, две рекомендуемых технологии для параллельной обработки.
Две центральных функции GCD,
dispatch_sync(3) OS X Developer Tools Manual Page
(для синхронной диспетчеризации) илиdispatch_async(3) OS X Developer Tools Manual Page
(для асинхронной диспетчеризации), берут в качестве их вторых параметров блок.NSOperationQueue
объект, планирующий задачи, которые будут выполняться одновременно или в порядке, определенном отношениями зависимости. Задачи представленыNSOperation
объекты, часто использующие блоки для реализации их задач.
Для больше о GCD, NSOperationQueue
, и NSOperation
, см. Руководство по программированию Параллелизма.
Copyright © 2015 Apple Inc Все права защищены. Условия использования | Политика конфиденциальности | обновленный: 15.08.2010