objc_msg

作者: 浩然爸 | 来源:发表于2018-02-08 14:58 被阅读7次

1、动态添加方法

#import <Foundation/Foundation.h>

@interface Person : NSObject

+ (void)say;
- (void)say;

@end
#import "Person.h"
#import <objc/message.h>

@implementation Person
+ (void)say {
    NSLog(@"+ say");
}

- (void)say {
    NSLog(@"- say");
}

void aaa(id self, SEL _cmd) {
    NSLog(@"调用了eat %@ %@", self, NSStringFromSelector(_cmd));
}

void bbb(id self, SEL _cmd, id param1) {
    NSLog(@"调用了eat %@ %@ %@", self, NSStringFromSelector(_cmd), param1);
}

//动态添加方法,首先实现这个方法
//当调用一个没有实现的方法的时候 就会触发这个方法
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    NSLog(@"%@", NSStringFromSelector(sel));
    
    if (sel == @selector(eat)) {
        /**
         *  cls:给那个类添加方法
            name:添加方法的方法编号
            imp:方法的实现,函数的入口,函数名
            types:方法的返回类型,函数的类型 (差文档 runtime)
         */
        class_addMethod(self, sel, (IMP)aaa, "v@:");
        
        return YES;
    } else if (sel == @selector(eat:)) {
        class_addMethod(self, sel, (IMP)bbb, "v@:@");
        return YES;
    }
    
    return [super resolveInstanceMethod:sel];
}

@end
  • 使用
Person *p = [[Person alloc] init];
    
    [p say];
    //相当于
    [p performSelector:@selector(say)];
    //上面用运行时 调用方法就相当于发送消息
    objc_msgSend(p, @selector(say));
    
    [Person say];
    objc_msgSend([Person class], @selector(say));
  • 思考
//动态添加方法
    //使用场景:如果一个类方法非常多,加载类到内存的时候就会比较消耗资源,需要给每个方法生成映射表。因此可以用动态添加方法来解决这个问题
    //经典问题:有没有使用performSelector,其实是主要想问的就是有没有用过动态动态添加方法
    //performSelector 一般用在动态添加方法的时候调用
    //动态添加方法
    [p performSelector:@selector(eat)];
    [p performSelector:@selector(eat:) withObject:@"ss"];

2、方法交换

#import <UIKit/UIKit.h>

@interface UIImage (Extension)

@end
#import "UIImage+Extension.h"
#import <objc/message.h>

@implementation UIImage (Extension)
//类加载的时候调用该的
+ (void)load {
    NSLog(@"%s", __func__);
    //获取方法的实现:class_getMethodImplementation(<#__unsafe_unretained Class cls#>, <#SEL name#>)
    //获取实例方法:class_getInstanceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>)
    //获取类方法:class_getClassMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>)
    
    //获取要交换的方法
    Method m1 = class_getClassMethod(self, @selector(imageNamed:));
    Method m2 = class_getClassMethod(self, @selector(SFJ_imageNamed:));
    
    //交换方法的实现
    method_exchangeImplementations(m1, m2);
}

+ (UIImage *)SFJ_imageNamed:(NSString *)name {
    
    UIImage *image = [UIImage SFJ_imageNamed:name];
    if (!image) {
        NSLog(@"图片是空的");
    }
    return image;
}

@end
  • 使用
//此时imageNamed方法实际上是使用了我们替换以后的方法SFJ_imageNamed
UIImage *image = [UIImage imageNamed:@"ss"];

3、添加属性

#import <Foundation/Foundation.h>

@interface NSObject (Extension)

@property (nonatomic, copy) NSString *name;

@end
#import "NSObject+Extension.h"
#import <objc/message.h>

//动态添加属性
@implementation NSObject (Extension)

//static NSString *_name;

- (void)setName:(NSString *)name {
    /**
     *  object:给那个对象添加属性
        key:属性名,根据key去获取关联的对象
        value:关联的值
        policy:策略
     */
    objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//    _name = name;
}

- (NSString *)name {
    return objc_getAssociatedObject(self, "name");
}

@end
  • 使用
NSObject *obj = [[NSObject alloc] init];
    obj.name = @"sss";
    NSLog(@"%@", obj.name);

相关文章

网友评论

      本文标题:objc_msg

      本文链接:https://www.haomeiwen.com/subject/uvsttftx.html