Block(二)

二, block  注意事项
1 block  在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在  block  块内使用该只读拷贝。
如下代码:
- ( void )testAccessVariable
{
NSInteger outsideVariable =10;
   //__block NSInteger outsideVariable=  10 ;
   NSMutableArray * outsideArray = [[NSMutableArray alloc]init];
    void  (^blockObject)( void )= ^( void ){
       NSInteger insideVariable=  20 ;
      KSLog( @" > member variable = %d" ,self.memberVariable);
      KSLog( @" > outside variable = %d" ,outsideVariable);
      KSLog( @" > inside variable = %d" ,insideVariable);
       [outsideArrayaddObject: @"AddedInsideBlock" ];
   };
   outsideVariable =  30 ;
   self.memberVariable =  30 ;
   blockObject();
   KSLog( @" > %d items in outsideArray" ,[outsideArray count]);
}
输出结果为:
  > membervariable =  30
  > outsidevariable =  30
  > insidevariable =  20
 >  1  items  in  outsideArray
注意到没? outside  变量的输出值为 10 ,虽然 outside 变量在定义  block  之后在定义  block  所在的方法  testAccessVariable  中被修改为  20  了。这里的规则就是: blockObject  在实现时会对  outside  变量进行只读拷贝,在  block  块内使用该只读拷贝。因此这里输出的是拷贝时的变量值  10 。如果,我们想要让  blockObject  修改或同步使用  outside  变量就需要用  __block  来修饰  outside  变量。
__block NSInteger outsideVariable=  10 ;
注意:
a) ,在上面的  block  中,我们往  outsideArray  数组中添加了值,但并未修改  outsideArray  自身,这是允许的,因为拷贝的是  outsideArray  自身。  
b) ,对于  static  变量,全局变量,在  block  中是有读写权限的,因为在  block  的内部实现中,拷贝的是指向这些变量的指针。
c)  __block  变量的内部实现要复杂许多, __block  变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针。
2 ,非内联( inline  block  不能直接访问  self ,只能通过将  self  当作参数传递到  block  中才能使用,并且此时的  self  只能通过  setter   getter  方法访问其属性,不能使用句点式方法。但内联  block  不受此限制。
block  内存管理分析
block  其实也是一个  NSObject  对象,并且在大多数情况下, block  是分配在栈上面的,只有当  block  被定义为全局变量或  block  块中没有引用任何  automatic  变量时, block  才分配在全局数据段上。  __block  变量也是分配在栈上面的。


block 注意事项
1,block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。
注意:
a),在上面的 block 中,我们往 outsideArray 数组中添加了值,但并未修改 outsideArray 自身,这是允许的,因为拷贝的是 outsideArray 自身。 
b),对于 static 变量,全局变量,在 block 中是有读写权限的,因为在 block 的内部实现中,拷贝的是指向这些变量的指针。
c), __block 变量的内部实现要复杂许多,__block 变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针。
block 内存管理分析
block 其实也是一个 NSObject 对象,并且在大多数情况下,block 是分配在栈上面的,只有当 block 被定义为全局变量或 block 块中没有引用任何 automatic 变量时,block 才分配在全局数据段上。 __block 变量也是分配在栈上面的。
在 ARC 下,编译器会自动检测为我们处理了 block 的大部分内存管理,但当将 block 当作方法参数时候,编译器不会自动检测,需要我们手动拷贝该 block 对象。
在 ARC 下,对 block 变量进行 copy 始终是安全的,无论它是在栈上,还是全局数据段,还是已经拷贝到堆上。对栈上的 block 进行 copy 是将它拷贝到堆上;对全局数据段中的 block 进行 copy 不会有任何作用;对堆上的 block 进行 copy 只是增加它的引用记数。
如果栈上的 block 中引用了__block 类型的变量,在将该 block 拷贝到堆上时也会将 __block 变量拷贝到堆上如果该 __block 变量在堆上还没有对应的拷贝的话,否则就增加堆上对应的拷贝的引用记数。
 

你可能感兴趣的:(Block(二))