Weak的实现-&SideTables()[oldObj]
&SideTables()[oldObj]这是什么?很多人看到这里都被这操作搞蒙了,下面分三步来理解,分别是SideTables()、[oldObj]、&。先贴上入口的代码
id oldObj;
SideTable *oldTable;
oldObj = *location;
oldTable = &SideTables()[oldObj];
1. 理解SideTables()
首先SideTables()是一个静态函数,完全体是这样的
static StripedMap<SideTable>& SideTables() {
return SideTablesMap.get();
}
函数体里面调用了一个全局的静态变量SideTablesMap的get()方法,
静态变量里面保存了所有的SideTable。的声明如下:
static objc::ExplicitInit<StripedMap<SideTable>> SideTablesMap;
可以看出SideTablesMap是在命名空间objc下面的一个ExplicitInit类,它里面实现了get()方法,如下
Type &get() {
return *reinterpret_cast<Type *>(_storage);
}
对于不熟悉c++的理解下面这几点基本就能看懂:
- c++ 中的引用
&,在c++中&除了有取地址的作用还可以作为引用。方法返回的是一个引用,如果没有c++基础的很容易误认为返回了一个指针。 - c++中的模板
template,泛型Type是通过模板传入的,即StripedMap。 从上面声明SideTablesMap的地方可以看到,这里是个模板的嵌套,StripedMap是ExplicitInit模板的泛型;SideTable是StripedMap模板的泛型。 - c++中的
reinterpret_cast<new_type>(expression),它可以将两种任何类型进行转换,新值和旧值(expression)有相同的比特位。
最后用*取转换后得到的地址的所保存的值,返回,所以说这里返回的不是指针。
Type *就相当于StripedMap *,所以get()方法返回的就是StripedMap结构体实例。
2. 理解[oldObj]
这里的[]其实是对[]进行了重载
T& operator[] (const void *p) {
return array[indexForPointer(p)].value;
}
在indexForPointer()方法里,先将结构体指针oldObj转化成和其有相同比特位的地址,再进行位移、异或、去模操作得到一个从0-63位之间的index,通过index,拿到数组里面的PaddedT结构体,返回该结构体的value成员即结构体SideTable。
static unsigned int indexForPointer(const void *p) {
uintptr_t addr = reinterpret_cast<uintptr_t>(p);
return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
}
struct PaddedT {
T value alignas(CacheLineSize);
};
其实StripedMap是一个以void *p为key,PaddedT为value的的表。
3. &
最后对SideTables()[oldObj]即SideTable取地址,这样就和SideTable *newTable;对上了。