如何调配初始化方法?

How to swizzle initialization method?

我有一个 class 带有初始化方法的 MyOldController

    -(instancetype) initWithMyController: (MyController *) myController {
    if((self = [self init])) {
        _myController = myController;
    }
    return self;
}

我想将这个初始化方法调配到另一个,这是我的调配代码

@implementation MyOldController(Swizzle)

+ (void)load {
    [MyOldController swizzleMethods];
}

+ (void)swizzleMethods {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(initWithMyController)), class_getInstanceMethod(self, @selector(swizzle_ initWithMyController)));
}

我试着写这个

-(instancetype) swizzle_initWithMyController: (MyController *) myController {
    if((self = [self init])) {
        _myController = myController;
    }
    return self;
}

但是它会报错

然后我将 init 方法重命名为此并更新 (void)swizzleMethods

-(instancetype) initWithMyController_swizzle: (MyController *) myController {
    if((self = [self init])) {
        _myController = myController;
    }
    return self;
}

错误消息消失但 swizzle 不起作用。它只是调用旧的初始化方法,而不是我的新方法。

我错过了哪一点?初始化方法的调配有一些特殊的方法吗?

(从必要的警告开始:这是非常危险的,永远不应该在生产代码中使用。考虑到指定的初始化程序链接,Swizzling 初始化程序特别危险,除了探索和调试之外,绝对不应该在没有首先确认的情况下进行任何操作swizzled 初始化器的实现。好吧,把它拿开。)

我无法重现您的问题。初始化程序应始终以 init 开头,因此您的第二种方法是正确的。我怀疑您只是犯了一个小错误,也许是在您的 @selector 中(您的问题中有错字,这表明您的实际代码中可能存在错误)。这是执行您所描述内容的代码。

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface MyOldController: NSObject
- (instancetype)initWithInt:(NSInteger)x
@end

@implementation MyOldController
- (instancetype)initWithInt:(NSInteger)x
{
    self = [super init];
    if (self) {
        NSLog(@"init");
    }
    return self;
}
@end

@implementation MyOldController(Swizzle)

+ (void)load {
    [MyOldController swizzleMethods];
}

+ (void)swizzleMethods {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(initWithInt:)), class_getInstanceMethod(self, @selector(initWithInt_swizzle:)));
}

- (instancetype)initWithInt_swizzle:(NSInteger)x
{
    self = [super init];
    if (self) {
        NSLog(@"init_swizzle");
    }
    return self;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        MyOldController *controller = [[MyOldController alloc] initWithInt:1];
        NSLog(@"%@", controller);
    }
    return 0;
}

如预期的那样打印:

2018-06-21 12:23:14.431936-0400 test[30981:401466] init_swizzle
2018-06-21 12:23:14.432172-0400 test[30981:401466] <MyOldController: 0x10051ee10>