【问题标题】:How to swizzle initialization method?如何调配初始化方法?
【发布时间】:2018-11-30 23:44:45
【问题描述】:

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

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

【问题讨论】:

    标签: objective-c initialization method-swizzling


    【解决方案1】:

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

    【讨论】:

    • 感谢您的解释,我决定避免在初始化方法上使用 swizzling
    猜你喜欢
    • 2016-08-13
    • 2016-09-30
    • 2020-01-12
    • 1970-01-01
    • 2010-11-08
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 2021-03-29
    相关资源
    最近更新 更多