NSLocale使用方法swizzling改变currentLocale输出为测试目的

问题描述:

我想改变设备currentLocale输出执行一些有趣的单元测试,这是我使用的代码,但它似乎返回currentLocale doesn'不会被覆盖。任何提示?NSLocale使用方法swizzling改变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有什么问题?

你的第一种方法是修改实例方法 ,但不适用于类方法。 会发生什么 - 如果我理解正确的话 - 是

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的类方法。