iOS进阶之面试题iOS

RunTime

2019-02-13  本文已影响14人  愤怒的八哥

运行时系统负责完成
1、对象的生成、释放时的内存管理。
2、为发来的消息查找对应的处理方法。
OC的消息是在运行时才去绑定,运行时系统首先会确认接收者的类型(动态类型识别),然后根据消息名称在类的方法列表中查找,如果没找到就到父类中继续查找,假如一直找到NSObject都没有找到要调用的方法,进入消息转发,最后会报告不能识别上述消息的错误。
三种不同的层级上与 Runtime 系统进行交互
1、通过 Objective-C 源代码
2、通过 Foundation 框架的NSObject类定义的方法
3、通过对 runtime 函数的直接调用。

消息发送的过程详解

OC消息源码会被编译成
id objc_msgSend ( id self, SEL op, ... );
id

/// A pointer to an instance of a class.
typedef struct objc_object *id;
/// Represents an instance of a class.
struct objc_object {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
};

Class

typedef struct objc_class *Class;
struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
class-diagram.jpg
上图实线是 superclass 指针,虚线是isa指针。 有趣的是根元类的超类是 NSObject,而 isa 指向了自己,而 NSObject 的超类为 nil,也就是它没有超类。
SEL
objc_msgSend函数第二个参数类型为SEL,它是selector在Objc中的表示类型(Swift中是Selector类)。selector是方法选择器,可以理解为区分方法的 ID,而这个 ID 的数据结构是SEL:
typedef struct objc_selector *SEL;

其实它就是个映射到方法的C字符串

**objc_method **

struct objc_method {
    SEL _Nonnull method_name                                 OBJC2_UNAVAILABLE;
    char * _Nullable method_types                            OBJC2_UNAVAILABLE;
    IMP _Nonnull method_imp                                  OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

objc_ivar

struct objc_ivar {
    char * _Nullable ivar_name                               OBJC2_UNAVAILABLE;
    char * _Nullable ivar_type                               OBJC2_UNAVAILABLE;
    int ivar_offset                                          OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
}     
struct objc_category {
    char * _Nonnull category_name                            OBJC2_UNAVAILABLE;
    char * _Nonnull class_name                               OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable instance_methods     OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable class_methods        OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
}                                                            OBJC2_UNAVAILABLE;

class_copyIvarList 函数获取的不仅有实例变量,还有属性。但会在原本的属性名前加上一个下划线。
对比下 class_copyIvarList 函数,使用 class_copyPropertyList 函数只能获取类的属性,而不包含成员变量。但此时获取的属性名是不带下划线的。
IMP

typedef void (*IMP)(void /* id, SEL, ... */ );

注意点
1、当 self 为实例对象时,[self class] 与 object_getClass(self) 等价,因为前者会调用后者。object_getClass([self class]) 得到元类。
2、当 self 为类对象时,[self class] 返回值为自身,还是 self。object_getClass(self) 与 object_getClass([self class]) 等价。

常用方法

1、关联,Runtime系统让Objc支持向对象动态添加变量。涉及到的函数有以下三个:

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 );

2、方法交换,Aspect库实现了 方法前中后加入代码,替换原方法。

+ (void)load {
    SEL originalSelector = @selector(ReceiveMessage:);
    SEL overrideSelector = @selector(replacementReceiveMessage:);
    Method originalMethod = class_getInstanceMethod(self, originalSelector);
    Method overrideMethod = class_getInstanceMethod(self, overrideSelector);
    if (class_addMethod(self, originalSelector, method_getImplementation(overrideMethod), method_getTypeEncoding(overrideMethod))) {
            class_replaceMethod(self, overrideSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
    } else {
            method_exchangeImplementations(originalMethod, overrideMethod);
    }
}

3、路由跳转,动态生成对象,给对象赋值。
4、获取成员变量列表快速归档
参考:
http://yulingtianxia.com/blog/2014/11/05/objective-c-runtime/

上一篇下一篇

猜你喜欢

热点阅读