oc-runtime应用

281 阅读3分钟

一、method-swizzling

+ (void)methodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL
{
  if (!cls)
    NSLog(@"传入的交换类不能为空");
  
  Method oriMethod = class_getInstanceMethod(cls,oriSEL);
  Method swiMethod = class_getInstanceMethod(cls,swizzledSEL);
  method_exchangeImplementations(oriMethod,swiMethod);
  
  /*
  		原本:
  		oriSEL  ->  oriIMP
  		swiSEL  ->  swiIMP
  		交换后:
  		oriSEL  ->  swiIMP
  		swiSEL  ->  oriIMP
  */
}

1、操作时机

放在load方法中操作,原因 :

  • 调用时机早,在main函数前调用
  • 系统自动调用
  • 唯一性:load方法不会被覆盖,因此保证了安全性

注:若手动调用load方法还是会执行一次交换,方法就会交换城原状,所以最好用dispatch_once

2、坑

  1. 父类中 有方法A,子类没有实现方法A,但实现了方法B

    此时在子类的分类的load方法中对方法A与方法B进行交换

    现象:

    • 子类生成的对象调用方法A正常执行,没有任何问题
    • 父类生成的对象调用方法A后crash,报错为“方法B未实现”,因为父类拿不到子类方法B的实现

    注:不要在子类里瞎搞父类的方法

    ​ 子类做方法交换时,不应该影响到父类,不应该让父类去调用子类的方法

    + (void)betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL
    {
      if (!cls)
        NSLog(@"传入的交换类不能为空");
      
      Method oriMethod = class_getInstanceMethod(cls,oriSEL);
      Method swiMethod = class_getInstanceMethod(cls,swizzledSEL);
      
      // 该处添加了一个名为方法A但指针指向方法B的方法,即SEL_A`->IMP_B
      // A`代表子类中再次实现的A
      BOOL didAddMethod = class_addMethod(cls,oriSEL,method_getImplementation(swiMethod),method_getTypeEncoding(swiMethod));
      
      if (didAddMethod)
      {
        // 之前报错是因为子类拿自己的方法B去交换了父类的方法A,父类在调用方法B的时候找不到方法B,子类做方法交换时,不应该影响到父类,不应该让父类去调用子类的方法
        
        // 所以这里子类自己实现了方法A即A`,并且将方法B的SEL指向->父类方法A的IMP
        class_replaceMethod(cls,swizzledSEL,method_getImplementation(oriMethod),method_getTypeEncoding(oriMethod));
        
        // 所以当子类对象调用方法A的时候会走方法B,因为调的实际上是A`
        // 当父类对象调用方法A时,就是调用的原本父类实现的方法A,原本的方法A在这里没有发生交换
      }
      else
      {
        method_exchangeImplementations(oriMedthod,swiMedthod);
      }
    }
    
  2. 父类也没有实现A,子类也没有实现A,父类和子类的方法A的IMP都没有

    此时,用子类对象调用方法A

    现象:发生了递归

    原因: 因为没有IMP_A,所以方法交换会失败,导致的结果是SEL_A -> IMP_BSEL_B -> IMP_B

    + (void)bestMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL
    {
        
        if (!cls) NSLog(@"传入的交换类不能为空");
        
        Method oriMethod = class_getInstanceMethod(cls, oriSEL);
        Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
        if (!oriMethod) {
            class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
            method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){ }));// 给一个空代码块相当于IMP_A
        }
    
        BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
        if (didAddMethod) {
            class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }else{
            method_exchangeImplementations(oriMethod, swiMethod);
        }
    }
    
  3. 类方法会如何?

二、isKindOfClass和isMemberOfClass

+ (BOOL)isKindOfClass:(Class)cls {
  	//  object_getClass((id)self) 是元类
    for (Class tcls = object_getClass((id)self); tcls; tcls = tcls->superclass) {
      	// 当传进来的类cls == self的元类或自己元类的父类的时候返回yes
      	// 所以当cls = NSObject && self = NSObject 时返回YES
      	// 当cls = NSObject && self = 其他类时,也返回YES
      	// 目前个人判断:
        //    cls只要不是NSObject都会返回NO,只要是NSObject,就会返回YES
        if (tcls == cls) return YES;
    }
    return NO;
}

- (BOOL)isKindOfClass:(Class)cls {
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (tcls == cls) return YES;
    }
    return NO;
}
+ (BOOL)isMemberOfClass:(Class)cls {
    return object_getClass((id)self) == cls;// 永远返回NO
}

- (BOOL)isMemberOfClass:(Class)cls {
    return [self class] == cls;
}

三、[self class] 和 [super class]

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

- (Class)superclass { // 并不会走这个方法,因为不是[self superclass]
    return [self class]->superclass;
}
 [super class] 相当于 objc_msgSendSuper(&objc_super, class)
   // [self class] 是self发送的class消息
   // [super class] 是&objc_super发送的class消息,但是传入class的self是objc_super给的self
  
  
struct objc_super {
    /// Specifies an instance of a class.
    __unsafe_unretained _Nonnull id receiver;  // 就是self

    __unsafe_unretained _Nonnull Class super_class; // 父类
    /* super_class is the first class to search */
};