Swizzling, вызывающий рекурсию

Поэтому, когда я попытался swizzle UIImage's init(named:), чтобы я мог установить идентификатор доступности с именем изображения, кажется, что, хотя я вызываю method_exchangeImplementation, оба моих swizzled метода ftg_imageNamed(named name: String) и init(named:) вызывают мой swizzled метод: ftg_imageNamed(named name: String) создавая бесконечный цикл. Почему это?

Звонок method_exchangeImplementation

extension UIImage {

    static func swizzleInitImplementation() {
        let originalSelector =  #selector(UIImage.init(named:))
        let swizzledSelector = #selector(UIImage.ftg_imageNamed(named:))


        let imgSelf: AnyClass = self.classForCoder()

        guard  let originalMethod = class_getClassMethod(imgSelf, originalSelector),
            let swizzledMethod = class_getClassMethod(imgSelf, swizzledSelector) else {
                assertionFailure("The methodsw are not found")
                return
        }

        method_exchangeImplementations(originalMethod, swizzledMethod)
    }

    @objc static func ftg_imageNamed(named name: String)  {
        setAccessibilityLabel(name)
        self.ftg_imageNamed(named: name)
    }

}

Ручная реализация, которая потерпела неудачу так же.

extension UIImage {

    static func swizzleInitImplementation() {
        let originalSelector =  #selector(UIImage.init(named:))
        let swizzledSelector = #selector(UIImage.ftg_imageNamed(named:))


        let imgSelf: AnyClass = self.classForCoder()

        guard  let originalMethod = class_getClassMethod(imgSelf, originalSelector),
            let swizzledMethod = class_getClassMethod(imgSelf, swizzledSelector) else {
                assertionFailure("The methodsw are not found")
                return
        }

        let imp1 = method_getImplementation(originalMethod)
        let imp2 = method_getImplementation(swizzledMethod)
        method_setImplementation(originalMethod, imp2)
        method_setImplementation(swizzledMethod, imp1)

    }

    @objc static func ftg_imageNamed(named name: String)  {
        setAccessibilityLabel(name)
        self.ftg_imageNamed(named: name)
    }

}

person ScottyBlades    schedule 13.01.2019    source источник
comment
что такое self.UI(named: name)?   -  person vikingosegundo    schedule 13.01.2019
comment
исправлено. @vikingosegundo, вы понизили голос из-за опечатки?   -  person ScottyBlades    schedule 13.01.2019
comment
Вы вызываете метод ftg_imageNamed из самого себя во время swizzling. Вот ваша причина рекурсии.   -  person x4h1d    schedule 13.01.2019
comment
@ x4h1d, насколько я понимаю, когда вы swizzle, вы говорите компилятору вызывать метод 2, когда он говорит вызвать метод 1, и вызывать метод 1, когда он говорит вызывать метод 2. trinhngocthuyen.github.io/. Соответственно, рекурсии быть не должно.   -  person ScottyBlades    schedule 13.01.2019
comment
да, это после выполнения swizzleInitImplementation, не в состоянии реализации swizzleInitImplementation. Когда вы вызываете swizzleInitImplementation, он вызывает ftg_imageNamed. Поскольку swizzling еще не реализован, self.ftg_imageNamed(named: name) вызовет сам себя. Следовательно, рекурсия.   -  person x4h1d    schedule 13.01.2019
comment
Он не вызывает ftg_imageNamed, когда я звоню swizzleInitImplementation. Однако он вызывает ftg_imageNamed, когда я позже вызываю инициализатор UIImage(named:).   -  person ScottyBlades    schedule 13.01.2019
comment
Я не минусовал его из-за опечатки. Я проголосовал за него, потому что эта опечатка сделала невозможным ответ на этот вопрос.   -  person vikingosegundo    schedule 13.01.2019
comment
@vikingosegundo, спасибо за отмену.   -  person ScottyBlades    schedule 13.01.2019
comment
Я хочу подчеркнуть, что в отличие от Objective-C inits не являются обычными функциями. они не имеют тип func, а также у них нет оператора возврата. Я не знаю, какие последствия это имеет для swizzling, но я не ожидал, что они будут вести себя хорошо.   -  person vikingosegundo    schedule 13.01.2019
comment
@vikingosegundo. Действительно хорошее замечание, мне было интересно об этом.   -  person ScottyBlades    schedule 13.01.2019


Ответы (1)


Ваш swizzling выглядит "хорошо" до self.UI(named: name). Так что проверьте этот метод на проблему с бесконечным циклом.

Это плохая реализация swizzling. UIImage.init(named:) возвращает экземпляр UIImage, где swizzled-метод UIImage.ftg_imageNamed(named:) возвращает Void. И исходный, и измененный метод должны иметь одинаковые параметры и тип возвращаемого значения, реализация может различаться.

Вы должны рассмотреть простой метод расширения, чтобы достичь того, чего вы хотите, вместо того, чтобы размахивать.

Изменить

extension UIImage {
    static func initIncludingAccessibility(named: String) -> UIImage {
       let img = UIImage(named: named)
       img.setAccessibilityLabel(named)
       return img
    }
}

использовать его как

let image = UIImage.initIncludingAccessibility(named: /* your_image_name*/)
person x4h1d    schedule 13.01.2019
comment
Извините, это была опечатка. You should consider a simple extension method to achieve what you want instead of swizzling. Я весь в ушах. Как я могу это сделать? - person ScottyBlades; 13.01.2019
comment
Для этого нам нужно знать, чего вы хотите достичь. - person x4h1d; 13.01.2019
comment
Когда создается экземпляр UIImage, я хочу, чтобы идентификатор доступности автоматически устанавливался равным имени актива изображения. - person ScottyBlades; 13.01.2019
comment
Ах, для этого потребуется изменить всю инициализацию UIImage. Я хочу, чтобы это изменение произошло без изменения текущего кода. - person ScottyBlades; 13.01.2019
comment
Сделайте простые задачи простыми! – Бьерн Страуструп. Удачи. - person x4h1d; 13.01.2019
comment
Давайте продолжим обсуждение в чате. - person ScottyBlades; 13.01.2019