原文参考博文:

http://blog.devtang.com/2013/07/28/a-look-inside-blocks/

http://www.cnblogs.com/kesalin/archive/2013/04/30/ios_block.html

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

关于闭包,可以理解成是一个函数(或指向函数的指针),再加上该函数执行的外部的上下文变量。

这里介绍关于block的:

1,内部实现,数据结构介绍

2,block 的三种类型及其相关的内存管理方式

3,block 如何通过 capture 变量来达到访问函数外的变量

一个 block 实际是一个对象,它主要由一个 isa 和 一个 impl 和 一个 descriptor 组成。更具体的说来,结构如下:

对应的结构体定义如下,

struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};

可以看出,主要包含6部分,

1,isa指针,所有对象都有这个指针。指向对象的类结构。

2,invoke指针,函数指针,指向具体的block实现的函数调用地址

3,variables,block 能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。

4,reserved,保留字段。5,flags,descriptions,一些附加描述信息,比如size等。

OC中,一共三种类型的block,

1,_NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。

2,_NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。

3,_NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

block对外部变量的引用:

主要包含2类,

1,对于 block 外的变量引用,block 默认是将其复制到其数据结构中来实现访问的。

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

=======

block使用时的几个注意点:

1,block中的变量拷贝,是在实现时,对引用到的它所在方法中定义的栈变量进行一次只读拷贝。

这个变量是只读的,比如

id result = nil;

[context performBlockAndWait:^{

result = block();

}];

会报错,variable is not assignable。

需要对其有写操作时,可以加__block。

2,非内联(inline)block 不能直接访问 self。

  这种情况,可以将self 当作参数传递到 block 中才能使用。而且这个时候self的属性,只能通过setter 或 getter方法访问,不能用点语法。

typedef NSString* (^IntToStringInlineConverter)(NSInteger paramInteger);

// 非内联block

IntToStringConverter independentBlockObject = ^(id self, NSInteger paramInteger) {
    KSLog(@" >> self %@, memberVariable %d", self, [self memberVariable]);
NSString *result = [NSString stringWithFormat:@"%d", paramInteger];
KSLog(@" >> independentBlockObject %@", result);
return result;
};

// 内联block,用到self则不需要传self,也可以用点语法。
- (void)testAccessSelf
{
// Independent
[self convertIntToString:20 usingBlockObject:independentBlockObject]; // Inline
IntToStringInlineConverter inlineBlockObject = ^(NSInteger paramInteger) {
KSLog(@" >> self %@, memberVariable %d", self, self.memberVariable);
NSString *result = [NSString stringWithFormat:@"%d", paramInteger];
KSLog(@" >> inlineBlockObject %@", result);
return result;
};
[self convertIntToStringInline:20 usingBlockObject:inlineBlockObject];
}

3,使用 weak–strong避免循环引用

  内联block直接使用self时,需要小心,避免循环引用。

  block的本质其实还是一个对象。当self强持有这个block,而这个block又强持有self时,就会导致循环引用。

  换句话也就是说,只有释放了self才可以释放被self强持有的block。但self又被block强持有,无法释放。

  

  __weak KSViewController * wself = self;
_observer = [[NSNotificationCenter defaultCenter]
addObserverForName:@"TestNotificationKey"
object:nil queue:nil usingBlock:^(NSNotification *n) {
KSViewController * sself = wself;
if (sself) {
NSLog(@"%@", sself);
}
else {
NSLog(@"<self> dealloc before we could run this code.");
}
}];

  weak-strong的作用是,

  外部传入一个self的弱引用。这样block对象并没有强持有self,当self被释放的时候,wself 变成 nil。这样已经可以解决循环引用的问题。

  但是为了在block运行过程中不至于出现wself被释放,所以一般会声明一个__strong的变量,持有wself。这样,在self被释放后,block可以本正常释放,sself也就被释放。

最新文章

  1. PHP 之 CURL 模拟登陆并获取数据
  2. MongoDB的真正性能-实战百万用户一-一亿的道具
  3. mac下配置openfire
  4. C# 统计程序执行时间
  5. Devexpress TreeList选择父级联动
  6. 中兴软件编程规范C/C++
  7. C# 四舍五入
  8. Entity Framework中编辑时错误ObjectStateManager 中已存在具有同一键的对象
  9. yii2配置表前缀
  10. loadrunner_analysis技巧_filter和group by
  11. Apache 2.x+jboss6.1反向代理session共享问题设置
  12. 关于“找不到附属汇编 Microsoft.VC90.CRT,上一个错误是 参照的汇编没有安装在系统上。”的解决
  13. HDU-4866-Shooting(函数式线段树)
  14. IOSi科研OS7 具体的使用说明的适应
  15. redis学习一
  16. Spring 4 MVC+Hibernate 4+MySQL+Maven使用注解集成实例
  17. input输入框自动填充黄色背景解决方案
  18. css实现多行文本溢出显示省略号(…)全攻略
  19. mysql第一课,数据库的简单简单操作方法(配图略虐狗)
  20. java通过反射拷贝两个对象的同名同类型变量

热门文章

  1. List&lt;T&gt;的对比
  2. HalconMFC(二)之VS2010下配置Halcon11教程
  3. CMT learning
  4. Sort Characters By Frequency
  5. js回车动态添加表格,右键动态删除表格行
  6. elasticsearch,python包pyes进行的处理
  7. css 修改滚动条
  8. Gnu C的不同于标准C的语法
  9. 使用 UnrealPak.exe 创建 Pak文件方法
  10. 面向小白的JS笔记 - #Codecademy#学习笔记