2016-04-08 4 views
2

デバイスのcurrentLocale出力を変更して興味深いユニットテストを実行しようとしていますが、これは私が使用しているコードですが、currentLocaleが 'オーバーライドされる。何かヒント?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) 
     } 
    } 
} 

// EDIT

上記のコードは動作しません。しかし、私がこのように書くと、それは動作します:

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に何が問題なのですか?

答えて

3

最初の方法は、インスタンスメソッド を有効にするが、クラスメソッドでは有効にしないでください。私はそれを正しく理解すれば - - 何が起こる は

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

クラスにインスタンスメソッドを追加することで、trueを返します。その後

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

失敗インスタンスメソッドを、置き換えられます。

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

なると予想されるように、その後スウィズリングが機能するでしょうスウィフトに翻訳

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

:あなたはNSHipsterからMethod Swizzling記事を見れば

あなたは次のコメントを見つけることができます。 (重要な点は、selfではなく、 class_addMethod()が呼び出され、selfではなく)です。

実際に私はあなたの2番目の方法よりも利点はありません。 didAddMethodは、frLocale がすでにNSLocaleのクラスメソッドとして定義されているため、常にfalseを返します。