block研究

上传人:今*** 文档编号:106895870 上传时间:2019-10-16 格式:PPT 页数:23 大小:1.36MB
返回 下载 相关 举报
block研究_第1页
第1页 / 共23页
block研究_第2页
第2页 / 共23页
block研究_第3页
第3页 / 共23页
block研究_第4页
第4页 / 共23页
block研究_第5页
第5页 / 共23页
点击查看更多>>
资源描述

《block研究》由会员分享,可在线阅读,更多相关《block研究(23页珍藏版)》请在金锄头文库上搜索。

1、探求Objective-c中Block的实现,关于Block和C语言闭包,闭包是可以包含自由(未绑定到特定对象)变量的代码块; 这些变量不是在这个代码块内或者任何全局上下文中定义的,而是在定义代码块的环境中定义。 “闭包”一词来源于以下两者的结合:要执行的代码块(由于自由变量被包含在代码块中,这些自由变量以及它们引用的对象没有被释放)和为自由变量提供绑定的计算环境(作用域)。 在 Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python,objective c 等语言中都能找到对闭包不同程度的支持。,闭包,Object

2、ive c 中的的闭包,是通过block实现的。Apple在C,Objective-C和C+中扩充了Block这种文法的,并且在GCC4.2中进行了支持。你可以把它理解为函数指针,匿名函数,闭包,lambda表达式,这里暂且用块对象来表述,因为它们之间还是有些许不同的。 如果以内联方式使用块对象,则无需声明。块对象声明语法与函数指针声明语法相似,但是块对象应使用脱字符()而非星号指针 (*);,Objective-c中的闭包,对比参考:函数指针 函数指针的声明方法为: 函数类型 (标志符指针变量名) (形参列表); int func(int x); /* 声明一个函数 */ int (*f)

3、(int x); /* 声明一个函数指针 */ f = func; /* 将func函数的首地址赋给指针f */,Block与函数指针的异同,关于Block的内部实现,1.命名规则,会产生对应的3个函数: _maxBlk_block_func_0 _main_block_func_0 _main_block_func_1 可见函数的命名规则为:_$Scope_block_func_$index。,研究工具:clang 为了研究编译器是如何实现block的,我们需要使用clang。clang提供一个命令, 可以将Objetive-C的源码改写成c语言的,借此可以研究block具体的源码实现方式。

4、该命令是 clang -rewrite-objc block.c,Block结构体的实现: 以下代码为例: int i = 1024; void(blk)(void) = printf(“%dn“, i); ; 3 blk(); BLOCK的实现 #ifndef BLOCK_IMPL #define BLOCK_IMPL struct_block_impl void *isa; /结构体的类型 int Flags; /标志位 int Reserved; /保留位 void *FuncPtr; /见_main_block_func_0 ; / 省略部分代码 #endif,struct Block

5、_descriptor unsigned long int reserved; unsigned long int size; void (*copy)(void *dst, void *src); void (*dispose)(void *); ; struct Block_layout void *isa; int flags; int reserved; void (*invoke)(void *, .); struct Block_descriptor *descriptor; /* Imported variables. */ ;,对应的结构体定义如下:,通过该图,我们可以知道,一

6、个block实例实际上由6部分构成:,isa指针,所有对象都有该指针,用于实现对象相关的功能。 flags,用于按bit位表示一些block的附加信息. reserved,保留变量。 invoke,函数指针,指向具体的block实现的函数调用地址。 descriptor, 表示该block的附加描述信息,主要是size大小,以及copy和dispose函数的指针。 variables,capture过来的变量,block能够访问它外部的局部变量,就是因为将这些变量(或变量的地址)复制到了结构体中。,在Objective-C语言中,一共有3种类型的block: _NSConcreteGlobal

7、Block 全局的静态block, 不会访问任何外部变量。 _NSConcreteStackBlock 保存在栈中的block, 当函数返回时会被销毁。 _NSConcreteMallocBlock 保存在堆中的block, 当引用计数为0时会被销毁。,NSConcreteStackBlock 类型的block的实现 int main() int a = 100; void (block2)(void) = printf(“%dn“, a); ; block2(); return 0; ,struct _main_block_impl_0 struct _block_impl impl; st

8、ruct _main_block_desc_0* Desc; int a; / 这里是对block之外的变量a的值拷贝 _main_block_impl_0(void *fp, struct _main_block_desc_0 *desc, int _a, int flags=0) : a(_a) impl.isa = ,int main() int a = 100; void (block2)(void) = printf(“%dn“, a); ; block2(); return 0; ,C语言中的实现 int main() int a = 100; void (*block2)(voi

9、d) = (void (*)() ,如何修改作用域外的变量,int main() _block int i = 1024; void (block1)(void) = printf(“%dn“, i); i = 1023; ; block1(); return 0; ,对于block外的变量引用,block默认是将其复制到其数据结构中来实现访问的,如下图所示 对于用_block修饰的外部变量引用,block是复制其引用地址来实现访问的,如下图所示,struct _Block_byref_i_0 void *_isa; _Block_byref_i_0 *_forwarding; int _fl

10、ags; int _size; int i; ; struct _main_block_impl_0 struct _block_impl impl; struct _main_block_desc_0* Desc; _Block_byref_i_0 *i; / by ref _main_block_impl_0(void *fp, struct _main_block_desc_0 *desc, _Block_byref_i_0 *_i, int flags=0) : i(_i-_forwarding) impl.isa = ,static void _main_block_copy_0(s

11、truct _main_block_impl_0*dst, struct _main_block_impl_0*src) _Block_object_assign(void*),_Block_byref_i_0 描述Block的结构体,Objective-c 代码,int main() _block int i = 1024; void (block1)(void) = printf(“%dn“, i); i = 1023; block1(); return 0; ,转换之后的c代码 int main() _attribute_(_blocks_(byref) _Block_byref_i_0

12、 i = (void*)0,(_Block_byref_i_0 *) /,Block的拷贝,错误实例: - (void)viewDidLoad UIButton *btn = UIButton buttonWithType: UIButtonTypeRoundedRect; btn addTarget: self action: selector(btnClick:) forControlEvents:UIControlEventTouchUpInside; self.view addSubview: btn; _blockint val = 10; tempBlock = NSLog(“va

13、l = %d“, +val); - (void) btnClick: (id) Sender tempBlock(); 修改之后: tempBlock = NSLog(“val = %d“, +val); retain;,修改措施,blk stackBlock = NSLog(“val = %d“, +val); tempBlock = stackBlock copy;,_NSStackBlock_,_NSMallocBlock_,- (blk) myTestBlock _block int val = 10; blk stackBlock = NSLog(“val = %d“, +val);

14、 return stackBlock copy autorelease; ,在把block对象外传的时候,我们要传出一个经过copy, 再autorelease的block在堆上的_NSMallocBlock_对象。,一个会有内存问题的例子,interface KSViewController () id _observer; end implementation KSViewController - (void)viewDidLoad super viewDidLoad; / Do any additional setup after loading the view, typically

15、from a nib. _observer = NSNotificationCenter defaultCenter addObserverForName:“TestNotificationKey“ object:nil queue:nil usingBlock:(NSNotification *n) NSLog(“%“, self); ; - (void)dealloc if (_observer) NSNotificationCenter defaultCenter removeObserver:_observer; ,一个会有内存问题的例子(修改后),_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(“

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号