2016-04-08 1 views
2

Я пытаюсь изменить вывод currentLocale устройства для выполнения некоторых интересных модульных тестов, это код, который я использую, но кажется, что возвращаемый currentLocale не работает, t переопределить. Любой намек?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

Ваш первый метод был бы правильным, чтобы swizzle метод экземпляра, , но не для метода класса. Что происходит - если я правильно понимаю - это то, что

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

добавляет метод экземпляра к классу, и возвращает true. Тогда

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

заменяет метод экземпляра, который терпит неудачу.

Если вы посмотрите на Method Swizzling статью из NSHipster, то вы найдете следующий комментарий:

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

, а затем swizzling работает, как ожидалось. (Решающим моментом является то, что class_addMethod() вызывается на объект класса, а не на self.)

Но на самом деле я не вижу никакого преимущества перед вашим вторым методом. didAddMethod всегда будет возвращать false, потому что frLocale уже определен как метод класса NSLocale.

Смежные вопросы