语言英语语法极速通关26|从句的简化

目录

  • 简介
  • Runtime中之组成部分数据结构
  • 消息转发
  • 涉及对象的贯彻原理

简介

为Objc是平派动态语言,所以它连接惦记方法把有些操纵工作于编译连接推迟到运行时。也就是说只有编译器是不够的,还用一个运转时系统
(runtime system) 来实行编译后底代码。这便是 Objective-C Runtime
系统有的意思,它是全方位 Objc 运行框架的一样片基石。

Runtime其实有点儿个本子: “modern” 和 “legacy”。我们本因此之 Objective-C
2.0 采用的是本 (Modern) 版的 Runtime 系统,只能运行在 iOS 和 macOS
10.5 之后的 64 位程序中。而 maxOS 较老的32各程序按照使 Objective-C 1
中的(早期)Legacy 版本的 Runtime
系统。这简单单版最可怜的分别在当您再度改一个看似的实例变量的布局时,在最初版本被你得再编译它的子类,而如今版虽无欲。

于OC中调用一个函数,其实就是是向阳一个靶(类为是一个对象)发送一漫长信息,比如:
[receiver message]
见面被编译器转化为
objc_msgSend(receiver, selector)
了解Runtime其实就是了解OC动态特性的底部实现,这对于我们了解OC这门语言很有必不可少。

脚,你可下载runtime的源码下一场来与自己一块探究

目录

一样、Runtime中的有些数据结构

先是,在runtime源码的objc-private.h文件被我们好看看目标以及好像都是一个结构体:

目标和类似的概念

接触进入我们一个一个查看

对象的结构体

足见到,对象要就是一个饱含isa变量的结构体,这个变量主要就是是带有一个指向Class的指针。

isa_t

再度来探望Class结构体的切切实实定义。
每当objc-runtime-old.h中,它要涵盖这样有数据结构:

struct objc_class : objc_object {
    //继承自objc_object的isa指针
    Class superclass;                       //指向父类的指针
    const char *name;                       //类名
    uint32_t version;                       //类的版本信息
    uint32_t info;                          //类信息,提供一些运行期使用的一些标示位
    uint32_t instance_size;                 //类的实例变量的大小
    struct old_ivar_list *ivars;            //类的成员变量链表
    struct old_method_list **methodLists;   //方法定义的链表
    Cache cache;                            //方法缓存(用于消息发送时的查找)
    struct old_protocol_list *protocols;    //协议链表
}

得视,objc_class是延续自objc_object的,所以别忘了,objc_class也时有发生一个isa指针。为什么类为发生isa指针呢?我前的文章已关系过,在开立类的时段,Runtime其实创建了元类(Meta
Class),,所以类似对象的所属种类就是元类,具体信息方可参考这首文章。关于类的信通通有是数据结构中,操作类其实就是操作是结构体。
而是就是前的runtime实现,现行版的Runtime源码在objc-runtime-new.h中:

今昔版的Class结构体

相同、从句简化的概念

英语受到的老三杀从句(名词性从句、副词性从句、形容词性从句)在前头都逐一作了介绍。但是我们在英语阅读中会发现,构造完整的由句很少会看到,总看缺少了碰啊,也扣不发出它究竟是只什么由句。

招这种场面之案由是,主句和于句以意义、内容达到是起关联的,这即招其中免不了会生出重新的定义出现。为了要句子显得简练,人们常常会看略掉起句被再的、无意义的一部分。

习俗语法对这种场面往往可基本上说,而是创造了各种概念:非谓语动词、同位语、独立短语等等。实际上,这些概念都能通过打句之简化来解释,并且,如果我们清楚了于句简化的条条框框,这些混乱的定义一个还未用记。

首先,我们经过一个例来拘禁打句的简化究竟是怎一转头事。

设发生三单句子:

I avoid something.

I am caught.

I am unprepared.

当下三独句子都是最为中心的简易句,意思虽然说清楚了,但是来得煞是“low”。作文要是如此写的口舌,估计老师只能让个辛苦分。

不难看出,这三词话实际还当说及一个主题,那么我们不怕足以以那个改变写成一个复句:

I avoid that I am caught when I am unprepared.

是复句里,既来that因势利导之名词性从句,又有when带的副词性从句,的确是于三个大概句“高级”了好几。但是这样的语句依然得不了高分,因为极度啰嗦。

再进一步分析,我们发现主句和有限个自句的主语都是均等的;两只从句的谓语动词都是纸上谈兵的be动词;连接词that没有实际意义;连接词when虽然发出意味“当…的上”的义,但也非是非要不可。

因而,上面这些重新的、无意义的、可发生可不管的物都得以通探视略掉:

I avoid being caught unprepared.

转看这个词单词少,但眼看才是真的“高大上”,它亦可用极端明确的语言表达清楚复杂的意义,可以说凡是英文作文之危境界。

如今晓为什么当英语阅读着寻觅不交组织总体的打句了吧?不是为作者没有行使从句,而是为这些由句或多或少都经了简化。

cacge_t

cacge_t

cache_t,顾名思义,其实就是缓存,对许受老版的cache。
_buckets 存储IMP_mask_occupied 对应 vtable

bucket_t

bucket_t

bucket_t 中不怕是储存了指针与 IMP
的键值对,以当艺术寻找的时光能针对缓存过的措施进行快捷响应。

class_data_bits_t

objc_class中最背之虽是bits,对类似的操作几乎就是是围绕她进行

struct class_data_bits_t {
    // Values are the FAST_ flags above.
    uintptr_t bits;
    class_rw_t* data() {
        return (class_rw_t *)(bits & FAST_DATA_MASK);
    }
}

组合前面objc_classdata方,就是直以 class_data_bits_t
data 方法返回,返回的凡
class_rw_t型,而以此价是bits与FAST_DATA_MASK按位与取的结果。bits在内存中每个位的意思如下:

32位:

32位

64位兼容版:

64号兼容版

64号不兼容版:

64各类非兼容版

其间64各项不兼容版每个宏对应如下:

// class is a Swift class
#define FAST_IS_SWIFT           (1UL<<0)
// class's instances requires raw isa
#define FAST_REQUIRES_RAW_ISA   (1UL<<1)
// class or superclass has .cxx_destruct implementation
//   This bit is aligned with isa_t->hasCxxDtor to save an instruction.
#define FAST_HAS_CXX_DTOR       (1UL<<2)
// data pointer
#define FAST_DATA_MASK          0x00007ffffffffff8UL
// class or superclass has .cxx_construct implementation
#define FAST_HAS_CXX_CTOR       (1UL<<47)
// class or superclass has default alloc/allocWithZone: implementation
// Note this is is stored in the metaclass.
#define FAST_HAS_DEFAULT_AWZ    (1UL<<48)
// class or superclass has default retain/release/autorelease/retainCount/
//   _tryRetain/_isDeallocating/retainWeakReference/allowsWeakReference
#define FAST_HAS_DEFAULT_RR     (1UL<<49)
// summary bit for fast alloc path: !hasCxxCtor and 
//   !instancesRequireRawIsa and instanceSize fits into shiftedSize
#define FAST_ALLOC              (1UL<<50)
// instance size in units of 16 bytes
//   or 0 if the instance size is too big in this field
//   This field must be LAST
#define FAST_SHIFTED_SIZE_SHIFT 51

可见到,这其中除了FAST_DATA_MASK
是一模一样段落控件存储数据外,其它都是为此1bit来存储bool值保存信息class_data_bits_t提供了三只方式用于各类操作:getBit,setBitsclearBits,对承诺到每个bool值的掩码都来函数封装,如:

    bool hasDefaultRR() {
        return getBit(FAST_HAS_DEFAULT_RR);
    }
    void setHasDefaultRR() {
        setBits(FAST_HAS_DEFAULT_RR);
    }
    void setHasCustomRR() {
        clearBits(FAST_HAS_DEFAULT_RR);
    }

具体的公可望源码,我就无详细贴出了。

前我们说了,这个data回到的凡bitsFAST_DATA_MASK各队和收获的价,而这边FAST_DATA_MASK骨子里就囤了负于class_rw_t的指针。

class_rw_t

class_rw_t

新一拘留,这个仿佛是存储类的办法、属性、协议等的,但是咱来看,这里还有一个class_ro_t,再累看

class_ro_t

class_ro_t

梳理一下,全部结构是如此的objc_class包含了class_data_bits_tclass_data_bits_t存储了class_rw_t的指针,而class_rw_t结构体又噙class_ro_t指针。lass_ro_t中的method_list_t,
Ivar_list_t,property_list_t
结构体都继承自entsize_list_tt<Element, List, FlagMask>。结构为xxx_list_t的列表元素结构也xxx_t,命名很整齐。protocol_list_t
与前方三独不等,它存储的是protocol_t *指南针列表,实现比较简单。

entsize_list_tt落实了 non-fragile特性的数组结构。假如苹果在新本子的
SDK 中向
NSObject恍如增加了一部分情节,NSObject的挤占的内存区域会扩张,开发者以前编译出底二进制中的子类就见面暨新的
NSObject
内有着重叠部分。于是当编译期会受instanceStartinstanceSize赋值,确定好编译时每个接近的所占内存区域开始偏移量和分寸,这样才需要用子类与基类的当即点儿只变量作比即可知道子类是否跟基类有层,如果发,也可理解子类需要活动多少偏移量。

class_ro_t->flags则存储了好多在编译时期就是规定的切近的音讯,也是 ABI
的一致片段。

总结:
class_rw_t提供了运行时对类拓展之力量,而class_ro_t囤的基本上是相仿以编译时即既规定的信息。二者都包藏来相近的办法、属性(成员变量)、协议等消息,不过存储它们的列表实现方式各异。

class_rw_t遇使用的 method_array_t, property_array_t,
protocol_array_t且继承自list_array_tt<Element, List>,
它好不断扩充,因为她可储存 list 指针,内容有三种植:

  • 一个 entsize_list_tt 指针
  • entsize_list_tt 指针数组

class_rw_t的内容是得于运转时叫动态修改的,可以说运行时对类的拓大都是储存在这里的。

class_rw_t->flags 存储的值并无是编辑器设置的,其中小值可能将来会晤当
ABI 的一样部分。

demangledName
是计算机语言用于缓解实体名称唯一性的同等栽方法,做法是朝名称中上加有类型信息,用于自编译器中向链接器传递更多语义信息。

第二、从句简化的相似规则

Category

Category

category_t
存储了色中可以拓展之实例方法、类措施、协议、实例属性与类属性。类特性是
Objective-C 2016 年新增的风味,沾 Swift 的只。所以
category_t遭到稍微成员变量是以配合 Swift 的特点,Objective-C
暂没有提供接口,仅开了底部数据结构及的匹配。

再有很多数据结构,我便不一一贴出了,源码中都是得一直翻的。

1.起句简化的根基语法观念

当介绍从句简化的规则之前,我们第一要铭记在心有“离经叛道”的语法观念,这些传统和习俗语法格格不入,但就此起来也是充分得心应手,所以,学着去接受吧。

重大出以下四点:

A.始终视be动词为叫语动词,其后的分词等一律视为补语

B.现在分词视为形容词,同时表“持续、进行”的意义

C.过去分词视为形容词,同时表“被动、完成”的含义

D.不定式具有无确定的音,语气助动词都只是改写为be+to的形式

旋即几乎单观念在事先其实都介绍了,这里就是不再过多证,我们好整合句子简化的条条框框来越了解和控制。

第二、消息转发

当一个对象会接纳一个信不时,就会见倒正常的法门调用流程。但若是一个靶无法接收指定消息不时,就会见启动所谓”信息转发(message
forwarding)
“机制,通过就无异编制,我们可以告知对象如何处理未知之音信。默认情况下,对象收取至未知之音讯,会促成程序崩溃。

信转发一共发三步:

  1. 动态方法分析
  2. 备用接收者
  3. 整体转发

2.自句简化的要

简化从句要召开三桩业务:处理主语、处理动词、处理连接词。

里主语和连词之处理比较简单,如果起句之主语和主句主语重复,就好直接省微掉起句之主语,句子简化过后剩下的连接词如果是纸上谈兵的或是无所谓的,也足以以接连词看略掉。

比较复杂的凡动词的拍卖,要分三栽情况。

A.动词是be动词时,直接省略掉be动词

倘由句之动词是be动词,那么可一直将be动词省略掉,因为be动词是突出的系动词,本身并未实际意义。

例如:

More wizards were joining the marching group,while they were laughing
and pointing up at the floating bodies.

第一可以望,while因势利导之副词性从句之主语they以及主句的more
wizards
重复,可以直接省微掉。

接下来,从句的动词是were,没有实际意义,也可以直接省有点掉。

末尾剩下的连接词while虽发生“当…的时节”的含义,但去丢为并无最好影响,同样可望略掉。

以上三码事做得了事后,从句简化就水到渠成了:

More wizards were joining the marching group, laughing and pointing up
at the floating bodies.

B.于句被富含语气助动词时,将文章助动词简化为不定式

自从句被如带有语气助动词,可以率先用文章助动词改写成“be+to”的花样,然后省略掉无意义之be动词,最终变成不定式的样式。

例如:

I expect that I can finish the book on the way.

此复句中,that因势利导之名词性从句主语和主句主语重复,可以直接省略掉;语气助动词can足改写成am to,再用无意义的am看看略掉;最后剩余的连接词that从来不实际意义,同样好直接省多少掉。

末由句简化的结果是:

I expect to finish the book on the way.

C.从句被只有平常动词时,将惯常动词变成V-ing形式

如若起句被既没有be动词,也从不语气助动词,那咱们就算设管动词改写成带有be动词的V-ing形式。

例如:

The runner who finished second won a small prize.

who引导的形容词性从句被,关系代词作主语,并且与主句的主语相同,所以可以省略掉。

动词的拍卖我们好这么进行,先将who finished second改写成who was
finishing second
,句意并没改,然后拿任意义之was看望略掉即可。

由句简化后底句子为:

The runner finishing second won a small prize.

再也来回顾一下以上三单例,从传统语法的角度来讲,三独简化后的由句分别是本分词短语作副词修饰动词、不定式短语作宾语、现在分词短语作形容词修饰名词。

不过若从于句简化的角度来拘禁,它们还是于句简化后获取的结果。因此,我们如果了解从句是怎样简化的,就甭还错过记那么多本分词、不定式的定义,可以减轻不少学学压力。

上述就由句简化的共通规则,具体到各个种档次的自句被,还有个别需注意的地方,后面又各自进行探索。

动态方法分析

目标在收取及未知的消息不时,首先会调用所属类的类方法+resolveInstanceMethod:(实例方法)或者+resolveClassMethod:(类方式)。在这个方式吃,我们有机会呢该未知消息新增一个”处理方法””。不过以该措施的前提是我们已实现了该”处理方式”,只待以运作时经过class_addMethod函数动态增长到近似中就是可以了。

void functionForMethod1(id self, SEL _cmd) {
    NSLog(@"%@, %p", self, _cmd);
}

+ (BOOL)resolveInstanceMethod:(SEL)sel{
    NSString *selectorString = NSStringFromSelector(sel);
    if ([selectorString isEqualToString:@"method1"]) {
        class_addMethod(self.class, @selector(method1), (IMP)functionForMethod1, "@:");
    }
    return [super resolveInstanceMethod:sel];
}

备用接受者

比方当直达亦然步无法处理消息,则Runtime会继续调整以下措施:

- (id)forwardingTargetForSelector:(SEL)aSelector

倘一个目标实现了此方式,并赶回一个非nil且非self的结果,则是目标见面作为信息之初接收者,且消息会受分发至之目标。如果我们从没点名相应的目标来处理aSelector,则当调用父类的兑现来回到结果。

如:

- (id)forwardingTargetForSelector:(SEL)aSelector{
    return [Test2 new];
}

此刻出殡的音讯就会见交Test2的一个对象

注意:如果想为换类方法的接受者,需要覆写
+ (id)forwardingTargetForSelector:(SEL)aSelector措施,并返回类对象:

此编译器没有代码补全提醒,且若当文档中凡是找不顶之主意的,但是透过试验确实是出此艺术的,且会如愿以偿转发类方法。

总体信息转发

倘以上同一步还非克处理未知消息,则唯一能够开的虽是启用完整的消息转发机制了。此时会见调用以下方式:

- (void)forwardInvocation:(NSInvocation *)anInvocation

这里需要留意的凡参数anInvocation是自哪的来之啊?其实际forwardInvocation:信息发送前,Runtime系统会向目标发送methodSignatureForSelector:信息,并拿走到回的章程签名用于转移NSInvocation靶。所以我们以还写forwardInvocation:的而也要重新写methodSignatureForSelector:办法,否则会丢掉大。

当下同步转发与亚步转发的机要分就是是,它可指定多独对象进行转账,且这些目标还要贯彻相应的艺术,否则还是会弃来大。如:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    NSString *sel = NSStringFromSelector(aSelector);
    if ([sel isEqualToString:@"add"]) {
        return [NSMethodSignature signatureWithObjCTypes:"v:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation{
    SEL sel = anInvocation.selector;
    if ([NSStringFromSelector(sel) isEqualToString:@"add"]) {
        [anInvocation invokeWithTarget:[Test2 new]];
        [anInvocation invokeWithTarget:[Test3 new]];
    }
}

这会儿Test2和Test3少只类似的目标还见面转化这条信息。

老三、关联对象的实现原理(Associated Objects)

此地自己就算不介绍涉对象的应用了,网上有关博客有广大,这里我们介绍涉对象是如果将一个目标关系起来的。
咱俩一直看关系对象相关的老三单道吧:

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);

objc_setAssociatedObject

咱们一直看objc-runtime.mm中之源码

void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
    _object_set_associative_reference(object, (void *)key, value, policy);
}

void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
             ...
    }
    if (old_association.hasValue()) ReleaseValue()(old_association);
}

这边我概括了差不多底实现代码,我们任重而道远看她的兑现原理就是吓。

最主要注意这里的几个类和数据结构:

  • AssociationsManager
  • AssociationsHashMap
  • ObjcAssociationMap
  • ObjcAssociation

AssociationsManager 在源代码中之概念是这么的:

spinlock_t AssociationsManagerLock;

class AssociationsManager {
    // associative references: object pointer -> PtrPtrHashMap.
    static AssociationsHashMap *_map;
public:
    AssociationsManager()   { AssociationsManagerLock.lock(); }
    ~AssociationsManager()  { AssociationsManagerLock.unlock(); }

    AssociationsHashMap &associations() {
        if (_map == NULL)
            _map = new AssociationsHashMap();
        return *_map;
    }
};

其保护了spinlock_t
AssociationsHashMap的单例,初始化它的时段会调用 lock.lock()
方法,在析构时会见调用lock.unlock(),而 associations
方法用于得一个大局的 AssociationsHashMap 单例。

也就是说 AssociationsManager
通过装有一个自旋锁
spinlock_t 保证对 AssociationsHashMap
的操作是线程安全的,即历次就会产生一个线程对 AssociationsHashMap
进行操作

怎存储ObjcAssociation

AssociationsHashMap

class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap *, DisguisedPointerHash, DisguisedPointerEqual, AssociationsHashMapAllocator> {
    public:
        void *operator new(size_t n) { return ::malloc(n); }
        void operator delete(void *ptr) { ::free(ptr); }
    };

AssociationsHashMap用来保存于目标的 disguised_ptr_t
ObjectAssociationMap 的映射。

ObjectAssociationMap

class ObjectAssociationMap : public std::map<void *, ObjcAssociation, ObjectPointerLess, ObjectAssociationMapAllocator> {
    public:
        void *operator new(size_t n) { return ::malloc(n); }
        void operator delete(void *ptr) { ::free(ptr); }
    };

ObjectAssociationMap尽管如此保留了从key 到关系对象ObjcAssociation
的照耀,这个数据结构保存了时目标对应之有所涉对象

ObjcAssociation

class ObjcAssociation {
        uintptr_t _policy;
        id _value;
    public:
        ObjcAssociation(uintptr_t policy, id value) : _policy(policy), _value(value) {}
        ObjcAssociation() : _policy(0), _value(nil) {}

        uintptr_t policy() const { return _policy; }
        id value() const { return _value; }

        bool hasValue() { return _value != nil; }
    };

ObjcAssociation 包含了 policy以及 value

推选一个简单易行的例证:

        NSObject *obj = [NSObject new];
        objc_setAssociatedObject(obj, @selector(hello), @"Hello", OBJC_ASSOCIATION_RETAIN_NONATOMIC);

这里的关联对象 ObjcAssociation(OBJC_ASSOCIATION_RETAIN_NONATOMIC,
@”Hello”) 在内存中凡这样存储的:

associateobjcect

好了,我们回去对 objc_setAssociatedObject道的解析

void _object_set_associative_reference(id object, void *key, id value, uintptr_t policy) {
    // retain the new value (if any) outside the lock.
    ObjcAssociation old_association(0, nil);
    id new_value = value ? acquireValue(value, policy) : nil;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        if (new_value) {
            // break any existing association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i != associations.end()) {
                // secondary table exists
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    j->second = ObjcAssociation(policy, new_value);
                } else {
                    (*refs)[key] = ObjcAssociation(policy, new_value);
                }
            } else {
                // create the new association (first time).
                ObjectAssociationMap *refs = new ObjectAssociationMap;
                associations[disguised_object] = refs;
                (*refs)[key] = ObjcAssociation(policy, new_value);
                object->setHasAssociatedObjects();
            }
        } else {
            // setting the association to nil breaks the association.
            AssociationsHashMap::iterator i = associations.find(disguised_object);
            if (i !=  associations.end()) {
                ObjectAssociationMap *refs = i->second;
                ObjectAssociationMap::iterator j = refs->find(key);
                if (j != refs->end()) {
                    old_association = j->second;
                    refs->erase(j);
                }
            }
        }
    }
    // release the old value (outside of the lock).
    if (old_association.hasValue()) ReleaseValue()(old_association);
}
  1. 使用 old_association(0, nil) 创建一个临时之 ObjcAssociation
    对象(用于所有原有的涉嫌对象,方便于方调用的最后释放值)

new_value != nil的情景下

  1. 调用 acquireValuenew_value进行retain 或者 copy

static id acquireValue(id value, uintptr_t policy) {
    switch (policy & 0xFF) {
    case OBJC_ASSOCIATION_SETTER_RETAIN:
        return objc_retain(value);
    case OBJC_ASSOCIATION_SETTER_COPY:
        return ((id(*)(id, SEL))objc_msgSend)(value, SEL_copy);
    }
    return value;
}
  1. 初始化一个
    AssociationsManager,并取唯一的保留关联对象的哈希表AssociationsHashMap

  2. 优先采取 DISGUISE(object) 作为 key 寻找对应之 ObjectAssociationMap

  3. 一旦无找到,初始化一个 ObjectAssociationMap,再实例化
    ObjcAssociation 对象上加到 Map 中,并调用 setHasAssociatedObjects
    方法(它见面以 isa 结构体中之符号位 has_assoc 标记为
    true),表明当前目标涵盖关联对象

ObjectAssociationMap *refs = new ObjectAssociationMap;
associations[disguised_object] = refs;
(*refs)[key] = ObjcAssociation(policy, new_value);
object->setHasAssociatedObjects();
  1. 假如找到了相应的 ObjectAssociationMap,就要扣押 key
    是否留存了,由此来控制是翻新原有的涉对象,还是长一个

ObjectAssociationMap *refs = i->second;
ObjectAssociationMap::iterator j = refs->find(key);
if (j != refs->end()) {
    old_association = j->second;
    j->second = ObjcAssociation(policy, new_value);
} else {
    (*refs)[key] = ObjcAssociation(policy, new_value);
}
  1. 最后,如果原先的涉及对象有值的话语,会调用 ReleaseValue()
    释放关联对象的值

new_value == nil的状下,其实就是调用 erase 方法,擦除
ObjectAssociationMap 中 key 对应之节点,删除对承诺key的关系对象。

objc_getAssociatedObject
前面objc_setAssociatedObject已经详细介绍了,下面这半单道就是十分容易理解了。

id objc_getAssociatedObject(id object, const void *key) {
    return _object_get_associative_reference(object, (void *)key);
}

id _object_get_associative_reference(id object, void *key) {
    id value = nil;
    uintptr_t policy = OBJC_ASSOCIATION_ASSIGN;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        disguised_ptr_t disguised_object = DISGUISE(object);
        AssociationsHashMap::iterator i = associations.find(disguised_object);
        if (i != associations.end()) {
            ObjectAssociationMap *refs = i->second;
            ObjectAssociationMap::iterator j = refs->find(key);
            if (j != refs->end()) {
                ObjcAssociation &entry = j->second;
                value = entry.value();
                policy = entry.policy();
                if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
                    objc_retain(value);
                }
            }
        }
    }
    if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
        objc_autorelease(value);
    }
    return value;
}

她的逻辑和objc_setAssociatedObject差不多

  1. 获得静态变量AssociationsHashMap

  2. DISGUISE(object)为 key 查找AssociationsHashMap

  3. void *keykey查找ObjcAssociation

  4. 根据 policy调用相应的计

if (policy & OBJC_ASSOCIATION_GETTER_RETAIN) {
      objc_retain(value);
 }

if (value && (policy & OBJC_ASSOCIATION_GETTER_AUTORELEASE)) {
     objc_autorelease(value);
 }
  1. 回来关联对象 ObjcAssociation 的价值

objc_removeAssociatedObjects

直放代码吧

void objc_removeAssociatedObjects(id object) 
{
    if (object && object->hasAssociatedObjects()) {
        _object_remove_assocations(object);
    }
}

void _object_remove_assocations(id object) {
    vector< ObjcAssociation,ObjcAllocator<ObjcAssociation> > elements;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.associations());
        if (associations.size() == 0) return;
        disguised_ptr_t disguised_object = DISGUISE(object);
        AssociationsHashMap::iterator i = associations.find(disguised_object);
        if (i != associations.end()) {
            // copy all of the associations that need to be removed.
            ObjectAssociationMap *refs = i->second;
            for (ObjectAssociationMap::iterator j = refs->begin(), end = refs->end(); j != end; ++j) {
                elements.push_back(j->second);
            }
            // remove the secondary table.
            delete refs;
            associations.erase(i);
        }
    }
    // the calls to releaseValue() happen outside of the lock.
    for_each(elements.begin(), elements.end(), ReleaseValue());
}

盼此自己怀念呢没啥用说的了,唯一要专注一点底就是此在剔除之前,它加了只判断if (object && object->hasAssociatedObjects())
我们来探视是hasAssociatedObjects

objc_object::hasAssociatedObjects()
{
    if (isTaggedPointer()) return true;
    if (isa.nonpointer) return isa.has_assoc;
    return true;
}

如果是TaggedPointer,则回true,正常对象则是因isa的符号位来判断是否留存涉嫌对象。

总结

Runtime是支持OC的一个特别有力的堆栈,OC的累累特点都是依于Runtime,所以想只要还好的左右这宗语言,对Runtime的解是必需的。

末了,文中有什么错误的地方想大家指出,希望与大家共同进步。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图