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);