objc_getClass、objc_getMetaClass、[self class]、object_getClass的区别

当我们使用runtime交换方法时,通常使用如下方法

static inline BOOL ISExchangeImplementationsInTwoClasses(Class _fromClass,
                                                         SEL _originSelector,
                                                         Class _toClass,
                                                         SEL _newSelector) {
  if (!_fromClass || !_toClass) {
    return NO;
  }
  
  Method oriMethod = class_getInstanceMethod(_fromClass, _originSelector);
  Method newMethod = class_getInstanceMethod(_toClass, _newSelector);
  if (!newMethod) {
    return NO;
  }
  
  BOOL isAddedMethod = class_addMethod(_fromClass, _originSelector,
                                       method_getImplementation(newMethod),
                                       method_getTypeEncoding(newMethod));
  if (isAddedMethod) {
    // 如果 class_addMethod 成功了,说明之前 fromClass 里并不存在 originSelector,
    // 所以要用一个空的方法代替它,以避免 class_replaceMethod 后,
    // 后续 toClass 的这个方法被调用时可能会 crash
    IMP oriMethodIMP = method_getImplementation(oriMethod)
    ?: imp_implementationWithBlock(^(id selfObject){
    });
    const char* oriMethodTypeEncoding =
    method_getTypeEncoding(oriMethod) ?: "v@:";
    class_replaceMethod(_toClass, _newSelector, oriMethodIMP,
                        oriMethodTypeEncoding);
  } else {
    method_exchangeImplementations(oriMethod, newMethod);
  }
  return YES;
}

我们知道class_getInstanceMethod获取的是实例方法,交换减号方法时,_fromClass和_toClass都传[self class]就行了,但是交换两个加号方法时,传这个参数却没有用,方法交换失败,但是传object_getClass交换即可成功。再加上那到底他们有什么区别呢?

先来看下图:

objc_getClass、objc_getMetaClass、[self class]、object_getClass的区别_第1张图片
图片.png

当需要交换实例方法时,我们传入 Class即可,当时当交换加号方法时,需要传 MetaClss,可以这样理解,oc里的Class里的加号方法,相当于该类的MetalClas的实例方法,类调用类方法,和对象调用实例方法,其实底层实现都是一样的。类也是对象。

以UIImage为例,

Class a1 = objc_getClass("UIImage");
Class a2 = objc_getMetaClass("UIImage");
Class a3 = [self class];
Class a4 = object_getClass(self);

NSLog(@"%p",a1);
NSLog(@"%p",a2);
NSLog(@"%p",a3);
NSLog(@"%p",a4);

2019-03-09 16:01:46.074567+0800 Configuration[8694:652882] 0x1e6229c68
2019-03-09 16:01:46.074607+0800 Configuration[8694:652882] 0x1e6229c90
2019-03-09 16:01:46.074618+0800 Configuration[8694:652882] 0x1e6229c68
2019-03-09 16:01:46.074627+0800 Configuration[8694:652882] 0x1e6229c90

1.objc_getMetaClass 获取MetalClass
2.objc_getClass 获取Class
3.object_getClass 获取 object 的isa指针对象。

看开源的objc源码有class的方法

+ (Class)class {
return self;
}

- (Class)class {
return object_getClass(self);
}

其实object_getClass(obj)与[obj class]的区别了,就两点:

1、如果是obj实例对象,他们一样;
2、如果是类对象,class是self,object_getClass是isa

参考链接:https://www.jianshu.com/p/ae5c32708bc6

你可能感兴趣的:(objc_getClass、objc_getMetaClass、[self class]、object_getClass的区别)