我也很难将这些init
方法用于UIImage
. 我发现的唯一方法是改用类方法,这似乎工作正常(我首先尝试使用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")
}
}