关于objc_runtime关联对象

2018-03-29  本文已影响0人  LikeSnooker

关联对象,按字面理解 无非就是将两个对象关联起来。'关联'可以联想到映射,能完成这件事情的,首先想到的数据结构就是hash_map。事实上objc_runtime就是这么做的。
有了思路,我们就可以自己动手了。思路大概是这样的,我们现在要实现为一个对象去关联多个对象,这些多个对象通过不同的KEY值来存取。这样的话,一张hash表似乎是不行的。一张表只能完成一个对象到一个对象的映射。如果思路受阻,请默念下面这段话三次。

All problems in computer science can be solved by another level of indirection,
except of course for the problem of too many indirections.

一张表不行,我们可以维护这样一张表,他将每个对象映射到一张表,而映射到的表分别将不同的KEY映射到不同的对象。这样就实现了将一个对象通过不同的KEY关联到另一个对象。这里涉及 TARGET(被关联的对象) KEY(键) OBJECT(关联对象)。

typedef long TARGET;
typedef long KEY;
typedef long OBJECT;

这里全都用了long型,为什么用long型呢?(这里似乎是应该用 void *更合理嘛)。因为c++库中的hash_map需要提供两个函数对象 ,分别用来比较KEY值大小和计算KEY的哈希值(方便在hash_map中储存自定义类型)。而long型是基本类型,省去了这样的麻烦。另外就是long 在计算机中是8字节,现在大部分pc都是64位,指针也是8字节,内存模型匹配,我们可以通过类型转换来处理这个问题。是不是很讨巧呢。

typedef hash_map<TARGET,hash_map<KEY,OBJECT> > MAP;
typedef hash_map<KEY,OBJECT>             ASSOCIATION_MAP;

我们将总表的类型定义为MAP,而具体的KEY->OBJECT的映射表定义为ASSOCIATION_MAP;
好了,话不多说,直接看代码,相当简单的代码:

#include <iostream>
#include <map>
#include <ext/hash_map>

using __gnu_cxx::hash_map;
using __gnu_cxx::pair;
typedef long TARGET;
typedef long KEY;
typedef long OBJECT;
typedef hash_map<TARGET,hash_map<KEY,OBJECT> > MAP;
typedef hash_map<KEY,OBJECT>             ASSOCIATION_MAP;
typedef pair<TARGET,hash_map<KEY,OBJECT>>      TARGET_ASSOCIATIONMAP;
typedef pair<KEY,OBJECT>                       KEY_OBJECT;

class AssociationManager
{
public:
    static MAP & manager()
    {
        return AssociationManager::association;
    }
private:
    static MAP association;
private:
    AssociationManager ()
    {
        
    }
};
MAP AssociationManager::association = MAP();
OBJECT getAssociated(TARGET target,KEY key)
{
    OBJECT result = 0;
    MAP &map(AssociationManager::manager());
    MAP::iterator it = map.find(target);
    if(it != map.end())
    {
        ASSOCIATION_MAP &ass_map(it->second);
        ASSOCIATION_MAP::iterator ass_map_it = ass_map.find(key);
        if(ass_map_it != ass_map.end())
        {
            return ass_map_it->second;
        }
    }
    return result;

}
void setAssociate(TARGET target,KEY key,OBJECT objc)
{
    MAP &map(AssociationManager::manager());
    MAP::iterator it = map.find(target);
    if(it == map.end())
    {
        ASSOCIATION_MAP ass_map;
        ass_map.insert(KEY_OBJECT(key,objc));
        map.insert(TARGET_ASSOCIATIONMAP(target,ass_map));
    }
    else
    {
        (it->second).insert(KEY_OBJECT(key,objc));
    }

}
class CTarget
{
public:
    int index;
};
class CObject
{
public:
    int number;
};
int main(int argc, const char * argv[]) {
    CTarget * p_target = new CTarget;
    p_target->index    = 1;
    CObject * p_object = new CObject;
    p_object->number   = 2;
    
    static char  key[10] = "hello_map";
    // setAssociate
    setAssociate((TARGET)p_target, (KEY)key, (OBJECT)p_object);
    
    // getAssociated
    CObject * p_obj = (CObject*)getAssociated((TARGET)p_target, (KEY)key);
    
    // test
    std::cout << "关联对象.number = "<<p_obj->number << std::endl;
    std::cout << "Hello, World!\n";
    return 0;
}

我们实现了两个函数getAssociated 和setAssociate,接着我们定义了两个类,在main函数中,我们通过两个函数将两个对象关联,并随后通过第一个对象成功取出关联的对象。为了只表达出思路,代码写的十分精简,点到为止。方便阅读。当然objc_runtime在实现的时候,还需要考虑到存取策略等一些列的问题。

上一篇下一篇

猜你喜欢

热点阅读