runTime一点点理解

OC底层的初步理解

  1. OC是是一门运行时运行会在运行时动态的获去属性和方法
调用方法编译时会被转化为消息发送

/* OC调用 */
[obj test];
/* 编译时运行时会将上边的代码转化为下面的消息发送C函数 */
obj_msgSend(obj,@selector(test))


Class的结构(其实就是isa指针指向结构体)

OC类室友Class类型来表示的他实际是一个指向objc_class的结构体的指针.

// 1. 结构体
typedef struct objc_class *Class;

struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                       OBJC2_UNAVAILABLE;  // 父类
    const char *name                        OBJC2_UNAVAILABLE;  // 类名
    long version                            OBJC2_UNAVAILABLE;  // 类的版本信息,默认为0
    long info                               OBJC2_UNAVAILABLE;  // 类信息,供运行期使用的一些位标识
    long instance_size                      OBJC2_UNAVAILABLE;  // 该类的实例变量大小
    struct objc_ivar_list *ivars            OBJC2_UNAVAILABLE;  // 该类的成员变量链表
    struct objc_method_list **methodLists   OBJC2_UNAVAILABLE;  // 方法定义的链表
    struct objc_cache *cache                OBJC2_UNAVAILABLE;  // 方法缓存
    struct objc_protocol_list *protocols    OBJC2_UNAVAILABLE;  // 协议链表
#endif
} OBJC2_UNAVAILABLE;


  1. isa指向metaclass(元类).
  2. super_class指向父类.

objc继承原理:

  1. obj通过class生成,但是class本身也是obj
  2. 如上本质是结构体(写一个不继承NSObject的类,一个指向结构体的指针)
  3. objc的class保存了方法列表还有指向父类的指针.isa指向metaclass(元类).保存了所有实现的方法列表,以及父类的metaclass(元类)

![Uploading Snip20161107_6_028079.png . . .]

objc方法原理:

  1. 消息是如何映射方法的?方法又是如何执行的??

  2. 首先对象属性保存在对象中,方法在类中.class的方法列表其实相当于一个字典.key:selector,IMPs:value.并且注意key和value是在运行时才确定的.而不是在编译时.引出IMPs代表什么呢??

  3. IMPs可以理解为指向方法的指针.

// Method
- (id)doSomethingWithInt:(int)aInt{}

/* 
IMP
参数1:self
参数2:_cmd
参数3:方法的参数
*/
id doSomethingWithInt(id self, SEL _cmd, int aInt){}


# pragma mark - 运行时里面是一个强大的runtime库,用c和汇编写的,具有一些很强大的功能.以后再去研究.建议可以阅读南峰子的博客
class_addIvar,          // 增加成员变量
class_addMethod,        // 增加方法
class_addProperty       // 增加属性
class_addProtocol       // 增加协议

class_copyIvarList,     // 复制成员变量列表
class_copyMethodList,   // 复制方法列表
class_copyProtocolList  // 复制协议列表
class_copyPropertyList  // 复制属性列表 

作用:

  • 获取一个类的属性列表和成员变量
// 字典转模型中获取一个类的属性列表,遍历得到属性名数组,根据属性名赋值属性,实现setValueUndefined方法避免报错,完成字典转模型(简单实现思路)
class_copyPropertyList  // 复制属性列表


  • 交换方法的实现(消息发送机制,指针可以改变).
+ (void)load {
    Method addobject = class_getInstanceMethod(self, @selector(addObject:));
    Method logAddobject = class_getInstanceMethod(self, @selector(logAddObject:));
    method_exchangeImplementations(addObject, logAddObject);

}

- (void)logAddObject:(id)aobject { [self logAddObject:aObject]; NSLog(@"Added object %@ to array %@", aObject, self);}

  • 关联对象.用于给分类添加属性的set,get方法的实现.因为分为能过写属性但是不会生成set和get方法,需要我们手动去实现这个功能.

- (NSString *)downloadingURLString {
//    return _downloadingURLString;
    // id object: 获取哪个对象上面的值
    // const void *key:
    return objc_getAssociatedObject(self, key);
}

- (void)setDownloadingURLString:(NSString *)downloadingURLString {
//    _downloadingURLString = downloadingURLString;
    // 关联对象: 设置一个值到一个对象上面
    
    // id object: 值保存到哪个对象上面
    // const void *key: 名称�
    // id value: 要保存的内容
    // objc_AssociationPolicy policy: 策略
    objc_setAssociatedObject(self, key, downloadingURLString, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
  • KVO监听原理,Key Value Observing。当你开始observing an object时,Cocoa会创建这个object的class的subclass,然后将这个object的isa指向新创建的subclass(父类)。
object_setClass(myObject, [MySubclass class]);
消息动态处理流程

/* 1. 时机处理之一,在这个方法中我们可以利用runtime的特性动态添加方法来处理 */
+ (BOOL)resolveInstanceMethod:(SEL)sel;
/* 2. 时机处理之二,在这个方法中看代理能不能处理,如果代理对象能处理,则转接给代理对象 */
- (id)forwardingTargetForSelector:(SEL)aSelector;
/* 3. 消息转发之一,该方法返回方法签名,如果返回nil,则转发流程终止,抛出异常 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector;
/* 4. 消息转发之二,在该方法中我们可以对调用方法进行重定向 */
- (void)forwardInvocation:(NSInvocation *)anInvocation;

消息转发:

如果resolve method:解决方法,返回一个NO,再去找代理对象有没有实现这个方法,运行时就会进入消息转发
有两种常见的方法

  1. 将消息转发到另一个可以处理消息的obj.(代理)
  2. 将多个消息转发到同一个方法.
1. forwardingTargetForSelector:发送给另一个obj

2. forwordInvacation:运行时将消息打包成NSInvacation返回给你处理的,处理完后调用invokeWithTarget

Cacoa有哪里用到了消息转发呢?第一个代理,第二个响应者链条.

NSInvacation方法对象

消息的对象.

NSProxy

NSProxy是一个轻量级的class,它的作用就是转发消息到另一个object。

NSUndoManager

NSUndoManager也有用到,不过是截取消息,之后再执行,而不是转发到其他的地方。

你可能感兴趣的:(runTime一点点理解)