Swift - метод swizzling

Это метод, использующий код, написанный на Objective-C. Мне трудно преобразовать это в Swift.

void MPApplicationDidRegisterForRemoteNotificationsWithDeviceToken(id self, SEL _cmd, UIApplication *application, NSData *deviceToken) {
    [[MPPush shared] appRegisteredForRemoteNotificationsWithDeviceToken:deviceToken];

    IMP original = [MPAppDelegateProxy originalImplementation:_cmd class:[self class]];
    if (original)
        ((void(*)(id, SEL, UIApplication *, NSData*))original)(self, _cmd, application, deviceToken);
}  

Swiftify неправильно преобразует приведенный выше код.

Я пытался сделать это, но я не уверен, как передавать параметры и использовать точно указанные выше параметры в методе Swizzling Swift. Это моя неудачная попытка преобразовать приведенное выше в Swift (код даже не компилируется):

var MPApplicationDidRegisterForRemoteNotificationsWithDeviceToken: Void {
        //     TODO:   MPPush.shared.app

        let original = MPAppDelegateProxy.proxyAppDelegate.originalImplementation(selector: cmd, forClass: type(of: self))
    }(self: Any, _cmd: Selector, application: UIApplication, deviceToken: Data)

person Nitish    schedule 17.09.2018    source источник
comment
@Cristic: Разве я не могу сделать это Swift?   -  person Nitish    schedule 17.09.2018
comment
В каком классе определен этот метод?   -  person ielyamani    schedule 20.09.2018
comment
@Cristic: Потому что это не функция. Функция Objective-C начинается с -   -  person Nitish    schedule 03.10.2018
comment
@Cristic: Итак, это должна быть просто функция Swift?   -  person Nitish    schedule 03.10.2018


Ответы (1)


Расширьте свой класс:

extension YourClassName {
    static let classInit: () -> () = {
        let originalSelector = #selector(originalFunction)
        let swizzledSelector = #selector(swizzledFunction)
        swizzle(YourClassName.self, originalSelector, swizzledSelector)
    }

    @objc func swizzledFunction() {
        //Your new implementation
    }
}

Ваш класс (YourClassName) должен наследоваться от NSObject, а originalSelector должен быть методом dynamic.

swizzle — это замыкание, которое меняет реализации:

private let swizzle: (AnyClass, Selector, Selector) -> () = { fromClass, originalSelector, swizzledSelector in
    guard 
        let originalMethod = class_getInstanceMethod(fromClass, originalSelector),
        let swizzledMethod = class_getInstanceMethod(fromClass, swizzledSelector)
        else { return }
    method_exchangeImplementations(originalMethod, swizzledMethod)
}

Вы можете определить swizzle в классе, где вы собираетесь делать swizzling. Например, определение класса AppDelegate. А затем прокрутите AppDelegate.init():

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    override init() {
        super.init()
        YourClassName.classInit()
    }
}

Пример

Вот конкретный пример swizzling, он заменяет реализацию двух методов, которые взять один аргумент:

class Example: NSObject {
    @objc dynamic func sayHi(to name: String) {
        print("Hi", name)
    }
}

extension Example {
    public class func swizzleMethod() {
        guard
            let originalMethod = class_getInstanceMethod(Example.self, #selector(Example.sayHi(to:))),
            let swizzledMethod = class_getInstanceMethod(Example.self, #selector(Example.sayHello(to:)))
            else { return }
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
    @objc func sayHello(to name: String) {
        print("Hello", name)
    }
}

Example.swizzleMethod()

let a = Example()
a.sayHi(to: "Nitish")        //Hello Nitish
person ielyamani    schedule 20.09.2018
comment
Можете ли вы провести меня через свой ответ? Я сталкиваюсь с трудностями при преобразовании и вызове MPApplicationDidRegisterForRemoteNotificationsWithDeviceToken - person Nitish; 03.10.2018
comment
Я добавил конкретный пример методов swizzling - person ielyamani; 03.10.2018