如何为指定实例调配方法?

How to swizzling method for a designative instance?

class Person:

@implementation Person

- (void)sayHi {
    NSLog(@"hi");
}

- (void)sayHello {
    NSLog(@"hello");
}

- (void)swizzlingMethod {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL HI_SEL = @selector(sayHi);
        SEL HELLO_SEL = @selector(sayHello);

        Method HI_METHOD = class_getInstanceMethod(self.class, HI_SEL);
        Method HELLO_METHOD = class_getInstanceMethod(self.class, HELLO_SEL);

        BOOL addSuccess = class_addMethod(self.class, HI_SEL, method_getImplementation(HELLO_METHOD), method_getTypeEncoding(HELLO_METHOD));
        if (addSuccess) {
            class_replaceMethod(self.class, HI_SEL, method_getImplementation(HELLO_METHOD), method_getTypeEncoding(HELLO_METHOD));
        } else {
            method_exchangeImplementations(HI_METHOD, HELLO_METHOD);
        }
    });
}

@end

Person的实例调用swizzlingMethod时,方法sayHi和方法sayHello会互换

然而,一旦实例调用swizzlingMethod,实例的所有方法将被交换:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    Person *person1 = [Person new];
    [person1 swizzlingMethod];
    [person1 sayHi];

    Person *person2 = [Person new];
    [person2 sayHi];
}

控制台打印了 hellohello,即使 person2 没有调用 swizzlingMethod

我想要的只是person1的方法exchanged.So有什么方法可以帮助实现吗?

在 Xcode 10.2.1 中,您可以将 swizzlingMethod 声明为 class 方法并像 [Person swizzlingMethod] 一样调用它,而无需更改实现。这意味着此方法为 Person 的所有实例交换 sayHisayHello 的实现。您不能为特定对象执行此操作,请参阅 this answer 了解更多详细信息。

另外,你有逻辑错误,把class_replaceMethod(self.class, HI_SEL, method_getImplementation(HELLO_METHOD), method_getTypeEncoding(HELLO_METHOD));换成class_replaceMethod(self.class, HELLO_SEL, method_getImplementation(HI_METHOD), method_getTypeEncoding(HI_METHOD));