method_exchangeImplementations使用时需要注意self类型改变

204 阅读1分钟

1.定义一盒ZBJPerson类

@interface ZBJPerson : NSObject

@property (nonatomic, copy) NSString *name;

- (void)logName;
- (void)logSomething;

@end

#import "ZBJPerson.h"

@interface ZBJPerson()

@property(nonatomic, strong) NSNumber *weight;

@end

@implementation ZBJPerson

- (void)logName {
    NSLog(@"name:%@",_name);
}

- (void)logSomething {
    NSLog(@"something");
}

@end

2.在ZBJRuntimeExample尝试交互logName实现。

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface ZBJRuntimeExample : NSObject

- (void)exchangeImplementations;

@end

#import "ZBJRuntimeExample.h"
#import <objc/runtime.h>
#import "ZBJPerson.h"

@interface ZBJRuntimeExample()

@property(nonatomic, strong) ZBJPerson *person;
@property (nonatomic, copy) NSString *name;

@end

@implementation ZBJRuntimeExample

- (instancetype)init {
    self = [super init];
    if (self) {
        _person = [ZBJPerson new];
    }
    return self;
}

- (void)logName {
//    NSLog(@"my name is :%@", _person.name);//会crash
//    NSLog(@"my name is :%@", self.name);//输出结果 my name is :xxx
    NSLog(@"my name is :%@", [self valueForKey:@"_name"]);
    //    [self logSomething];//直接报错,无法编译通过
    [self performSelector:@selector(logSomething)];
}

- (void)exchangeImplementations {
    _person.name = @"xxx";
    self.name = @"123";
    Method oriMethod = class_getInstanceMethod(_person.class, @selector(logName));
    Method curMethod = class_getInstanceMethod(self.class, @selector(logName));
    method_exchangeImplementations(oriMethod, curMethod);
    [_person logName];
}
@end

注意方法交换以后,ZBJRuntimeExample的logName方法里面不能使用ZBJRuntimeExample的属性和方法。应该使用ZBJPerson的属性和方法,此时logName的self是ZBJPerson而不是ZBJRuntimeExample。属性可以用KVC,方法可以用performSelector。