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