Blocks学习笔记总结

本文是对Apple的《Blocks Progromming Gude》学习的笔记总结。

  对象时C级别的语法和运行时特性。和标准C函数很类似,但除了可执行代码外,还可能包含了变量自动绑定(栈)或内存托管(堆)。所以一个block维护一个状态集(数据),可以在执行的时候用来影响程序行为。Block用来作为回调特别有用。

  你可以在MAC OS 10.6及其以后版本、IOS 4.0及其以后版本上使用Blocks.

  Blocks运行时是开源的,可以再LLVM's compiler-rt subproject repository(LLVM的RT编译器的子项目)里面找到他。

1.声明一个Block

复制代码
1 int (^myBlock) (int) = ^(int num){
2     return num * num; 
3 }
4 说明:
5 int:返回值类型,如果没有返回值则为void
6 (^myBlock):块定义需要有一个^标记,myBlock是块名称
7 (int):参数类型列表,如果没有参数则为void
8 ^(int num):以^开头的参数列表,如果没有则为void,也可以省略
9 {}:block体(相当于函数体)
复制代码

2.使用block

1 printf("%d",myBlock(7));

3.很多情况下不需要对block进行生命,而是直接使用内联的block

复制代码
1 char *myCharacters[3] = {"TomJohn","George","Jim Green"};
2 
3 qsort_b(myCharacters,3,sizeof(char *),^(const void *l,const void *r){
4     char *left = *(char **)l;
5     char *right = *(char **)r;
6     return strncmp(left,right,l);
7 });
复制代码

4.在Cocoa frameworks中有一些方法使用block作为参数,通常不是执行对一个对象的集合的操作就是在操作完成的时候作为回调使用。例子中显示了如何通过NSArray的sortedArrayUsingComparator:使用block.

复制代码
 1 -(void) sort{
 2     NSArray *stringArray = [NSArray arrayWithObjects:@"Java网络编程",@"Java开发实战经典",@"研磨设计模式",@"iPhone开发秘籍",@"自己动手写网络爬虫",@"Cocos2d 游戏开发实战",@"Oracle宝典",@"Java Web开发实战",nil];
 3     static NSStringCompareOptions options = NSCaseInsensitiveSearch |
 4                 NSNumericSearch |
 5                 NSWidthInsensitiveSearch |
 6                 NSForcedOrderingSearch;
 7     NSLocale *currentLocale = [NSLocale currentLocale];
 8     NSComparator sortBlock = ^(id string1,id string2){
 9         NSRange string1Range = NSMakeRange(0, [string1 length]);
10         return [string1 compare:string2 options:options range:string1Range locale:currentLocale];
11     };
12     NSArray *sortedArray = [stringArray sortedArrayUsingComparator:sortBlock];
13     NSLog(@"array:%@",sortedArray);
14 }
复制代码

5、Blocks默认不能修改相同作用域范围内的变量,但是如果这个相同作用域的变量如果使用了__block关键字进行修饰,则可以通过blocks进行修改。

6、一个block就是一个匿名的内联代码集合体:

  • *和函数一样拥有参数类型
  • *有推断和声明的返回值类型
  • *可以捕获它的声明所在的相同作用域的状态,可以和其它定义在相同作用于范围的bolcks进行共享更改
  • *在相同作用域范围被销毁后持续共享和更改相同作用域范围的状态

7、Blocks通常代表一个很小、自包的代码段。因此他们作为封装的工作单元在并发执行或者一个集合项上或者当其他操作执行完毕时的回调的时候非常使用。

Blocks作为传统的回调函数的一个实用的替代方法有以下两个原因:

  它们可以让你在调用的地方编写代码实现后面将要执行的操作。因此Blocks通常作为Frameworks 方法的参数

  它们允许你访问局部变量,而不是需要使用一个你想要执行操作时继承所有上下文信息的数据结构来进行回调。你可以直接简单的访问局部变量。

8、blocks和一个函数指针很相似,除了使用^来代替*。下面的都是合法的block的声明:

1 void (^blockReturningVoidWithVoidArgument)(void);
2 int (^blockReturningIntWIthIntndCharArguments)(int,char);
3 void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);
4 
5 Blocks还支持可变参数(...).一个没有使用任何参数的block必须在参数列表上用void标明。

9、可以把一个bolcks强制转换成任意类型,反之亦然,但是不能通过*修饰符来解引用一个block,因此一个block的带笑傲是无法在编译的时候计算的。你同样可以创建block的类型,挡在多个地方使用同一个给定签名的block的时候,这通常被认为是最佳的方法:

1 typedef float (^MyBlockType) (float,float);
2 MyBlockType myFirstBlock = ...;
3 MyBlockType mySecondBlock = ...;

10、创建一个Block

复制代码
1 int (^oneFrom) (int);
2 oneFrom = ^(int anInt){
3     return anInt - 1;
4 };
5 如果咩有显式的给一个block表达式声明一个返回值,它会自动的从block内容推断出来。如果返回值是推断的,而且参数列表也是void,那么你同样可以省略参数列表的void。如果或者当出现多个返回状态的时候,它们必须是完全匹配的(如果有必要可以使用强制类型转换)
复制代码

11、全局Blocks

在文件级别,可以把block作为全局标示符:

1 #import <stdio.h>
2 
3 int GlobalInt  = 0;
4 int (^getGaobalInt)(void) = ^{return GlobalInt;};

12、在block的主体代码中,变量可以被使用五种方法来处理。可以引用三种标准类型的变量,就像在函数里面引用一样:

全局变量:包括静态局部变量

全局函数:在技术上说这不是变量

封闭范围内的局部变量和参数

*在函数界别是__block变量。这些在block里面是可变的,并且任何引用block的都被保存一份副本到堆里面。

*引用const

*最后在实现方法里面,blocks也许会引用Objective-C的实例变量。

在Blocks里面使用变量遵循以下的规则:

全局变量可以访问,包括在相同作用域范围内的静态变量

传递给block的参数可以访问(和函数的参数一样)

程序里面属于同一作用域范围的堆变量作为const变量(只读)。它们的值在程序里面的block表达式内使用。在嵌套block里面,该值在最近的封闭范围内被捕获。

属于同一作用域内并被__block修饰符标识的变量作为引用传递因此是可变的。

属于同一作用域范围内的block的变量就和函数的局部变量操作一样。

example:使用本地非静态变量

1 int multipiler = 7;
2 int (^myBlock)(int) = ^(int num){
3     return multipiler * 7;
4 };
5 如果在block体内修改multipiler的值将会发生错误。

13、可以通过__block修饰符指定引入的变量是可以更改的,此种类型的变量保存在变量共享的作用域范围内,所有的blocks和block副本都声明或者创建在和变量的作用域相同的范围内。你可以指定引入一个变量为可更改的,即读-写的,通过应用__block存储类型修饰符。局部变量的__block的存储和register、auto、static等存储类型相似,但它们之间不兼容。 __block变量保存在变量共享的作用域范围内,所有的blocks和block副本都声明或创建在和变量的作用域相同范围内。所以,如果任何blocks副本声明在栈内并未超出栈的结束时,该存储会让栈帧免于被破坏(比如封装为以后执行)。同一作用域范围内给定的多个block可以同时使用一个共享变量。 作为一种优化,block存储在栈上面,就像blocks本身一样。如果使用Block_copy拷贝了block的一个副本(或者在Objective-C里面给block发送了一条copy消息),变量会被拷贝到堆上面。所以一个__block变量的地址可以随时间推移而被更改。

使用__block的变量有两个限制:它们不能是可变长的数组,并且它们不能是包含有C99可变长度的数组变量的数据结构。

 

复制代码
1 __block int x = 123; // x lives in block storage
2 void (^printXAndY)(int) = ^(int y) {
3 x = x + y;
4 printf("%d %d\n", x, y);
5 };
6 printXAndY(456);
复制代码
复制代码
 1 下面的例子显示了blocks和其他几个类型变量间的交互:
 2 extern NSInteger CounterGlobal;
 3 static NSInteger CounterStatic;
 4 {
 5 NSInteger localCounter = 42;
 6 __block char localCharacter;
 7 void (^aBlock)(void) = ^(void) {
 8 ++CounterGlobal;
 9 ++CounterStatic;
10 CounterGlobal = localCounter; // localCounter fixed at block creation
11 localCharacter = 'a'; // sets localCharacter in enclosing scope
12 };
13 ++localCounter; // unseen by the block
14 localCharacter = 'b';
15 aBlock(); // execute the block
16 
17 // localCharacter now 'a'
18 }
复制代码

14、在引用计数的环境里面,默认情况下当你在block里面引用一个Objective-C对象的时候,该对象会被retain。当你简单的引用了一个对象的实例变量时,它同样被retain。但是被__block存储类型修饰符标记的对象变量不会被retain

注意:在垃圾回收机制里面,如果你同时使用__weak和__block来标识一个变量,那么该block将不会保证它是一直是有效的。 如果你在实现方法的时候使用了block,对象的内存管理规则更微妙:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值