Blocks编程

1.介绍

Block是一个C Level的语法以及运行时的一个特性,非常像标准C中的函数(函数指针),但是其运行需要编译器和运行时支持,目前LLVM+Clang可以很好的支持Block(苹果修改过的GCC也可以)。Block和函数不同的是其语义 闭包 特性,以及可以有匿名block的存在。 你可以在LLVM的官方网站查看Block语言规范
你可以通过{}内的.

int multiplier = 2;
int (^myBlock)(int) = ^(int num){
    return num * multiplier;
};
printf("%d",myBlock(4));

上面代码中的 2. 声明创建和调用

声明Block变量 
Block变量保存着指向Block的指针,声明一个Block变量就和声明一个函数指针变量类似,只是将*改成了. 其他的就和C的类型系统保持一致了。

void (^blockReturningVoidWithVoidArgument)(void);
int (^blockReturningIntWithIntAndCharArguments)(int, char);
void (^arrayOfTenBlocksReturningVoidWithIntArgument[10])(int);

另 Block还支持可变参数variadic (...) ,没有参数的话,变量列表的地方必须写上void关键字.

声明Block类型 你可以通过typedef声明Block的类型,这样多个地方需要使用同种类型的Block的时候会比较方便,

typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;

Block创建 声明了一个Block变量之后,可以为这个变量赋值

blockReturningVoidWithVoidArgument = ^{
      printf("%s","Block Returing Void With Void Argument.");
}

当然你可以在声明变量的同时赋值

void (^blockReturningVoidWithVoidArgument)(void) = ^{
      printf("%s","Block Returing Void With Void Argument.");
}

Block调用 Block的调用和函数的调用是非常相似的,如上面定义的blockReturningVoidWithVoidArgument,调用的时候则直接blockReturningVoidWithVoidArgument();便可.

匿名Block 当一个Block作为函数参数的时候,一般实参都是以匿名Block的方式传过去的。

void callVoidVoid(void (^closure)(void)) {
   closure();
}
int main(int argc, char *argv[]) {
    __block int i = 10;
    callVoidVoid(^{ ++i; });
   if (i != 11) {
       printf("*** %s didn‘t update i\n", argv[0]);
       return 1;
   }
   printf("%s: success\n", argv[0]);
   return 0;
}

当然你也可以直接调用匿名Block,如

^{ ++i; }();

3.Block和变量

一个Block的内部是可以引用自身作用域外的变量的,包括static变量,extern变量或自由变量(定义一个变量的时候,如果不加存储修饰符,默 认情况下就是自由变量auto,auto变量保存在stack中的.除了auto之外还存在register,static等存储修饰符) ,对于自由变量,在Block中是只读的。在引入block的同时,还引入了一种特殊的变量存储修饰符 代码示例 3.1

__block int blockValue = 0;
int autoValue = 0;

void(^printValue)(void) = ^{
    printf("blockValue = %d\n",blockValue);
    printf("autoValue = %d\n",autoValue);

};
blockValue ++;
autoValue ++;
printValue();

3.1中的代码,输出的值为

blockValue = 1
autoValue = 0

可以看到自由变量尽管自增了,但是在调用printValue这个Block的时候,看到的还是其定义的时候看到的那个autoValue的值,autoValue的值在Block的内部示无法修改的,要不然编译器会报错:

Semantic Issue: Variable is not assignable (missing __block type specifier)

Block定义时内存是分配在stack上的,当其作用域结束,就会被自动释放,所以你不需要去担心它的内存情况,我们可以对一个Block进行Block_copy()之后,Block会被拷贝到heap中的内存中,且其所有的引用到的自由变量也将会被拷贝,当然你得记得通过 在Block内部如果引用到对象或者对象的成员变量,那么当Block被拷贝 代码示例 3.2

NSObject *testObject = [[NSObject alloc] init];

NSLog(@"%lu",[testObject retainCount]); //1
NSLog(@"%lu",[self retainCount]); //1

void(^testBlock)(void) = ^{
       NSLog(@"The Test String : %@", testObject);
   NSLog(@"The Window Object : %@", _window);
};

NSLog(@"%lu",[testObject retainCount]); //1
NSLog(@"%lu",[self retainCount]); //1

void(^testBlock2)(void) = Block_copy(testBlock); //testBlock会被拷贝到heap中,所以用完了要自己调用Block_release进行释放
NSLog(@"%lu",[testObject retainCount]); //2
NSLog(@"%lu",[self retainCount]); //2

testBlock2();

Block_release(testBlock2);

NSLog(@"%lu",[testObject retainCount]); //1
NSLog(@"%lu",[self retainCount]); //1

[testObject release];

Block的闭包特性使得Block可以脱离其定义的作用域进行运行,所以你可以在一个函数中返回一个Block,在别的线程或者当前线程的RunLoop中进行运行,而不用担心那些引用到的外部变量是否被释放掉了。

4.Block实际应用

那么我们一般什么时候会用到Block呢? Blocks通常是一小段自包含的代码片段.所以它经常被用于多线程运行的代码单元(如GCD),或用于处理聚合类元素单元,或者作为某个函数调用完成后的回调函数.

Block用作回调函数比传统的回调函数有以下的优越性: (Jacky Shin:下面这个是重点,需要仔细理解使用场合)

  • 在函数调用的时候,将Block作为一个参数传给函数
  • 允许访问本地变量,这样可以避免通过结构体将本地变量封装后传递给回调函数

应用1: Animations & Completion Handler

[UIView animateWithDuration:2
               animations:^{
                    self.view.backgroundColor = [UIColor redColor];
                }
                completion:^(BOOL finished){
                    if (finished){
                        self.view.backgroundColor = [UIColor blueColor];
                    }
                }];

应用2: Enumeration 
对数据集合类中的每一个元素进行遍历,每次传入一个对象,进行处理

NSArray *cards = [NSArray arrayWithObjects:@"Jack", @"Queen", @"King", @"Ace", nil];
[cards enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) {
     NSLog(@"%@ card at index %d", object, index);
 }];

应用3: Notification Handler


[[NSNotificationCenter defaultCenter]
 addObserverForName:@"TestNotification"
 object:nil
 queue:aNSOperationQueue
 usingBlock:^(NSNotification *notification){
     NSLog(@"Notification: %@",notification);
 }];

应用4: GCD


dispatch_queue_t imageDownloadQueue = dispatch_queue_create("Image Download Queue", NULL);
dispatch_async(imageDownloadQueue, ^{
    NSURL *imageURL = [NSURL URLWithString:@"http://xxx.xx.com/a.png"];
    NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
    UIImage *image = [UIImage imageWithData:imageData];
    dispatch_async(dispatch_get_main_queue(), ^{
        [imageView setImage:image];
    });
});
时间: 2024-08-28 15:20:39

Blocks编程的相关文章

[转]blocks编程

原文地址:http://geeklu.com/2012/01/block/ 介绍 声明创建和调用 Block和变量 Block实际应用 1.介绍 Block是一个C Level的语法以及运行时的一个特性,非常像标准C中的函数(函数指针),但是其运行需要编译器和运行时支持,目前LLVM+Clang可以很好的支持Block(苹果修改过的GCC也可以).Block和函数不同的是其语义 闭包 特性,以及可以有匿名block的存在. 你可以在LLVM的官方网站查看Block语言规范. 你可以通过^ 运算符

.Net中的并行编程-5.流水线模型实战

自己在Excel整理了很多想写的话题,但苦于最近比较忙(其实这是借口).... 上篇文章<.Net中的并行编程-4.实现高性能异步队列>介绍了异步队列的实现,本篇文章介绍我实际工作者遇到了处理多线程问题及基于异步队列底层数据结构的解决方案. 需求如下:1.提供数据服写入务供上层应用调用,数据写入服务处理的吞吐量要达到60w/s每秒,也就是用户每秒发送60w的数据然后通过数据写入服务写到数据库中(数据库为公司自主研发的实时数据库). 2.尽量简化上层应用调用服务的复杂度. 一.分析性能瓶颈: 1

反汇编objc分析__block

"You can specify that an imported variable be mutable—that is, read-write— by applying the __block storage type modifier."文档已经清楚说明了它的作用.反汇编就是要看个究竟. __block类型有着它自己的storage,是blocks编程的一部分,今天先来看一下它如何做storage的. 我们定义如下: NSString* c = [@"ab"

objc反汇编分析,手工逆向libsystem_blocks.dylib

上一篇<block函数块为何物?>介绍了在函数中定义的block函数块的反汇编实现,我在文中再三指出__block变量和block函数块自始还都是stack-based的,还不完全适合在离开定义它们的范围之外使用,包括异步回调.本篇贴上我手工逆向的函数 libsystem_blocks.dylib`_Block_copy_internal.从名字可以看出blocks编程由系统提供的编程框架,_Block_copy_internal也就是block函数块的copy方法,是令block函数块适合用

ShareSDK向iOS平台移植时问题及解决办法

问题 此前,我的开发环境是Windows7(64bits)+VMware 9.0+Mac OS 8.5+Xcode 4.5,结果在测试游戏中集成目前最新的ShareSDK(ShareSDK For iOS 2.10.3,而ShareSDK For COCOS2D-X也是目前最新的)时失败.出现如下图所示的编译错误: 而第二个错误如下图: 显然,这两个错误都来自ShareSDK官方文件.注意:在基于Cocos2d-x框架开发的游戏中集成ShareSDK实现iOS版本时需要两个部分(其中也要加入上面

ios性能测试Instruments

Instruments 用户指南 Instruments用户指南介绍 Instruments 是应用程序用来动态跟踪和分析 Mac OS X 和 iOS 代码的实用工具.这是一个灵活而强大的工具,它让你可以跟踪一个或多个进程,并检查收集的数据.这样,Instruments 可以帮你更好的理解应用程序和操作系统的行为. 使用 Instruments 应用,你可以使用特殊的工具(即 instruments 工具)来跟踪同一进程不同方面的行为.你也可以使用该应用来记录一系列用户界面的动作并响应它们,同

体验Code::Blocks下的Windows GUI编程(32 bit and 64 bit)

0. 前言 不知道为什么,几乎所有的C++编程教程都是从命令行版(控制台应用程序)的Hello World开始的.然而,对于现在的年轻人来说,从小就用鼠标点击窗口或图标操作电脑,对于那个神秘黑色的窗口中的文字就像天书.对于我们这些从DOS时代走来的人,或许那个黑色窗口会唤起很多记忆,但是,对于当前的GUI化的时代来说,那个窗口已经没有多少意义了.除非为了显示我的知识渊博和高深莫测,通常我不会给年轻人讲述那个黑色窗口中的东西. 既然现在学习C++编程的都是年轻人,我还是讲一下怎样构建GUI版的He

(译文)IOS block编程指南 4 声明和创建blocks

Declaring and Creating Blocks (声明和创建blocks) Declaring a Block Reference (声明一个block引用) Block variables hold references to blocks. You declare them using syntax similar to that you use to declare a pointer to a function, except that you use ^ instead o

python网络编程socket (一)

提起网络编程,不同于web编程,它主要是C/S架构,也就是服务器.客户端结构的.对于初学者而言,最需要理解的不是网络的概念,而是python对于网络编程都提供了些什么模块和功能.不同于计算机发展的初级阶段,程序员走到今天,已经脱离了手工打造一切,要自己实现所有细节的年代.现在提倡的是不要重复造轮子,而是学习别人的轮子怎么用,只有那些有需求或能专研的人才去设计轮子甚至汽车,so,这是一个速成的年代. 因此,对于一个面向工作的python程序员,学习python的网络编程,其实学的就是那么几个模块,