close
当前位置: 物联网在线 > 技术文库 > ios >

iOS中block技术小结

block是C语言级别的语法和运行时特性,应用到Objective-C中可以增强函数功能。在合适场景中灵活应用block技术,对实际开发大有裨益。

block是对C语言中函数的扩展,除了函数中的代码,还包含变量的绑定。block有时也被称为闭包(closure),闭包就是一个函数,或者一个指向函数的指针,加上这个函数执行的非局部变量。通俗一点,就是闭包允许一个函数访问声明该函数运行上下文中的变量,甚至可以访问不同运行上文中的变量。

脚本语言:

function funA(callback){

alert(callback());

}

function funB(){

var str = "Hello World"; //函数funB的局部变量,函数funA的非局部变量

funA(

function(){

return str;

}

);

}

通过上面的代码我们可以看出,按常规思维来说,变量str是函数funB的局部变量,作用域只在函数funB中,函数funA是无法访问到str的。但是上述代码示例中函数funA中的callback可以访问到str,就是因为闭包性。

block实际上就是Objective-C语言对于闭包的实现。block配合dispatch_queue,可以方便地实现简单的多线程编程和异步编程。

block原型及定义

block本质上是和其他变量类似。不同的是block存储的数据是一个函数体。使用block时,你可以像调用其他标准函数一样,传入参数,并得到返回值。

脱字符(^)是block的语法标记,按照我们熟悉的参数语法规约所定义的返回值以及block的主体(也就是可以执行的代码)。下图讲解了如何把block变量赋值给一个变量的语法:

iOS中block技术小结

按照调用函数的方式调用block对象变量就可以了:

int result = myBlock(4); //result是28

使用typedef关键字

由于block数据类型的语法会降低整个代码的阅读性,所以常使用typedef来定义block类型。

typedef double (^Multiply2BlockRef)(double c, double d);

这行语句定义了一个名为Multiply2BlockRef的block变量,它包含两个double类型参数并返回一个double类型数值。有了typedef定义,就可以像下面这样使用这个变量:

Multiply2BlockRef multiply2 = ^(double c, double d) {

return c * d;

}

printf(“%f”, multiply2(4, 5));

Block和变量

block被声明后会捕捉创建点时的状态。block可以访问函数用到的标准类型的变量:

全局变量;

全局函数(这个是可以调用);

封闭范围内的变量;

与block声明时同级别的__block变量(这是可以修改的);

封闭范围内的非静态变量会被获取为常量;

Objective-C对象;

block内部变量;

3.1 本地变量

本地变量就是与block在同一范围内声明的变量。

typedef double (^Multiply2BlockRef)(double c, double d);

double a = 10, b = 10;

Multiply2BlockRef multiply = ^(void) { return a * b;}

a = 20;

b = 20;

NSLog(@“%f”, multiply());

这个NSLog会输出什么值?400?不是,为什么?

因为对于本地变量,block定义时copy变量的值,在block中作为常量使用,所以即使变量的值在block外改变,也不影响他在block中的值。NSLog只会输出100。

3.2 全局变量

全局变量或静态变量在内存中的地址是固定的,block在读取该变量值的时候是直接从其所在内存读出,获取到的是最新值,而不是在定义时copy的常量。

3.3 Block变量

本地变量会被block作为常量获取到,如果想要修改它们的值,必须将它们声明为可修改的,否则会编译出错。

double c = 3;

Multiply2BlockRef multiply2 = ^(double a, double b){ c = a * b; } // 编译会报错

如果想要在block代码里修改本地变量,需要将变量标记为__block。基于之前的代码,给变量c添加__block关键字,如下:

__block double c = 3;

对于用__block修饰的外部变量引用,block是复制其引用地址来实现访问的。

3.4Objective-C对象

一般来说我们总会在设置block之后,在合适的时间回调block,而不希望回调block的时候block已经被释放了,所以我们需要对block进行copy,copy倒堆中,以便后用。

当一个block被Copy的时候,如果你在block里进行了一些调用,那么将会有一个强引用指向这些调用方法的调用者,有两个规则:

如果是通过引用来访问一个实例变量,那么将强引用至self;

如果是通过值来访问一个实例变量,那么将直接强引用至这个“值”变量;

苹果官方文档里有两个例子来说明这两种情况:

dispatch_async(queue, ^{

// instanceVariable is used by reference, a strong reference is made to self

doSomethingWithObject(instanceVariable);

});

id localVariable = instanceVariable;

dispatch_async(queue, ^{

/*

localVariable is used by value, a strong reference is made to localVariable

(not to self)

*/

doSomethingWithObject(localVariable);

});


(责任编辑:ioter)

用户喜欢...

iOS面试中,如何优雅的回答Block导致循环引用的问题

说到循环引用问题,最最最常遇到的,不是在项目中,而是在面试中。如果面试官问你开发中是否遇到过retain cycle,你如果说没遇到过,估计已经很难跟面试官继续友好的沟通下去了。 但是...


深入研究Block实现原理

Blocks是C语言的扩充功能, iOS 4中引入了这个新功能“Blocks”,那么block到底是什么东西呢。其实它就是一个闭包,一个带有自动变量(局部变量)的匿名函数。很多语言也实现自己的闭包,比...


iOS消息转发机制与BlocksKit

最近看了『神奇的 BlocksKit』系列,里面说到动态代理是BlocksKit的精华部分,对于使用block实现委托方法比较好奇,于是下载了源码阅读了一下。 Block已被广泛用于iOS编程。它们通常被用作可并...


关于 block 会不会被自动 copy 的实验和猜想

今天群里不知怎么说起了 block 在栈上还是在堆上的问题。好像之前在哪里看到过,现在 block 的属性已经不用写 copy 关键字,就会自动 copy。于是做了几个实验,想看看什么情况下会自动 cop...