Object-C高级编程读书笔记(2)——Block的实质

2023-10-17 19:30

本文主要是介绍Object-C高级编程读书笔记(2)——Block的实质,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

按照OC高级编程书中所说,所谓Block实质就是Object-C对象

如何理解这句话呢?应该从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                                       对象的sizestruct 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__类的对象。

这篇关于Object-C高级编程读书笔记(2)——Block的实质的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/227475

相关文章

Python中列表的高级索引技巧分享

《Python中列表的高级索引技巧分享》列表是Python中最常用的数据结构之一,它允许你存储多个元素,并且可以通过索引来访问这些元素,本文将带你深入了解Python列表的高级索引技巧,希望对... 目录1.基本索引2.切片3.负数索引切片4.步长5.多维列表6.列表解析7.切片赋值8.删除元素9.反转列表

深入探讨Java 中的 Object 类详解(一切类的根基)

《深入探讨Java中的Object类详解(一切类的根基)》本文详细介绍了Java中的Object类,作为所有类的根类,其重要性不言而喻,文章涵盖了Object类的主要方法,如toString()... 目录1. Object 类的基本概念1.1 Object 类的定义2. Object 类的主要方法3. O

正则表达式高级应用与性能优化记录

《正则表达式高级应用与性能优化记录》本文介绍了正则表达式的高级应用和性能优化技巧,包括文本拆分、合并、XML/HTML解析、数据分析、以及性能优化方法,通过这些技巧,可以更高效地利用正则表达式进行复杂... 目录第6章:正则表达式的高级应用6.1 模式匹配与文本处理6.1.1 文本拆分6.1.2 文本合并6

C#反射编程之GetConstructor()方法解读

《C#反射编程之GetConstructor()方法解读》C#中Type类的GetConstructor()方法用于获取指定类型的构造函数,该方法有多个重载版本,可以根据不同的参数获取不同特性的构造函... 目录C# GetConstructor()方法有4个重载以GetConstructor(Type[]

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念