iOS中-Block使用
Posted super_man_风清扬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了iOS中-Block使用相关的知识,希望对你有一定的参考价值。
Block对象是 C 级别的语法和运行时特性。它们和标准 C 函数很类似,但是除了可执行代码外,它们还可能包含了变量自动绑定(栈)或内存托管(堆)。所以一个block维护一个状态集(数据),它们可以在执行的时候用来影响程序行为。
你可以用 blocks来编写函数表达式,这些表达式可以作为 API 使用,或可选的存储,或被多个线程使用。Blocks作为回调特别有用,因为block携带了进行回调所需要的执行代码和执行过程中需要的数据。
Blocks在GCC和Clang里面可用,它附带在 Mac OS X v10.6 里面的Xcode开发工具里面。你可以在 Mac OS X v10.6 及其之后,和 ios 4.0 及其之后上面使用blocks。Blocks运行时是开源的,你可以在 LLVM’s compiler-rt subproject repository(LLVM 的 RT 编译器的子项目库)里面找到它。Blocks同样作为标准 C 工作组出现在N1370:Apple’s Extensions to C(该文档同样包括了垃圾回收机制)。因为Objective-C和C++都是从 C 发展而来,blocks被设计在三种语言上面使用(也包括Objective-C++)。(语法反应了这一目标)
你应该阅读该文档来掌握 block 对象是什么和如何在C,C++或Objective-C上面使用它们来让你的程序更高效和更易于维护。
本文档结构
该文档包含了以下几个章节:
-
第一章 “Blocks入门”提供了一个对blocks的快速的和实际的介绍。
-
第二章 “概念概述”提供了对blocks概念的介绍。
-
第三章 “声明和创建Blocks”描述如何声明block变量,并实现该blocks。
-
第四章 “Blocks和变量”介绍了blocks和变量的交互,并定义__block存储类型修饰
符。
-
第五章 “使用Blocks”说明不同的使用模式。
第一章 Blocks入门以下部分使用实际的例子帮助你开始使用Blocks。
1.1声明和使用一个Block
使用^操作符来来声明一个block变量和指示block文本的开始。Block本身的主
体被{}包含着,如下面的例子那样(通常使用 C 的;符合指示block的结束):
int multiplier =7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
注意 block可以使用相同作用域范围内定义的变量。
如果你声明一个 block 作为变量,你可以把它简单的作为一个函数使用:
int multiplier =7;
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
printf("%d", myBlock(3));
// prints "21"
1.2直接使用Block
在很多情况下,你不需要声明一个 block 变量;相反你可以简单的写一个内联(inline)的block文本,它需要作为一个参数使用。以下的代码使用qsort_b函数。qsort_b和标准qsort_r函数类似,但是它使用block作为最后一个参数。
char *myCharacters[3] = {"TomJohn","George","Charles Condomine" };
qsort_b(myCharacters,3,sizeof(char *), ^(constvoid *l,constvoid *r) {
char *left = *(char **)l;
char *right = *(char **)r;
returnstrncmp(left, right,1);
});
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }
1.3 Cocoa的Blocks
在 Cocoa frameworks里面有部分方法使用block作为参数,通常不是执行一个对象的集合操作,就是在操作完成的时候作为回调使用。下面的例子显示了如何通过NSArray的方法sortedArrayUsingComparator:使用block。该方法使用一个参数,即block。为了举例说明,该情况下block被定义为NSComparator的局部变量:
NSArray *stringsArray = [NSArrayarrayWithObjects:
@"string 1",
@"String 21",
@"string 12",
@"String 11",
@"String 02",nil];
staticNSStringCompareOptions comparisonOptions =NSCaseInsensitiveSearch |NSNumericSearch |
NSWidthInsensitiveSearch |NSForcedOrderingSearch;
NSComparator finderSortBlock = ^(id string1,id string2) {
NSRange string1Range =NSMakeRange(0, [string1length]);
return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale];
};
NSArray *finderSortArray = [stringsArraysortedArrayUsingComparator:finderSortBlock];
NSLog(@"finderSortArray: %@", finderSortArray);
/*
Output:
finderSortArray: (
"string 1",
"String 02",
"String 11",
"string 12",
"String 21"
)*/
1.4 __block变量
Blocks的最大一个特色就是可以修改相同作用域的变量。你可以使用__block存储类型修饰符来给出信号要修改一个变量。改编“Cocoa的Blocks”所示的例子,你可以使用一个block来计数多少个字符串和block中只读变量currentLocal相同:
NSArray *stringsArray = [NSArray arrayWithObjects:
@"string 1",
@"String 21",// <-
@"string 12",
@"String 11",
@"Str?ng 21",// <-
@"String 02",nil];
NSLocale *currentLocale = [NSLocalecurrentLocale];
__blockNSUInteger orderedSameCount =0;
NSArray *diacriticInsensitiveSortArray = [stringsArraysortedArrayUsingComparator:^(id string1,id string2) {
NSRange string1Range =NSMakeRange(0, [string1length]);
NSComparisonResult comparisonResult = [string1compare:string2options:NSDiacriticInsensitiveSearchrange:string1Rangelocale:currentLocale];
if (comparisonResult ==NSOrderedSame) {
orderedSameCount++;
}
return comparisonResult;
}];
NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray);NSLog(@"orderedSameCount: %d", orderedSameCount);
/* Output:
diacriticInsensitiveSortArray: (
"String 02",
"string 1",
"String 11",
"string 12",
"String 21",
"Str\U00eeng 21",
"Stri\U00f1g 21"
)
orderedSameCount: 2
*/
这会在“Blocks和变量”部分里面有更多的讨论。
第二章 概念概述
Block对象提供了一个使用 C 语言和 C 派生语言(如Objective-C和C++)来创建表达式作为一个特别(ad hoc)的函数。在其他语言和环境中,一个block对象有时候被成为“闭包(closure)”。在这里,它们通常被口语化为”块(blocks)”,除非在某些范围它们容易和标准 C 表达式的块代码混淆。
2.1 Block功能
一个 block就是一个匿名的内联代码集合体:
-
和函数一样拥有参数类型
-
有推断和声明的返回类型
-
可以捕获它的声明所在相同作用域的状态
可以和其他定义在相同作用域范围的blocks进行共享更改
-
在相同作用域范围(栈帧)被销毁后持续共享和更改相同作用域范围(栈帧)的状
态
你可以拷贝一个 block,甚至可以把它作为可执行路径传递给其他线程(或者在自己的线程内传递给run loop)。编译器和运行时会在整个block生命周期里面为所有block引用变量保留一个副本。尽管blocks在纯 C 和 C++上面可用,但是一个block也同样是一个Objective-C的对象。
2.2用处
Blocks通常代表一个很小、自包的代码片段。因此它们作为封装的工作单元在并发执行,或在一个集合项上,或当其他操作完成时的回调的时候非常实用。
Blocks作为传统回调函数的一个实用的替代办法,有以下两个原因:
-
它们可以让你在调用的地方编写代码实现后面将要执行的操作。
因此 Blocks通常作为框架方法的参数。
-
它们允许你访问局部变量。
而不是需要使用一个你想要执行操作时集成所有上下文的信息的数据结构来 进行回调,你可以直接简单的访问局部变量。
-
第三章 声明和创建Blocks3.1声明一个block的引用
Block变量拥有blocks的引用。你可以使用和声明函数指针类似的语法来声明它们,除了它们使用^ 修饰符来替代*修饰符。Block类型可以完全操作其他 C 系统类型。以下都是合法的block声明:
void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int,char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
Blocks还支持可变参数(...)。一个没有使用任何参数的 block 必须在参数列表上面用void标明。
Blocks被设计为类型安全的,它通过给编译器完整的元数据来合法使用blocks、传递到blocks的参数和分配的返回值。你可以把一个block引用强制转换为任意类型的指针,反之亦然。但是你不能通过修饰符 * 来解引用一个block,因此一个block的大小是无法在编译的时候计算的。
你同样可以创建 blocks的类型。当你在多个地方使用同一个给定的签名的block时,这通常被认为是最佳的办法。
typedeffloat (^MyBlockType)(float,float);
MyBlockType myFirstBlock =// ... ;
MyBlockType mySecondBlock = // ... ;
3.2创建一个block
你可以使用 ^修饰符来标识一个block表达式的开始。它通常后面跟着一个被()包含起来的参数列表。Block的主体一般被包含在 {} 里面。下面的示例定义了一个简单的block,并把它赋值给前面声明的变量(oneFrom)。这里block使用一个标准 C的结束符;来结束。
int (^oneFrom)(int);
oneFrom = ^(int anInt) {
return anInt -1;
}
如果你没有显式的给 block 表达式声明一个返回值,它会自动的从block内容推断出来。如果返回值是推断的,而且参数列表也是void,那么你同样可以省略参数列表的void。如果或者当出现多个返回状态的时候,它们必须是完全匹配的(如果有必要可以使用强制转换)。
3.3全局blocks
在文件级别,你可以把 block作为全局标示符:
#import <stdio.h>
int GlobalInt =0;
int (^getGlobalInt)(void) = ^{return GlobalInt; };
第四章 Blocks和变量本文描述blocks和变量之间的交互,包括内存管理。
4.1变量类型
在 block的主体代码里面,变量可以被使用五种方法来处理。
你可以引用三种标准类型的变量,就像你在函数里面引用那样:
-
全局变量,包括静态局部变量。
-
全局函数(在技术上而言这不是变量)。
-
封闭范围内的局部变量和参数。
Blocks同样支持其他两种类型的变量:
-
在函数级别是__block变量。这些在block里面是可变的(和封闭范围),并任何引
用 block的都被保存一份副本到堆里面。
-
引入const。
-
最后,在实现方法里面,blocks也许会引用Objective-C的实例变量。参阅“对象
和 Block变量”部分。
在 block里面使用变量遵循以下规则:
-
全局变量可访问,包括在相同作用域范围内的静态变量。
-
传递给block的参数可访问(和函数的参数一样)。
-
程序里面属于同一作用域范围的堆(非静态的)变
以上是关于iOS中-Block使用的主要内容,如果未能解决你的问题,请参考以下文章