Обсуждение

Обсуждение

Сначала научимся работать с переменными, которые являются локальными для реализаций двух блоковых объектов. Один из этих блоковых объектов будет встраиваемым, а другой — независимым:

void (^independentBlockObject)(void) = ^(void){

NSInteger localInteger = 10;

NSLog(@"local integer = %ld", (long)localInteger);

localInteger = 20;

NSLog(@"local integer = %ld", (long)localInteger);

};

При активизации этого блокового объекта те значения, которые мы присваиваем, выводятся в окне консоли:

local integer = 10

local integer = 20

Пока все несложно. Теперь рассмотрим встраиваемые блоковые объекты и переменные, которые являются для них локальными:

— (void) simpleMethod{

NSUInteger outsideVariable = 10;

NSMutableArray *array = [[NSMutableArray alloc]

initWithObjects:@"obj1",

@"obj2", nil];

[array sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) {

NSUInteger insideVariable = 20;

NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable);

NSLog(@"Inside variable = %lu", (unsigned long)insideVariable);

/* Возвращаем значение для блокового объекта. */

return NSOrderedSame;

}];

}

Метод экземпляра sortUsingComparator:, относящийся к классу NSMutableArray, пытается сортировать изменяемый массив. Цель кода, приведенного в данном примере, — просто продемонстрировать использование локальных переменных. Можно и не задаваться тем, что именно делает этот метод.

Блоковый объект может считывать информацию и записывать данные в собственную локальную переменную insideVariable. При этом по умолчанию блоковый объект имеет доступ только для чтения к переменной outsideVariable. Чтобы блоковый объект мог записывать информацию в outsideVariable, нужно поставить перед outsideVariable префикс __block, указывающий соответствующий тип хранения:

— (void) simpleMethod{

__block NSUInteger outsideVariable = 10;

NSMutableArray *array = [[NSMutableArray alloc]

initWithObjects:@"obj1",

@"obj2", nil];

[array sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) {

NSUInteger insideVariable = 20;

outsideVariable = 30;

NSLog(@"Outside variable = %lu", (unsigned long)outsideVariable);

NSLog(@"Inside variable = %lu", (unsigned long)insideVariable);

/* Возвращаем значение для блокового объекта. */

return NSOrderedSame;

}];

}

Доступ к self во встраиваемых блоковых объектах не вызывает никаких проблем, пока self определяется в лексической области видимости, внутри которой создается встраиваемый блоковый объект. Например, в данной ситуации блоковый объект сможет получить доступ к self, поскольку метод simpleMethod является методом экземпляра класса языка Objective-C:

— (void) simpleMethod{

NSMutableArray *array = [[NSMutableArray alloc]

initWithObjects:@"obj1",

@"obj2", nil];

[array sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) {

NSLog(@"self = %@", self);

/* Возвращаем значение для блокового объекта. */

return NSOrderedSame;

}];

}

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

void (^incorrectBlockObject)(void) = ^{

NSLog(@"self = %@", self); /* self здесь не определен. */

};

Если вы хотите получить доступ к self в независимом блоковом объекте, просто передайте объект, представляемый self, вашему блоковому объекту в качестве параметра:

void (^correctBlockObject)(id) = ^(id self){

NSLog(@"self = %@", self);

};

— (void) callCorrectBlockObject{

correctBlockObject(self);

}

Этому параметру не обязательно присваивать имя self. Ему можно дать любое имя. Тем не менее если назвать этот параметр self, то можно будет просто собрать код блокового объекта позже и поместить его в реализацию метода на языке Objective-C. Не придется менять имя каждого экземпляра переменной на self, чтобы код был воспринят компилятором.

Рассмотрим объявленные свойства и посмотрим, как блоковые объекты могут получать к ним доступ. При работе со встраиваемыми блоковыми объектами можно применять точечную нотацию — она позволяет считывать информацию из объявленных свойств self или записывать в них данные. Допустим, например, что у нас в классе есть объявленное свойство типа NSString, которое называется stringProperty:

#import «AppDelegate.h»

@interface AppDelegate()

@property (nonatomic, copy) NSString *stringProperty;

@end

@implementation AppDelegate

Теперь не составляет труда получить доступ к этому свойству во встраиваемом блоковом объекте:

— (void) simpleMethod{

NSMutableArray *array = [[NSMutableArray alloc]

initWithObjects:@"obj1",

@"obj2", nil];

[array sortUsingComparator: ^NSComparisonResult(id obj1, id obj2) {

NSLog(@"self = %@", self);

self.stringProperty = @"Block Objects";

NSLog(@"String property = %@", self.stringProperty);

/* Возвращаем значение для блокового объекта. */

return NSOrderedSame;

}];

}

Но в независимом блоковом объекте нельзя использовать точечную нотацию для считывания объявленного свойства или записи информации в это свойство:

void (^correctBlockObject)(id) = ^(id self){

NSLog(@"self = %@", self);

/* Вместо этого используем метод-установщик */

self.stringProperty = @"Block Objects"; /* Ошибка времени компиляции */

/* Вместо этого используем метод-получатель. */

NSLog(@"self.stringProperty = %@",

self.stringProperty); /* Ошибка времени компиляции */

};

В данном сценарии будем пользоваться методом-установщиком и методом-получателем синтезированного свойства:

void (^correctBlockObject)(id) = ^(id self){

NSLog(@"self = %@", self);

/* Это будет работать нормально. */

[self setStringProperty:@"Block Objects"];

/* Это также будет работать нормально. */

NSLog(@"self.stringProperty = %@",

[self stringProperty]);

};

Когда дело касается встраиваемых блоковых объектов, необходимо учитывать лишь одно очень важное правило: встраиваемые блоковые объекты копируют значения для переменных в своей лексической области видимости. Если вы не понимаете, что это значит, — не волнуйтесь. Рассмотрим пример:

typedef void (^BlockWithNoParams)(void);

— (void) scopeTest{

NSUInteger integerValue = 10;

BlockWithNoParams myBlock = ^{

NSLog(@"Integer value inside the block = %lu",

(unsigned long)integerValue);

};

integerValue = 20;

/* Вызываем блок здесь после изменения

значения переменной integerValue. */

myBlock();

NSLog(@"Integer value outside the block = %lu",

(unsigned long)integerValue);

}

Мы определяем целочисленную локальную переменную и сначала присваиваем ей значение 10. Затем реализуем блоковый объект, но пока не вызываем его. После того как блоковый объект реализован, мы просто изменяем значение локальной переменной, которую затем (после того как мы его вызовем) попытается считать блоковый объект. Сразу после изменения значения локальной переменной на 20 вызываем блоковый объект. Логично предположить, что блоковый объект выведет для переменной на консоль значение 20, но этого не произойдет. Он выведет значение 10, как показано здесь:

Integer value inside the block = 10

Integer value outside the block = 20

Вот что здесь происходит. Блоковый объект сохраняет для себя копию переменной integerValue, доступную только для чтения, и делает это именно там, где реализуется блок. Напрашивается вопрос: почему же блоковый объект принимает доступное только для чтения значение переменной integerValue? Ответ прост, и мы уже дали его в этом разделе. Если у локальной переменной нет префикса __block, означающего соответствующий тип хранения, локальные переменные в лексической области видимости блокового объекта просто передаются блоковому объекту как переменные, доступные только для чтения. Следовательно, чтобы изменить это поведение, мы могли бы изменить реализацию метода scopeTest и сопроводить переменную integerValue префиксом __block, указывающим тип хранения. Это делается так:

— (void) scopeTest{

__block NSUInteger integerValue = 10;

BlockWithNoParams myBlock = ^{

NSLog(@"Integer value inside the block = %lu",

(unsigned long)integerValue);

};

integerValue = 20;

/* Вызываем блок здесь после изменения

значения переменной integerValue. */

myBlock();

NSLog(@"Integer value outside the block = %lu",

(unsigned long)integerValue);

}

Теперь, если вывести на консоль результаты после вызова метода scopeTest, мы увидим следующее:

Integer value inside the block = 20

Integer value outside the block = 20

Итак, в данном разделе мы довольно подробно рассмотрели вопросы использования переменных с блоковыми объектами. Рекомендую вам написать несколько блоковых объектов и попытаться использовать в них переменные. Присваивайте им переменные, считывайте из них информацию, чтобы лучше разобраться с тем, как в блоковых объектах применяются переменные. Перечитайте этот раздел, если случайно забудете правила, регулирующие доступ к переменным в блоковых объектах.

Данный текст является ознакомительным фрагментом.



Поделитесь на страничке

Следующая глава >

Похожие главы из других книг:

Обсуждение

Из книги автора

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


Обсуждение

Из книги автора

Обсуждение Фреймворк Assets Library — удобный посредник между разработчиком и библиотекой фотографий. Как будет указано в разделе 13.6, в iOS SDK вам предоставляются встроенные компоненты графического пользовательского интерфейса, которыми можно пользоваться для доступа к


Обсуждение

Из книги автора

Обсуждение Чтобы пользователь мог выбирать фотоснимки или видеоролики из своей библиотеки фотографий, необходимо установить свойство sourceType экземпляра UIImagePickerController в значение UIImagePickerControllerSourceTypePhotoLibrary и только потом открывать перед пользователем инструмент для выбора


Обсуждение

Из книги автора

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


Обсуждение

Из книги автора

Обсуждение Класс UIVideoEditorController, содержащийся в iOS SDK, позволяет программисту вывести на экран перед пользователем специальный интерфейс для редактирования. Все, что требуется сделать, — предоставить URL видеоролика, который предполагается отредактировать, а потом


Обсуждение

Из книги автора

Обсуждение В зависимости от того, на работу в какой версии iOS рассчитано ваше приложение, его можно запускать и выполнять на различных устройствах, где установлены разные версии iOS. Например, вы можете разрабатывать приложение в последней версии iOS SDK, но в качестве целевой


Обсуждение

Из книги автора

Обсуждение Когда приложение переходит в фоновый режим, работа его основного потока приостанавливается. Потоки, которые вы создаете в своем приложении с помощью метода класса detachNewThreadSelector: toTarget: withObject:, относящегося к классу NSThread, также приостанавливаются. Если вы


Обсуждение

Из книги автора

Обсуждение Многие приложения, ежедневно поступающие на рынок App Store, обладают возможностями соединения с теми или иными серверами. Некоторые выбирают с сервера данные для обновления, другие отсылают информацию на сервер и т. д. В течение долгого времени в iOS существовал


Обсуждение

Из книги автора

Обсуждение В iOS приложение может запросить продолжить воспроизведение своих аудиофайлов, даже если оно само переходит в фоновый режим. В этом разделе мы воспользуемся плеером AVAudioPlayer, который прост и удобен в обращении. Наша задача — запустить аудиоплеер и воспроизвести


Обсуждение

Из книги автора

Обсуждение Когда приложение работает в приоритетном режиме, можно получать от экземпляра CLLocationManager делегатные сообщения, информирующие вас о том, что iOS обнаружила перемещение устройства на новое место. Однако если приложение переходит в фоновый режим и становится


Обсуждение

Из книги автора

Обсуждение Допустим, пустое приложение iOS (то есть приложение всего с одним окном, для которого еще не написан код) впервые запускается на устройстве с iOS, поддерживающем работу в многозадачном режиме. Оно запускается именно впервые, а не возвращается из фонового режима в


Обсуждение

Из книги автора

Обсуждение При работе с приложениями, которые используют класс NSURLConnection, но, уходя в фоновый режим, не запрашивают у iOS дополнительного времени, обращаться с соединениями не составляет никакого труда. Рассмотрим на примере, как будет действовать асинхронное соединение,


Обсуждение

Из книги автора

Обсуждение Пока ваше приложение работает в фоновом режиме, может произойти многое! Например, пользователь может вдруг изменить локализацию устройства с iOS на странице Settings (Настройки) и задать, к примеру, испанский язык вместо английского. Приложения могут


Обсуждение

Из книги автора

Обсуждение В приложениях, написанных для iOS, файл пакета настроек может быть предоставлен пользователю для внесения собственных настроек. Эти настройки будут доступны пользователю в приложении (Settings) на устройстве. Чтобы лучше понять, как работает этот механизм,


Обсуждение

Из книги автора

Обсуждение Пуш-уведомления похожи на локальные уведомления тем, что позволяют сообщать пользователю определенную информацию, даже если ваше приложение неактивно при поступлении уведомления. В то время как локальные уведомления назначаются самим приложением,