Objective-C Method Swizzling 示例不起作用
Posted
技术标签:
【中文标题】Objective-C Method Swizzling 示例不起作用【英文标题】:Objective-C Method Swizzling example not working 【发布时间】:2014-11-21 13:24:50 【问题描述】:我想尝试 Method Swizzling 以清楚地了解它是如何工作的。 查看此代码:http://nshipster.com/method-swizzling/。 我已经创建了一个类和一个类别,这里是代码
#import <Foundation/Foundation.h>
@interface CustomClass : NSObject
-(void) originalMethod;
@end
类的实现
#import "CustomClass.h"
@implementation CustomClass
-(id) init
self = [super init];
return self;
-(void) originalMethod
NSLog(@"I'm the original method");
@end
类别标题:
#import "CustomClass.h"
@interface CustomClass (CustomCategory)
-(void) newMethod;
@end
分类实现
#import "CustomClass+CustomCategory.h"
#include <objc/runtime.h>
@implementation CustomClass (CustomCategory)
-(void) newMethod
[self newMethod];
NSLog(@"I'm the new method");
+(void) load
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
Class class = [self class];
// When swizzling a class method, use the following:
// Class class = object_getClass((id)self);
SEL originalSelector = @selector(originalMethod:);
SEL swizzledSelector = @selector(newMethod:);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod)
class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
else
method_exchangeImplementations(originalMethod, swizzledMethod);
);
@end
这里是主要的:
#import <Foundation/Foundation.h>
#import "CustomClass.h"
#import "CustomClass+CustomCategory.h"
int main(int argc, const char * argv[])
@autoreleasepool
CustomClass *cc = [[CustomClass alloc] init];
[cc newMethod];
return 0;
当我调用[cc newMethod]
时,我得到了无限循环,根据我链接的文章,这不应该发生。
我在这段代码中看不到错误。
【问题讨论】:
你确定调用的是load方法吗? @user1963877 不,我没有检查过。应该调用它,因为它是 NSObject 中存在的方法。 这里有一些关于使用+(void)load
link的内容。请注意,您的教程涉及普通的 CocoaTouch 应用程序(带有 ui 线程等),而您在基本上是裸露的 hello world 程序上尝试它,所以它的行为可能不同。
@user1963877 不会有所作为。
我知道你发现了问题,但还有一件事:这本身并没有错,但你是从main()
调用[cc newMethod]
。当您混合方法时,通常的意图是新方法是隐藏的实现细节。客户将使用旧方法,而 swizzling 的目的是改变其行为。我知道您可能只是在尝试,但想确保您了解它应该如何工作。
【参考方案1】:
问题出在语法上,而不是
SEL originalSelector = @selector(originalMethod:);
SEL swizzledSelector = @selector(newMethod:);
我应该写:
SEL originalSelector = @selector(originalMethod);
SEL swizzledSelector = @selector(newMethod);
xCode 只给了我一个警告,所以我认为选择器名称没有错。
【讨论】:
【参考方案2】: class_replaceMethod(class,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
method_getImplementation(originalMethod)
不应该是swizzledMethod
吗?
【讨论】:
【参考方案3】:你好像在混用类方法:
Class class = [self class];
指向+load
上下文中的元类,尝试显式指定它,即
Class class = [CustomClass class];
// or
Class class = self;
另外,@bbum 说了什么
【讨论】:
【参考方案4】:语法错误,运行时会发送不同的消息。
SEL originalSelector = @selector(originalMethod);
SEL swizzledSelector = @selector(newMethod);
如果第一种方法没有效果。试试看:
BOOL didAddMethod =
class_addMethod(class, originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod)
method_exchangeImplementations(originalMethod, swizzledMethod);
交换实施可能产生的影响。
【讨论】:
以上是关于Objective-C Method Swizzling 示例不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Objective-C Method Swizzling 示例不起作用
Objective-C Runtime 运行时之四:Method Swizzling
iOS面试粮食Runtime—消息传递和转发机制Method Swizzling
iOS面试粮食Runtime—消息传递和转发机制Method Swizzling