2016-04-08 4 views
2

Ich versuche, die currentLocale-Ausgabe des Geräts zu ändern, um einige interessante Komponententests durchzuführen. Dies ist der Code, den ich verwende, aber es scheint, dass die zurückgegebene currentLocale nicht Ich werde übergangen. Irgendein Hinweis?NSLocale verwendet Methode swizzling, um die currentLocale-Ausgabe zu Testzwecken zu ändern

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

Der obige Code funktioniert nicht. Aber wenn ich es so schreibe es funktioniert:

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

was mit class_addMethod in diesem Fall falsch ist?

Antwort

3

Ihre erste Methode wäre korrekt, eine Instanzmethode zu vertauschen, , aber nicht für eine Klassenmethode. Was geschieht - wenn ich es richtig verstanden habe - ist, dass

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

eine Instanzmethode zur Klasse fügt hinzu und gibt true. Dann

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

ersetzt eine Instanzmethode, die fehlschlägt.

Wenn man sich die Method Swizzling Artikel aus NSHipster suchen dann werden Sie den folgenden Kommentar finden:

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

zu Swift übersetzt, die

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

und dann das Umstellen funktioniert wie erwartet würde. (Der entscheidende Punkt ist, dass class_addMethod() auf das Klassenobjekt aufgerufen wird, nicht auf self.)

Aber eigentlich ich sehe keinen Vorteil gegenüber dem zweiten Verfahren. didAddMethod wird immer false zurückgeben, weil frLocale bereits als eine Klassenmethode von NSLocale definiert ist.

Verwandte Themen