日志
+ (void)load
{
[RLMRealm defaultRealm];
}
// Global realm state
static std::mutex& s_realmCacheMutex = *new std::mutex();
......
RLMRealm *RLMGetThreadLocalCachedRealmForPath(std::string const& path) {
std::lock_guard<std::mutex> lock(s_realmCacheMutex); // <--- Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)
return [s_realmsPerPath[path] objectForKey:(__bridge id)pthread_self()];
}
最终的报错位置在这里,可以看出s_realmCacheMutex
是一个空对象,能看出是初始化出了问题。
可是为什么没有初始化成功呢?
C++的静态初始化与动态初始化
- static initialization: 静态初始化指的是用常量来对变量进行初始化,主要包括 zero initialization 和 const initialization,静态初始化在程序加载的过程中完成,对简单类型(内建类型,POD等)来说,从具体实现上看,zero initialization 的变量会被保存在 bss 段,const initialization 的变量则放在 data 段内,程序加载即可完成初始化,这和 c 语言里的全局变量初始化基本是一致的。
- dynamic initialization:动态初始化主要是指需要经过函数调用才能完成的初始化,比如说:
int a = foo()
,或者是复杂类型(类)的初始化(需要调用构造函数)等。这些变量的初始化会在 main 函数执行前由运行时调用相应的代码从而得以进行(函数内的 static 变量除外)。
需要明确的是:静态初始化执行先于动态初始化! 只有当所有静态初始化执行完毕,动态初始化才会执行。
Objective-C的静态库与动态库
静态库与动态库的区别在于:
一、静态库:链接时完整地拷贝至可执行文件中,被多次使用就有多份冗余拷贝。
二、动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存。
如果你在CocoaPods中使用了
use_frameworks!
,则Pods会将依赖库都打包成动态库
加载时序
静态库 + (void)load
-> C++静态全局变量的动态初始化 -> 动态库 + (void)load
-> main()
原因
不少人应该都猜出原因了吧,正是由于我在静态库的Load中初始化了Realm,导致Realm在获取互斥锁的时候出现了初始化失败。
解决方案
- 在+ (void)load中添加一个GCD异步任务,在异步中初始化Realm,此时GCD会将任务推迟到main之后执行。
- 改用动态库。
- 将Realm初始化延后。