Swizzling не работает для методов класса

Swizzling не выполняет динамический обмен методами. Этот код, который я использовал. Я слышал, что это решение, в котором инъекция зависимости не может сделать в XCTest в xcode 7. Можете ли вы дать мне объяснение Swizzling over DI(Dependency) с примером?

#import "TNUserDetail+Swizzle.h"
#import <objc/runtime.h>

@implementation TNUserDetail (Swizzle)

+ (void) swizzleInstanceSelector:(SEL)originalSelector
                 withNewSelector:(SEL)newSelector
{
    Method originalMethod = class_getClassMethod(self, originalSelector);
    Method newMethod = class_getClassMethod(self, newSelector);

    BOOL methodAdded = class_addMethod([self class],
                                       originalSelector,
                                       method_getImplementation(newMethod),
                                       method_getTypeEncoding(newMethod));

    if (methodAdded) {
        class_replaceMethod([self class],
                            newSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, newMethod);
    }
}

+(BOOL)isSignUpSwizzle {

    return sighUp;
}


Test
_____

@implementation TNSettingsViewControllerTests

- (void)setUp {
    [super setUp];

    UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];

    self.settingVC = [sb instantiateViewControllerWithIdentifier:@"TNSettingsViewController"];


    [self.settingVC performSelectorOnMainThread:@selector(loadView) withObject:nil waitUntilDone:YES];
    [self.settingVC performSelectorOnMainThread:@selector(viewWillAppear:) withObject:nil waitUntilDone:YES];
}

-(void)testTwitterConnectSwitchValueChanged
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        [TNUserDetail swizzleInstanceSelector:@selector(isSignUpWithTwitter) withNewSelector:@selector(isSignUpSwizzle)];
        [TNUserDetail isSignUpWithTwitter];
    });

    sighUp = YES;
    self.settingVC.twitterConnectSwitch.on = YES;
    [self.settingVC.twitterConnectSwitch sendActionsForControlEvents:UIControlEventValueChanged];;
}

Здесь, когда я вызываю [TNUserDetail isSignUpWithTwitter],+(BOOL)isSignUpSwizzle не вызывается, а вызывается только фактический метод. Что не так. Обратите внимание, что оба метода являются методами класса.

1 ответ

Решение

Экземпляр методов существует в классе таблицы диспетчеризации, но методы класса существуют в таблице метаданных диспетчеризации, поэтому вам нужно использовать "метакласс" вместо self(class).

#import "TNUserDetail.h"
#import <objc/runtime.h>

@implementation TNUserDetail

+ (void)swizzleInstanceSelector:(SEL)originalSelector withNewSelector:(SEL)newSelector {
    const char *className = [NSStringFromClass(self) UTF8String];
    Class clazz = objc_getMetaClass(className);
    Method originalMethod = class_getClassMethod(clazz, originalSelector);
    Method newMethod = class_getClassMethod(clazz, newSelector);

    BOOL methodAdded = class_addMethod(clazz,
                                       originalSelector,
                                       method_getImplementation(newMethod),
                                       method_getTypeEncoding(newMethod));

    if (methodAdded) {
        class_replaceMethod(clazz,
                            newSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
    } else {
        method_exchangeImplementations(originalMethod, newMethod);
    }
}

+ (void)load {
    [super load];
    [self swizzleInstanceSelector:@selector(printHello) withNewSelector:@selector(printHelloWorld)];
}

+ (void)printHello {
    NSLog(@"Hello");
}

+ (void)printHelloWorld {
    NSLog(@"Hello World");
}

@end

и позвонить [TNUserDetail printHello]; распечатать "Hello World"

Но твоя буря влияет на весь проект. Для этого случая я рекомендую использовать частичные mocks ( OCMock)

Другие вопросы по тегам