Свизлинг UILabel

swizzle

#1

Где это может пригодиться? Везде, где требуется изменить лейбл в контролах, не дающих это сделать. UIDatePicker, как пример. А дизайн требует!

В данном примере мы заменим шрифт UILabel внутри пикера:

extension UILabel {

    @objc func setFontSwizzled(font: UIFont) {
        if self.shouldOverride() {
            guard let rubikMedium = R.font.rubikMedium(size: 22) else { return }
            self.setFontSwizzled(font: rubikMedium)
        }
        else {
            self.setFontSwizzled(font: font)
        }
    }

    private func shouldOverride() -> Bool {
        let classes = ["UIDatePicker", "UIDatePickerWeekMonthDayView", "UIDatePickerContentView"]
        var view = self.superview
        while view != nil {
            let className = NSStringFromClass(type(of: view!))
            if classes.contains(className) {
                return true
            }
            view = view!.superview
        }
        return false
    }

    private static let swizzledSetFontImplementation: Void = {
        let instance = UILabel()
        let aClass: AnyClass! = object_getClass(instance)
        let originalMethod = class_getInstanceMethod(aClass, #selector(setter: font))
        let swizzledMethod = class_getInstanceMethod(aClass, #selector(setFontSwizzled))

        if let originalMethod = originalMethod, let swizzledMethod = swizzledMethod {
            // Switch implementation..
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }()

    static func swizzleSetFont() {
        _ = self.swizzledSetFontImplementation
    }

}

Использовать можно так:

@IBOutlet private(set) weak var datePicker: UIDatePicker! {
        didSet {
            let locale = Locale(identifier: "ru_RU")
            datePicker.locale = locale
            datePicker.setValue(R.color.mainViolet(), forKey: "textColor")
            datePicker.setValue(false, forKey: "highlightsToday")
            UILabel.swizzleSetFont() // <==================
            datePicker.minimumDate = Date().adding(years: -50)
            datePicker.maximumDate = Date()
        }
    }

Что в итоге?