【问题标题】:Swizzling UIImage init not working iOS SwiftSwizzling UIImage init 不工作 iOS Swift
【发布时间】:2020-05-18 21:40:07
【问题描述】:

我正在尝试调配 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.swizzle() 方法?
  • 我不明白这个问题? @RamMani

标签: ios objective-c swift uiimage method-swizzling


【解决方案1】:

我在为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")
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 1970-01-01
    相关资源
    最近更新 更多