常见面试题

2020-10-26  本文已影响0人  浪的出名

super的本质

  Student *s = [[Student alloc] init];
  [s test1];
  
  @interface Student : Person
  - (void)test1;
  @end
  - (void)test1
  {
     [super test];
  }
static void _I_Student_test1(Student * self, SEL _cmd) {
    ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("test"));
    //去掉一些强转
    objc_msgSendSuper((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("test"));
}

Method Swizzling的坑与应用

// 官方文档给出的描述
This function behaves in two different ways:
If the method identified by name does not yet exist, it is added as if class_addMethod were called. The type encoding specified by types is used as given.
If the method identified by name does exist, its IMP is replaced as if method_setImplementation were called. The type encoding specified by types is ignored.
此函数的行为有两种不同的方式:
如果通过名称标识的方法尚不存在,则将其添加为如同调用class_addMethod一样。 给定使用由类型指定的类型编码。
如果确实存在按名称标识的方法,则将其IMP替换,就像调用method_setImplementation一样。 由类型指定的类型编码将被忽略。
IMP imp1 = method_getImplementation(m1);
IMP imp2 = method_getImplementation(m2);
method_setImplementation(m1, imp2);
method_setImplementation(m2, imp1);

method-swizzling使用过程中的一次性问题

+ (void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
            交换方法
    });
}

自己没有实现,父类实现的问题

@interface Person : NSObject
- (void)instancetypeMeth1;
@end
@implementation Person
- (void)instancetypeMeth1
{
    NSLog(@"%s",__func__);
}
@end

@interface Student (XQ)

@end
@implementation Student (XQ)
+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [XQRuntimeTool xq_methodSwizzlingWithClass:self oriSEL:@selector(instancetypeMeth1) swizzledSEL:@selector(stu_instancetypeMeth1)];
    });
}

- (void)stu_instancetypeMeth1
{
    [self stu_instancetypeMeth1];
    NSLog(@"%s",__func__);
}
@end
    Student *s = [Student new];
    [s instancetypeMeth1];
    Person *p = [Person new];
    [p instancetypeMeth1];
image.png
+ (void)xq_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
    
    if (!cls) NSLog(@"传入的交换类不能为空");
  
    Method oriMethod = class_getInstanceMethod(cls, oriSEL);
    Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
   // 尝试添加你要交换的方法
    BOOL success = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(oriMethod));

    if (success) {// 自己没有 - 交换 - 没有父类进行处理 (重写一个)
        class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
    }else{ // 自己有
        method_exchangeImplementations(oriMethod, swiMethod);
    }
}
- (void)stu_instancetypeMeth1
{
    [self stu_instancetypeMeth1];//在这里相当于自己调用自己
    NSLog(@"%s",__func__);
}
+ (void)xq_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) { // 避免动作没有意义
        // 在oriMethod为nil时,替换后将swizzledSEL复制一个不做任何事的空实现,代码如下:
        class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
        method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){
            NSLog(@"来了一个空的 imp");
        }));
    }
    
    // 一般交换方法: 交换自己有的方法 -- 走下面 因为自己有意味添加方法失败
    // 交换自己没有实现的方法:
    //   首先第一步:会先尝试给自己添加要交换的方法 :instanceMethod1 (SEL) -> swiMethod(IMP)
    //   然后再将父类的IMP给swizzle  instanceMethod1(imp) -> swizzledSEL
    //oriSEL:instanceMethod1

    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);
    }
}
上一篇 下一篇

猜你喜欢

热点阅读