📌往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)
📃 鸿蒙(HarmonyOS)北向开发知识点记录~
📃 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
📃 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
📃 嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
📃 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
📃 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
📃 记录一场鸿蒙开发岗位面试经历~
📃 持续更新中……
一、前言
承接上一篇iunknown.h,本文接着对iunknown.c中的实现进行分析。在分析iunknown的实现之前,先介绍一下关于iunknown的相关背景,便于读者对后续代码的理解。
二、IUnknown背景
要想清楚的理解IUnknown就必须知道COM标准到底是什么。
COM全称Component Object Model,即组件对象模型,这是一种遵循COM规范的面向对象编程技术。它包含了三个基本的接口类,分别是IUnknown、IClassFactory和IDispatch。除了IUnknown以外,在鸿蒙后续的代码中,我们也会看到IClassFactory和IDispatch的身影,这里先分析IUnknown。COM规定任何的组件或接口都必须从IUnknown继承,而我在对模块二后续代码的分析中发现了大量的案例,如PubSubInterface、IClientProxy、IServerProxy等。IUnknown包含三个函数,分别是QueryInterface、AddRef、Release。
QueryInterface:查询实现的接口类,需要注意查询完后要调用release解除引用
AddRef:增加引用计数
Release:减少引用计数
看到这里可能会很疑惑,引用计数是什么,有什么作用?我们为什么要使用引用计数?
引用计数牵涉到内存管理的概念,每增加1就代表当前组件被一个对象引用,每减少1就代表当前组件少一个引用者,当引用计数为0时,就代表已经没有对象使用它了,那么它的生命周期就到此结束,释放自己占用的资源。通过引用计数来管理自己的生命周期,不需要其他对象的干预,这种方式极大的减少了代码开发者的工作。这种方式就跟C++11中的智能指针一样,通过引用计数来控制对象的生命周期,减少开发者的工作,避免内存泄漏。
三、代码分析
- 宏定义分析
//从IUnknown实现类的子类对象T(通用宏)获取IUnknown接口对象的指针
#define GET_IUNKNOWN(T) (IUnknown *)(&((T).iUnknown))
- 函数实现分析
为IUnknown对象添加引用
//增加iUnknown接口的引用计数,当重新实现QueryInterface函数时,需要在新的QueryInterface中调用该函数
int IUNKNOWN_AddRef(IUnknown *iUnknown)
{
if (iUnknown == NULL) {
return EC_INVALID;
}
//返回IUnknownEntry类型的地址,通过iUnknown的地址推断
IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
entry->ref++;//引用计数加1
return entry->ref;
}
查询接口信息
/*
函数功能:查询接口信息
函数参数:@iUnknown:iUnknown对象
@ver:版本号
@target:返回需要的IUnknown的子类类型
函数返回:成功 返回EC_SUCCESS,失败 返回EC_INVALID
函数描述:
1.查询指定版本的IUnknown接口。
2.在获得IUnknown接口对象后,函数调用者使用QueryInterface将该对象转换为所需的子类类型,内部将转换为调用者所需的子类类型。
*/
int IUNKNOWN_QueryInterface(IUnknown *iUnknown, int ver, void **target)
{
//参数检查
if (iUnknown == NULL || target == NULL) {
return EC_INVALID;
}
//返回IUnknownEntry类型的地址,通过iUnknown的地址推断
IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
//判断版本信息是否有效
if ((entry->ver & (uint16)ver) != ver) {
return EC_INVALID;
}
if (ver == OLD_VERSION &&
entry->ver != OLD_VERSION &&
(entry->ver & (uint16)DEFAULT_VERSION) != DEFAULT_VERSION) {
return EC_INVALID;
}
//作为返回值
*target = iUnknown;
//添加引用
iUnknown->AddRef(iUnknown);
return EC_SUCCESS;
}
释放引用数
/*
函数功能:释放iUnknown对象的引用数
函数参数:@iUnknown:iUnknown对象
函数返回:成功 引用计数,失败 返回EC_INVALID
详细描述:
1.释放不再使用的IUnknown接口的引用
2.在系统提供的默认实现中,如果引用计数为0,则IUnknown接口对象和实现对象的内存不会被释放
*/
int IUNKNOWN_Release(IUnknown *iUnknown)
{
//参数检查
if (iUnknown == NULL) {
return EC_INVALID;
}
//转换为IUnknownEntry对象
IUnknownEntry *entry = GET_OBJECT(iUnknown, IUnknownEntry, iUnknown);
int ref = entry->ref - 1;//引用数-1
if (ref < 0) {
//存在异常
} else {
if (ref == 0) {
//iunknown对象的引用数为0,应删除
//在默认版本中,iunknown可能是全局变量,默认不删除。
} else {
entry->ref = ref;//更新计数
}
}
return ref;
}