Objective-C Block数据类型讲解

阅读更多
转自:http://kan.weibo.com/con/3516583830745467

/**

用来内存管理第一部分的测试函数

@param value1 第一个整型值

@param num2 第二个参数

*/

int _testBlock(constint value1,int num2);

int _testBlock(constint value1,int num2)

{

   return value1 + num2;

}

int main(int argc, constchar * argv[])

{

   //Block 数据类型

   //1、声明Block 数据类型变量

   int num1 = 7;

   /**

   Block 数据类型与结构体类型相似指的都是泛指类型的数据类型,即需要声明具有实际意义的Block数据类型或结构体类型

  

       int(^aBlock)(int num2),第一个int指的是当前Block数据类型的返回值的类型是整型,可以换成其他数据类型,^aBlock在小括号内表示的数据类型为aBlock,第二个int num2即为参数

  

       ^(int num2){

  

           return num1+num2;

       }; 赋值运算符的后边,即为Block变量的值,大括号内是函数实现的逻辑,即可以随意更改为其他逻辑,例如return num1 * num2等等;

    */

   int(^aBlock)(int num2)  = ^(int num2){

      

       return num1+num2;

   };

  

   //同样可以通过类型定义,定义具体的Block数据类型,下面即定义一个返回值为整型,只有一个整型参数的myBlock数据类型

   typedefint(^myBlock)(int num2);

  

   //可以通过myBlock数据类型声明变量

   myBlock bBlock = ^(int num2){

       return num1 - num2;

   };

   //使用第一种方式定义的Block变量

   NSLog(@"aBlock = %d",aBlock(3));

   //使用第二种方式定义的Block变量

   NSLog(@"bBlock = %d",bBlock(3));

  

  

  

  

   //2、Block 变量涉及到的内存问题

   int value1 = 2;

   //定义具体的Block数据类型CaculateBlock

   typedefint(^CaculateBlock)(int num2);

   CaculateBlock _block = ^(int num2){

       //value1++是不可以改变的

       //在Block变量的内部,使用外部的变量时是只读的

       return value1 + num2;

   };

   /**

   重新修改valu1的值,结果等于4 而不是5

      

       我们可以通过另外一种方式理解,再main函数外定义一个函数 int _testBlock(const int value1,int num2);

    */

   //想想为什么_testBlock一定要在上边调用?

   NSLog(@"_testBlock = %d",_testBlock(value1,2));

   value1 = 3;

   NSLog(@"_block = %d",_block(2));

  

   //怎么解决这种问题只读变量的问题呢,使用__block关键字

  

   __blockint value2 = 2;

   CaculateBlock _block2 = ^(int num2){

       value2 ++;

       return value2 - num2;

   };

   value2++;

   //4-3 = 1,value2是怎么变成4的呢,很明显是value2的两次自增变化的

   NSLog(@"_block2 = %d",_block2(3));

  

   //总结内存问题,就是几句话,每一个Block变量是存储在一个栈区stack1(因为是局部变量的原因),但是因为每一个Block变量的值是一段代码块,所以Block变量的值自己也负责管理一片栈区stack2的内存,当Block变量出栈后,Block变量的值自己负责的栈也会自动出栈。

   //那么声明Block数据类型的变量的过程中,使用外部变量的时候,使用__block关键字的话,该外部变量可以理解为一个小型的全局变量,但是全局仅限于Block变量中使用,否则不使用__block关键字的话,在声明Block数据类型时,是将该外部变量的值赋值到Block变量自己负责的栈区内,并设置为const只读变量,所以及时修改了外部变量的值,仍然不会影响到Block自己负责的栈区的只读变量的值,因为它们已经是两片内存区域了。

  

   //3、由于使用Block引起的retain cycle即循环持有的问题.

   //举例,封转一个学生类FOStudent

   /**

       //定义一个具体的Block数据类型

       typedef int(^StudentBlock) (int _age);

  

       @interface FOStudent : NSObject

  

       //实例属性要写copy,使用copy关键字的作用就是将任意一片内存区域的内容,赋值相同的一份到堆内存

       @property (nonatomic ,copy) StudentBlock block;

  

       //年龄,一个测试属性

       @property (nonatomic ,assign) int age;

  

       @end

  

       @implementation FOStudent

       @synthesize block;

       @synthesize age;

       - (void)dealloc

       {

           //在delloc中,在控制台打印delloc消息,提示我们该实例对象已被销毁

           NSLog(@"%s",__FUNCTION__);

           self.block = nil;

           self.age = 0;

           [super dealloc];

       }

  

       @end

    */

  

   //实例化学生对象

   FOStudent *student = [[FOStudentalloc] init];

  

   StudentBlock _studentBlock = ^(int _age){

       return student.age + _age;

   };

   //设置student的block实例属性为刚刚声明的_studentBlock局部变量,因为实例属性使用的是copy关键字,所以局部变量_studentBlock会赋值到堆内存中,并且生命周期与student实例对象相同(因为是在dealloc中释放的实例对象block内存),

   student.block = _studentBlock;

   //当对student实例对象发送release消息后,发现并没有delloc内容在控制台输出

   [student release],student = nil;

  

   //说明student实例对象并没有销毁内存,到底是在哪里它的引用计数器又加1了呢,根据第二部分的理解,声明Block变量的过程中,如果使用到的外部变量没有使用__block关键字,是会拷贝一份到Block变量自己负责的栈区,同理,在OC对象作为外部变量使用到Block变量中的时候,会对该对象的引用计数器+1,并且是在出栈的时候引用计数器-1,因为该block变量已经作为student实例对象的属性与student的声明周期相同,结果student对象不销毁,block不销毁,block不销毁,也就不会出栈,结果造成了retain cycle问题.

   //怎么解决问题呢?

   //仍然是使用__block关键字,因为__block关键字会定义小型的全局变量

  

   FOStudent *_student = [[FOStudentalloc] init];

   __blockFOStudent *bStudent = _student;

  

   StudentBlock _bstudentBlock = ^(int _age){

       return bStudent.age + _age;

   };

   _student.block = _bstudentBlock;

   //这样通过这种方式的输出,_student对象就可以销毁了,并且也在控制台进行了输出

   [_student release],_student = nil;

   return0;

}

你可能感兴趣的:(objective-c)