【iOS7的一些总结】14、Block的概念和应用

我们知道,不同对象之间通信的方法比较常用的有代理(delegate)、通知中心(NotificationCenter)等方法。Block则是另一种对象间通信的方法。其中,delegate和block相关的两个对象是一对一的关系,通知中心所反映的则是一对多的关系,通过这些方法实现了对象间的解耦合(功能相关,但没有继承与派生关系)。


1、简介

Block在ios 4.0之后加入,并大量使用在新的ios api中。block是一个匿名的代码块,可以作为传递给其他对象的参数,并得到返回值。从本质上讲,block同其他普通的变量类似,只是其储存的数据是一个函数体。Block不只是针对Objective-C的专利,而是一种可以应用于C、C++和OBjective-C的语言层面的新特性。通过使用block,开发者可以将一段代码段像某一个数值一样当做参数传递给函数。同时,blocks也是Objective-C的一种对象,可以像其他对象一样添加到NSArray或者NSDictionary等集合中。


2、使用方法

(1)声明一个block:

//返回值 Block变量  参数
  int  (^myBlocks)(int);

(2)创建一个block:

myBlocks = ^(int a)
{
  int result = a * a;
  return result;
}

(3)调用block:

int ret = myBlocks(10);

熟悉C/C++的TX也许有一种感觉,即ios的block机制十分类似前者的函数指针这一概念。


(4)声明block的类型:利用typedef简化block的定义和实现,尤其是对同一种格式定义多个block时更加明显。

typedef int (^myBlocks) (int);
MyBlocks myBlock = ^(int a)
{
  int result = a*a;
  return result;
}

3、block作为函数的参数:

通过将block作为函数的参数进行传递,可以实现类似回调函数的功能;

.....

 

4、Block中的变量

Block中可以使用全局变量和局部变量,对二者的处理有所不同。block引用局部变量时,将该变量作为常量编码到代码块中;如果想在block中进行修改,则必须使用__block进行修饰。如:

//==========错误写法==========
int number = 10;
myBlock = ^(int a)
{
  number = 20;//number被处理成常量,不能修改。
  NSLog("%@",number);
}
//==========正确写法==========
__block int number = 10;
myBlock = ^(int a)
{
  number = 20;//__block修饰的局部变量可以在block内部修改
  NSLog("%@",number);
}

5、Block的内存管理

对于在block内部引用的对象,__block也是关键因素。如果在block内部引用了一个局部对象,那么该对象的引用计数会+1;除非该对象由__block修饰,那么其引用计数不变。这么做的主要原因是block的代码经常涉及到延迟执行的情况,所以ios将block内部涉及到的对象进行retain,防止在block中的代码执行之前该对象就被释放掉。

对block的内存管理通常可以使用copy和release方法。在创建之初,block的内存分配在栈中,copy之后转移到堆中。

避免在实现block时发生对self的强循环引用:
简而言之,如果一个类包含一个block作为property,那么这个block的copy属性可以认为是self对block的强引用,而一个block对其内部调用的变量和对象同样存在强引用关系。那么如果一个block在实现时调用了self的方法,那么将会造成self和block的强循环引用,使得内存无法被释放。为了避免这种情况,在block内部调用self的时候,需要重新定义一个由__weak修饰的self副本,并以该副本调用self的方法,如下代码所示:

- (void)configureBlock {
    XYZBlockKeeper * __weak weakSelf = self;
    self.block = ^{
        [weakSelf doSomething];   // capture the weak reference
  }
}

除了上述的block的主要作用之外,还可以使用block简化集合类的枚举操作,以及简化并行任务等,详见官方文档

上一篇:Android 模块化开发


下一篇:Virtualbox 安装CoreOS 学习使用Docker