Object-C高级编程读书笔记(2)——Block的实质
2016-03-08 23:10
411 查看
按照OC高级编程书中所说,所谓Block实质就是Object-C对象。
如何理解这句话呢?应该从OC的类对象所拥有的特征入手,如果Block同样拥有这些特征,那么Block当然也就是OC的对象。
我们知道,在OC中,基本上所有的类,最终都有一个相同的父类NSObject,查看NSObject定义,发现其只有一个Class类型的变量isa
而Class类型则为
通过注释,可得知Class类型就是OC中的一个统一的类类型,及通过isa变量,可以区分不同对象所属的具体的类的类别。
再看objc_class 的定义
其中还有个isa, 递归定义,应该是对自己的一个说明。再看其余变量,
以上这些内容,也能够说明该类是个什么样子了,因此,OC对象通过继承NSObjec的Class类型的isa变量,并在isa变量中填写自身类的相关信息,OC运行时就可以通过OC对象中的isa变量,来辨别该对象属于哪个具体的类了。
那么,反过来说,如果一个对象,具有isa变量,则就可以说是OC对象了。(OC运行时通过isa来辨别该对象的具体类)。
因此,证明Block本质是一个OC对象这个问题,就转换为了Block对象是否含有isa变量这个问题。
原始OC代码
转换后的C++代码,
主要看Block类型变量,转换为了__main_block_impl_0的结构体类型,
而__main_block_impl_0的结构体 定义如下
可以看到结构体主要是包含一个结构体变量和一个指向结构体变量的指针,
重点再看imply对应得struct类型__block_impl
Flags和Reserved分别对应标记位和保留位置,我们不去管它们。
而isa的出现,则说明了Block类型对象,同样含有isa变量,即Block变量同样使用了isa变量来保存其类的信息,即是说明,Block对象,也是一种OC类对象(这点我们稍后证明)。
FuncPtr的作用很明显,就是指向了Block变量所应该执行的函数的地址,运行Block,实际上就是执行Block对象中FuncPtr函数指针所指向的函数。
struct __block_impl 与 struct __main_block_desc_0*,通过查看struct __block_impl类型,可知其中有两个较为重要的变量
void *isa(证明Block变量是OC类变量的一种), FuncPtr(Block函数实现的机制)。
下面通过代码及断点,观察blk变量的结构,确实也证明了上面的说法。
可以看到,Block对象blk含有成员变量__isa, _FuncPtr, _flags, _reserved, __descriptor,这和我们上面关于__main_block_impl_0结构体的描述相吻合,同时可以知道,blk变量,在这里是属于__NSGlobalBlock__类的对象。
如何理解这句话呢?应该从OC的类对象所拥有的特征入手,如果Block同样拥有这些特征,那么Block当然也就是OC的对象。
Object-C对象
在OC中,我们可以用id类型来统一代表所有的OC对象类型。那OC运行时又是如何知道id所指向的对象类型具体是那种呢?我们知道,在OC中,基本上所有的类,最终都有一个相同的父类NSObject,查看NSObject定义,发现其只有一个Class类型的变量isa
@interface NSObject <NSObject> { Class isa OBJC_ISA_AVAILABILITY; }
而Class类型则为
/// An opaque type that represents an Objective-C class. typedef struct objc_class *Class;
通过注释,可得知Class类型就是OC中的一个统一的类类型,及通过isa变量,可以区分不同对象所属的具体的类的类别。
再看objc_class 的定义
struct objc_class { Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; const char *name OBJC2_UNAVAILABLE; long version OBJC2_UNAVAILABLE; long info OBJC2_UNAVAILABLE; long instance_size OBJC2_UNAVAILABLE; struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; struct objc_method_list **methodLists OBJC2_UNAVAILABLE; struct objc_cache *cache OBJC2_UNAVAILABLE; struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; #endif } OBJC2_UNAVAILABLE;
其中还有个isa, 递归定义,应该是对自己的一个说明。再看其余变量,
<pre name="code" class="objc"> const char *name 类名称 long version 版本 long info 信息
long instance_size 对象的size struct objc_ivar_list *ivars 对象变量列表 struct objc_method_list **methodLists 对象方法列表 struct objc_cache *cache struct objc_protocol_list *protocols 对象遵循的protocol列表
以上这些内容,也能够说明该类是个什么样子了,因此,OC对象通过继承NSObjec的Class类型的isa变量,并在isa变量中填写自身类的相关信息,OC运行时就可以通过OC对象中的isa变量,来辨别该对象属于哪个具体的类了。
那么,反过来说,如果一个对象,具有isa变量,则就可以说是OC对象了。(OC运行时通过isa来辨别该对象的具体类)。
因此,证明Block本质是一个OC对象这个问题,就转换为了Block对象是否含有isa变量这个问题。
从Block的C++代码实现看Block的本质
OC高级编程中,作者通过clang命令,将OC代码编译为C++代码,原始OC代码
int main(){ void(^blk)(void) = ^{ printf("Block\n"); }; blk(); return 0; }
转换后的C++代码,
主要看Block类型变量,转换为了__main_block_impl_0的结构体类型,
int main(){ void(*blk)(void) = (void(*)(void))&__main_block_impl_0(__main_block_func_0, __main_block_desc_0_DATA); }
而__main_block_impl_0的结构体 定义如下
struct __main_block_imp_0{ struct __block_impl imply; struct __main_block_desc_0 *Desc; // 构造函数 省略 };
可以看到结构体主要是包含一个结构体变量和一个指向结构体变量的指针,
struct __block_impl imply;
struct __main_block_desc_0 *Desc从名字就可以看出,imply主要涉及Block的实现相关信息,而Desc指针则是对于block的描述,这里不重要不研究它。
重点再看imply对应得struct类型__block_impl
struct __block_impl { void *isa; int Flags; int Reserved; void *FuncPtr; };
Flags和Reserved分别对应标记位和保留位置,我们不去管它们。
而isa的出现,则说明了Block类型对象,同样含有isa变量,即Block变量同样使用了isa变量来保存其类的信息,即是说明,Block对象,也是一种OC类对象(这点我们稍后证明)。
FuncPtr的作用很明显,就是指向了Block变量所应该执行的函数的地址,运行Block,实际上就是执行Block对象中FuncPtr函数指针所指向的函数。
总结
在这里稍稍总结一下,通过clang,我们将OC代码转换为C++代码,发现Block变量被声明为了__main_block_impl_0结构体,而该结构体包含两个类型的成员变量struct __block_impl 与 struct __main_block_desc_0*,通过查看struct __block_impl类型,可知其中有两个较为重要的变量
void *isa(证明Block变量是OC类变量的一种), FuncPtr(Block函数实现的机制)。
下面通过代码及断点,观察blk变量的结构,确实也证明了上面的说法。
#import <Foundation/Foundation.h> int main(int argc, const char * argv[]) { @autoreleasepool { void(^blk)(void) = ^{printf("Block\n");}; blk(); } return 0; }
可以看到,Block对象blk含有成员变量__isa, _FuncPtr, _flags, _reserved, __descriptor,这和我们上面关于__main_block_impl_0结构体的描述相吻合,同时可以知道,blk变量,在这里是属于__NSGlobalBlock__类的对象。
相关文章推荐
- Ruby中Block和迭代器的使用讲解
- Ruby中使用Block、Proc、lambda实现闭包
- Ruby中的block、proc、lambda区别总结
- 全面解析Objective-C中的block代码块的使用
- block 实现原理详解(一)
- iOS页面传值总结
- ios高效开发二--ARC跟block那点事
- EOP / Office 365: Block or Allow IP Address in Connection Filtering
- objective-c block 讲解
- oc入门基础
- IOS block的学习
- iOS控件篇之——UILabel
- block && Grand Central Dispatch
- object-c学习笔记
- 随机颜色及大小方框首页
- 代理 通知 Block区别
- 代理 通知 Block区别
- Hadoop MapReduce中如何处理跨行Block和InputSplit
- Object-C学习笔记之基础知识一
- Block 的循环引用:如何产生 和 解决办法