Source Code Learning - BeeHive

BeeHive 是一款阿里开源的解耦框架,通过模块和服务(Service)的方式实现组件化。

Module 和 Service 的调用方式

Annotation(标注)方式

Service 与 Module 的调用方式类似,只是 Service 有两个参数 ServiceName (以 Protocol 方式表示)以及实现的 IMP,以模块的调用方式为例

@BeeHiveMod(ShopModule)

该宏的定义为

#define BeeHiveMod(name) \
class BeeHive; char * k##name##_mod BeeHiveDATA(BeehiveMods) = ""#name”";

#define BeeHiveDATA(sectname) __attribute((used, section("__DATA,"#sectname" ")))

将宏展开

class BeeHive;
char *kShopModule_mod __attribute(used, section("__DATA_,"BeehiveMods" ")) = “ShopModule"
宏 ## 和 # 的使用方式

‘#’ 参数字符串化

#define SINGLE_SHARP(x) #x
SINGLE_SHARP(hello)
// "hello"

‘## 连两个字符串

#define DOUBLE_SHARP(x, y) x##y
DOUBLE_SHARP("hello", "world");
// hello word
__attribute used
__attribute(used, section("__DATA_,"BeehiveMods" ")) = “ShopModule”

在Linux上这样的定义

#define __attribute_used__    __attribute__((__used__))

used 说明

`This attribute, attached to a function, means that code must be
 emitted for the function even if it appears that the function is
 not referenced.  This is useful, for example, when the function is
 referenced only in inline assembly.`

使用 used字段,即使没有任何引用,在Release 下也不会被优化

__attribute section
__attribute__((section("section_name")))

其作用是将作用的函数或数据放入指定名为 “section_name” 输入段。

__attribute constructor destructor

宏被定义后,数据被加载到指定段(即 BeehiveMods )中,之后就是加载这些模块

__attribute__((constructor))
void initProphet() {
    _dyld_register_func_for_add_image(dyld_callback);
}

attribute constructor 和 destructor 会在 main 函数之前,exit 之后执行

__attribute__((constructor))
static void beforeMain(void) {
    NSLog(@"beforeMain");
}
__attribute__((destructor))
static void afterMain(void) {
    NSLog(@"afterMain");
}
int main(int argc, const char * argv[]) {
    NSLog(@"main");
    return 0;
}
// "beforeMain" -> "main" -> "afterMain"

使用项目
ProtocolKit

_dyld_register_func_for_add_image

/*

  • The following functions allow you to install callbacks which will be called
  • by dyld whenever an image is loaded or unloaded. During a call to _dyld_register_func_for_add_image()
  • the callback func is called for every existing image. Later, it is called as each new image
  • is loaded and bound (but initializers not yet run). The callback registered with
  • _dyld_register_func_for_remove_image() is called after any terminators in an image are run
  • and before the image is un-memory-mapped.
    */

_dyld_register_func_for_add_image 注册 image 文件装载回调方法,每个已经被加载的 image 文件都会调用回调方法,之后注册的 image 文件也会执行该回调

通过 getsectiondata 方法获取 __DATA 段中的指定段 BeehiveMods 中的数据

const struct mach_header_64 *mhp64 = (const struct mach_header_64 *)mhp;
uintptr_t *memory = (uintptr_t*)getsectiondata(mhp64, SEG_DATA, sectionName, &size);

intptr_t 和uintptr_t 类型用来存放指针地址。它们提供了一种可移植且安全的方法声明指针,而且和系统中使用的指针长度相同,对于把指针转化成整数形式来说很有用。[详见 《深入理解C指针》]

对 memory 指针进行处理后,获取到 BeehiveMods 段中的类名数组即根据类名进行注册

静态方式注册

通过 plist 模块 - BeeHive.plist,Service - BHService.plist 中注册

Beehive 在 初始化 context 的时候加载这些 plist

Load 方法注册

+ (void)load {
    [BeeHive registerDynamicModule:[self class]];
}

事件处理

模块会收到一些事件,如果需要将 AppDelegate 中的事件分发到各个模块中,需要继承 BHAppDelegate 用它来托管,对应模块实现事件需要遵守的协议即可

PS:
模块 (Module) 和组件 (Comonent) 的区别,模块强调职责的分离,组件强调复用。

参考文章
Beehive 原理
Beehive PPT
GCC Attributes

请我喝汽水儿