2

我正在尝试更改设备 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

4

1 回答 1

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);

翻译成斯威夫特那将是

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.

于 2016-04-08T17:42:24.440 回答