1. 交换方法
1.1 获取类方法
Method class_getClassMethod(Class cls , SEL name)
1.2 获取实例方法
Method class_getInstanceMethod(Class cls , SEL name)
1.3 交换两个方法
void method_exchangeImplementations(Method m1 , Method m2)
实例:
//Person.h
#import
@interface Person : NSObject
+ (void)method_1;
+ (void)method_2;
- (void)method_3;
- (void)method_4;
@end
//Person.m
#import "Person.h"
@implementation Person
+ (void)method_1
{
NSLog(@"method_1");
}
+ (void)method_2
{
NSLog(@"method_2");
}
- (void)method_3
{
NSLog(@"method_3");
}
- (void)method_4
{
NSLog(@"emthod_4");
}
@end
[Person method_1]; //log: method_1
[Person method_2]; //log: method_2
Method m1 = class_getClassMethod([Person class], @selector(method_1));
Method m2 = class_getClassMethod([Person class], @selector(method_2));
method_exchangeImplementations(m1, m2);
[Person method_1]; //log: method_2
[Person method_2]; //log: method_1
Person *p = [[Person alloc] init];
[p method_3]; //log: method_3
[p method_4]; //log: method_4
Method m3 = class_getInstanceMethod([Person class], @selector(method_3));
Method m4 = class_getInstanceMethod([Person class], @selector(method_4));
method_exchangeImplementations(m3, m4);
[p method_3]; //log: method_4
[p method_4]; //log: method_3
2. 分类添加属性
下面给NSObject添加一个name属性
#import
@interface NSObject (Category)
@property (nonatomic, strong) NSString *name;
@end
#import "NSObject+Category.h"
#import
const char * str = "myKey";
@implementation NSObject (Category)
- (void)setName:(NSString *)name
{
/**
* void objc_setAssociatedObject(id object , const void *key ,id value ,objc_AssociationPolicy policy)
* object 需要添加属性的对象
* key 属性的key, 将来可以通过key取出这个存储的值
* value 属性的值
* policy 使用的策略,是一个枚举值,可根据开发需要选择不同的枚举
*/
objc_setAssociatedObject(self, &str, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name
{
return objc_getAssociatedObject(self, &str);
}
@end
3. 消息拦截转发
用到的几个方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
+ (BOOL)resolveClassMethod:(SEL)sel
- (id)forwardingTargetForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation
//对当前类添加一个newTestMethod方法, 当testMethod没有实现时, runtime会进行消息转发
+ (BOOL)resolveInstanceMethod:(SEL)sel
{
// 指定对某一个方法的动态解析
NSString *selName = NSStringFromSelector(sel);
if ([selName isEqualToString:@"testMethod"]) {
// 动态的添加一个方法
class_addMethod([self class], @selector(testMethod), (IMP)newTestMethod, "v@:");
return YES;
}
return NO;
}
void newTestMethod()
{
NSLog(@"%s", __func__);
}
3.2 消息转发到其他类
// 我们首先要通过, 指定方法签名,若返回nil,则表示不处理。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSLog(@"指定方法签名");
NSString *selName = NSStringFromSelector(aSelector);
if ([selName isEqualToString:@"testMethod"]) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
// 通过anInvocation对象做很多处理,比如修改实现方法,修改响应对象等
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
NSLog(@"%s", __func__);
// 改变响应对象并改变响应方法
[anInvocation setSelector:@selector(newTestMethod)];
[anInvocation invokeWithTarget:[ZYChildren new]];
}
//跳转到其他类中执行
- (id)forwardingTargetForSelector:(SEL)aSelector
{
NSLog(@"备用接收者");
// 指定对某一个对象来执行方法
NSString *selName = NSStringFromSelector(aSelector);
if ([selName isEqualToString:@"testMethod"]) {
return [ZYChildren new];
}
return [super forwardingTargetForSelector:aSelector];;
}
//拦截调用
MyClass *myClass = [[MyClass alloc] init];
[myClass performSelector: @selector(testMethod) withObject: @"test"];
4. 其他用法
unsigned int count;
//获取属性列表
objc_property_t *propertyList = class_copyPropertyList([MyClass class], &count);
for (unsigned int i = 0; i < count; i ++)
{
const char *propertyName = property_getName(propertyList[i]);
NSLog(@"property ----> %@", [NSString stringWithUTF8String: propertyName]);
}
//获取实例方法列表
Method *methodList = class_copyMethodList([MyClass class], &count);
for (unsigned int i = 0; i < count; i ++)
{
Method method = methodList[i];
NSLog(@"method ----> %@", NSStringFromSelector(method_getName(method)));
}
//获取成员变量列表
Ivar *ivarList = class_copyIvarList([MyClass class], &count);
for (unsigned int i = 0; i < count; i ++)
{
Ivar myIvar = ivarList[i];
const char *ivarName = ivar_getName(myIvar);
NSLog(@"Ivar ----> %@", [NSString stringWithUTF8String: ivarName]);
}
//获取协议列表
__unsafe_unretained Protocol **protocolList = class_copyProtocolList([MyClass class], &count);
for (unsigned int i = 0; i < count; i ++)
{
Protocol *myProtocal = protocolList[i];
const char *protocolName = protocol_getName(myProtocal);
NSLog(@"protocol ----> %@", [NSString stringWithUTF8String: protocolName]);
}