NSLocale使用方法调配来更改currentLocale输出以进行测试

时间:2016-04-08 11:32:52

标签: swift testing swizzling

我试图更改设备currentLocale输出以执行一些有趣的单元测试,这是我正在使用的代码,但似乎返回的currentLocale没有被覆盖。任何提示?

extension NSLocale {
    class func frLocale()->NSLocale{
        return NSLocale(localeIdentifier: "fr_FR")
    }

    class func forceCurrentLocale(){
        let originalSelector = #selector(NSLocale.currentLocale)
        let swizzledSelector = #selector(self.frLocale)

        let originalMethod = class_getClassMethod(self, originalSelector)
        let swizzledMethod = class_getClassMethod(self, swizzledSelector)

        let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

//编辑

上面的代码不起作用。但是,如果我这样写它就可以了:

class func forceCurrentLocale(){
    let originalSelector = #selector(NSLocale.currentLocale)
    let swizzledSelector = #selector(NSLocale.frLocale)

    let originalMethod = class_getClassMethod(self, originalSelector)
    let swizzledMethod = class_getClassMethod(self, swizzledSelector)

    method_exchangeImplementations(originalMethod, swizzledMethod)
}

在这种情况下class_addMethod出了什么问题?

1 个答案:

答案 0 :(得分:3)

你的第一种方法是正确的混合实例方法, 但不适用于班级方法。 如果我理解正确的话会发生什么

let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

在类中添加实例方法,并返回true。然后

 class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))

替换失败的实例方法

如果你看一下NSHipster的Method Swizzling文章,你会发现以下评论:

// When swizzling a class method, use the following:
// Class class = object_getClass((id)self);
// ...
// Method originalMethod = class_getClassMethod(class, originalSelector);
// Method swizzledMethod = class_getClassMethod(class, swizzledSelector);

转换为Swift,这将是

class func forceCurrentLocale(){
    let originalSelector = #selector(NSLocale.currentLocale)
    let swizzledSelector = #selector(self.frLocale)

    let classObject : AnyClass = object_getClass(self)

    let originalMethod = class_getClassMethod(classObject, originalSelector)
    let swizzledMethod = class_getClassMethod(classObject, swizzledSelector)

    let didAddMethod = class_addMethod(classObject, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

    if didAddMethod {
        class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

然后如预期般的混合工作。 (关键是这一点 class_addMethod()在类对象上调用,而不在self上调用。)

但实际上我没有看到你的第二种方法有任何优势。 didAddMethod将始终返回false,因为frLocale 已被定义为NSLocale的类方法。