1

我想尝试 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],我得到了无限循环,根据我链接的文章,这不应该发生。我在这段代码中看不到错误。

4

4 回答 4

1

问题出在语法上,而不是

SEL originalSelector = @selector(originalMethod:);
SEL swizzledSelector = @selector(newMethod:);

我应该写:

SEL originalSelector = @selector(originalMethod);
SEL swizzledSelector = @selector(newMethod);

xCode 只给了我一个警告,所以我认为选择器名称没有错。

于 2014-11-22T23:57:27.453 回答
0

看起来你在调配类方法:

Class class = [self class];

指向+load上下文中的元类,尝试明确指定它,即

Class class = [CustomClass class];
// or
Class class = self;

另外,@bbum 说了什么

于 2014-11-23T14:33:32.440 回答
0
    class_replaceMethod(class,
                        swizzledSelector,
                        method_getImplementation(originalMethod),
                        method_getTypeEncoding(originalMethod));

method_getImplementation(originalMethod)应该swizzledMethod吗?

于 2014-11-21T17:15:50.983 回答
0
  1. 语法错误,运行时会发送不同的消息。

    SEL originalSelector = @selector(originalMethod);
    SEL swizzledSelector = @selector(newMethod);
    
  2. 如果第一种方法没有效果。试试看:

    BOOL didAddMethod =
    class_addMethod(class, originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));
    
    if (didAddMethod) {
        method_exchangeImplementations(originalMethod, swizzledMethod);
    
    }
    

交换实施可能会产生的影响。

于 2016-07-09T04:28:28.893 回答