1

我有一个带有 init 方法的类 MyOldController

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

我想将这个初始化方法转换为另一个,这是我的 swizzle 代码

@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 不起作用。它只是调用旧的初始化方法,而不是我的新方法。

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

4

1 回答 1

2

(从需要的警告开始:这是非常危险的,永远不应该在生产代码中使用。考虑到指定的初始化程序链接,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>
于 2018-06-21T16:27:47.750 回答