簡體   English   中英

Swizzling UIImage init 不工作 iOS Swift

[英]Swizzling UIImage init not working iOS Swift

我正在嘗試UIImage.init(named:)但沒有調用 init

extension UIImage {

    @objc public convenience init?(swizzledName: String) {
        self.init(named: swizzledName)

        /// Do something
        print("this is working")
    }

    static func swizzle() {
        guard let instance = class_getClassMethod(self, #selector(UIImage.init(named:))),
            let swizzledInstance = class_getClassMethod(self, #selector(UIImage.init(swizzledName:))) else { return }

        method_exchangeImplementations(instance, swizzledInstance)
    }
}

用法

UIImage.swizzle()
let image = UIImage(named: "avatar")

👆不工作

我也無法為UIImage這些init方法。 我發現的唯一方法是改用類方法,這似乎工作正常(我首先嘗試使用static方法,但沒有用,所以我嘗試了class方法,它確實有效):

func swizzle(originalClass: AnyClass,
             originalSelector: Selector,
             isOriginalSelectorClassMethod: Bool,
             swizzledClass: AnyClass,
             swizzledSelector: Selector,
             isSwizzledSelectorClassMethod: Bool) {
    guard let originalMethod = isOriginalSelectorClassMethod ?
        class_getClassMethod(originalClass, originalSelector) :
        class_getInstanceMethod(originalClass, originalSelector) else {
            return
    }

    guard let swizzledMethod = isSwizzledSelectorClassMethod ?
        class_getClassMethod(swizzledClass, swizzledSelector) :
        class_getInstanceMethod(swizzledClass, swizzledSelector) else {
            return
    }

    let didAddMethod = class_addMethod(isOriginalSelectorClassMethod ? object_getClass(originalClass)! : originalClass,
                                       originalSelector,
                                       method_getImplementation(swizzledMethod),
                                       method_getTypeEncoding(swizzledMethod))

    if didAddMethod {
        class_replaceMethod(isSwizzledSelectorClassMethod ? object_getClass(swizzledClass)! : swizzledClass,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod))
    } else {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

extension UIImage {
    static func swizzleInitializersIfNeeded() {
        guard !areInitializersSwizzled else {
            return
        }

        areInitializersSwizzled = true

        swizzle(originalClass: self,
                originalSelector: #selector(UIImage.init(named:)),
                isOriginalSelectorClassMethod: true,
                swizzledClass: self,
                swizzledSelector: #selector(UIImage.image(named:)),
                isSwizzledSelectorClassMethod: true)

        swizzle(originalClass: self,
                originalSelector: #selector(UIImage.init(named:in:with:)),
                isOriginalSelectorClassMethod: true,
                swizzledClass: self,
                swizzledSelector: #selector(UIImage.image(named:in:with:)),
                isSwizzledSelectorClassMethod: true)
    }

    private static var areInitializersSwizzled = false

    @objc fileprivate class func image(named name: String) -> UIImage? {
        let image = self.image(named: name)
        image?.name = name

        return image
    }

    @objc fileprivate class func image(named name: String,
                                       in bundle: Bundle,
                                       with config: UIImage.Configuration) -> UIImage? {
        let image = self.image(named: name, in: bundle, with: config)
        image?.name = name
        image?.bundle = bundle

        return image
    }

    private static var nameKey = 0
    private static var bundleKey = 0

    private(set) var name: String? {
        get { objc_getAssociatedObject(self, &UIImage.nameKey) as? String }
        set { objc_setAssociatedObject(self, &UIImage.nameKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
    }

    private(set) var bundle: Bundle? {
        get { objc_getAssociatedObject(self, &UIImage.bundleKey) as? Bundle }
        set { objc_setAssociatedObject(self, &UIImage.bundleKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) }
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        UIImage.swizzleInitializersIfNeeded()

        let image = UIImage(named: "test_image")

        print(image?.name as Any) // prints Optional("test_image")
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM