Блоки в языке

Objective-C

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

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

Блоки доступны в GCC и Clang в Xcode начиная с OS X v10.6. Вы можете использовать блоки с OS X 10.6 и iOS 4.0 и выше. Блоки являются средой с открытым исходным кодом и могут быть найдены в репозитории компилятора LLVM. Блоки были также представлены в C стандарте рабочей группы в качестве N1370: Apple, Расширения С. В Objective-C и C++ являются производными от C, блоки предназначены для работы со всеми тремя языками (а также Objective-C++).

Объявление и использование блока

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

int xx = 18;

int (^myBlock)(int) = ^(int num) {
    return num * xx;
};

Иллюстрация вышеприведенного примера:

cocoa objective-c block

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

int xx = 21;

int (^myBlock)(int) = ^(int num) {
    return num * xx;
};

printf("%d", myBlock(2));

// Напечатает "42"

Прямое использование блоков

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

char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };

qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
    char *left = *(char **)l;
    char *right = *(char **)r;
    return strncmp(left, right, 1);
});

// myCharacters теперь { "Charles Condomine", "George", "TomJohn" }

Блоки в Cocoa

Некоторые методы в Cocoa framework принимают блок в качестве аргумента, как правило, либо для выполнения операций над коллекцией объектов, или используют в качестве обратного вызова после завершения операции. В следующем примере показано, как использовать блок с методом NSArray sortedArrayUsingComparator. Метод принимает один аргумент-блок. Для примера, в этом случае блок определяется как NSComparator локальной переменной:

NSArray *stringsArray = @[ @"string 1",
                           @"String 21",
                           @"string 12",
                           @"String 11",
                           @"String 02" ];

static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch |
        NSWidthInsensitiveSearch | NSForcedOrderingSearch;

NSLocale *currentLocale = [NSLocale currentLocale];

NSComparator finderSortBlock = ^(id string1, id string2) {
    NSRange string1Range = NSMakeRange(0, [string1 length]);
    return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
};

NSArray *finderSortArray = [stringsArray sortedArrayUsingComparator:finderSortBlock];

NSLog(@"finderSortArray: %@", finderSortArray);

/*
Вывод:

finderSortArray: (
    "string 1",
    "String 02",
    "String 11",
    "string 12",
    "String 21"
)
*/

__block переменные

Мощью функций блоков является то, что они могут изменить переменные в той же лексической области. Вы сигнализируете, что блок может изменить переменную с помощью __block модификатора. В адаптации примера, показанного в "Блоки в Cocoa", можно использовать блок, чтобы подсчитать, сколько строк сравниваются как равные, как показано в следующем примере. Для примера, в этом случае блок используется непосредственно и использует currentLocale как переменную только для чтения в блоке:

NSArray *stringsArray = @[ @"string 1",
                          @"String 21", // <-
                          @"string 12",
                          @"String 11",
                          @"Strîng 21", // <-
                          @"Striñg 21", // <-
                          @"String 02" ];

NSLocale *currentLocale = [NSLocale currentLocale];

__block NSUInteger orderedSameCount = 0;

NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id string1, id string2) {
    NSRange string1Range = NSMakeRange(0, [string1 length]);
    NSComparisonResult comparisonResult = [string1 compare:string2 options:NSDiacriticInsensitiveSearch
                                   range:string1Range locale:currentLocale];

    if (comparisonResult == NSOrderedSame) {
        orderedSameCount++;
    }
    return comparisonResult;
}];

NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray);
NSLog(@"orderedSameCount: %d", orderedSameCount);

/*
Вывод:
diacriticInsensitiveSortArray: (
    "String 02",
    "string 1",
    "String 11",
    "string 12",
    "String 21",
    "Str\U00eeng 21",
    "Stri\U00f1g 21"
)

orderedSameCount: 2
*/

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

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

void (^blockReturningVoidWithVoidArgument)(void);

int (^blockReturningIntWithIntAndCharArguments)(int, char);

void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);

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

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

typedef float (^MyBlockType)(float, float);

MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;

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

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

float (^oneFrom)(float);

oneFrom = ^(float aFloat) {
    float result = aFloat - 1.0;

    return result;
};

Глобальные блоки

На уровне файла, вы можете использовать блок в качестве глобального буквально:

#import <stdio.h>

int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };
 
 
homeЗаметили ошибкукарта сайта 
   Made on a Mac