如何调配初始化方法?
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>
我有一个 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>