I'm experimenting with adding a form of theming support to iOS by swizzling UIColor constructor methods. I'm having trouble with a scenario coming from a storyboard when a control uses a "named color" (the ones added to the asset catalog manually). Printing the stack trace I can see before it gets to the UIColor(named: ....)
constructor which I was using, it calls UIColor initWithCoder
. I think if I can swizzle this instead and extract the "name" that was entered in the storyboard, it will solve my issue. (I'm aware this value will be passed in the other constructor, but I need to see if its possible from the coder constructor instead, long story)
I'm struggling to understand how to get this value out of the NSCoder
. I can't find any info on its underlying type of UINibDecoder
, debugger doesn't present any useful info, I don't know what keys/types the object uses so I can't call the coder.decode...
functions, and I can't find anything online regarding how to print all the keys/types. Any insights / help would be appreciated
Code I have currently is something along the lines of:
extension UIColor {
private static let originalCoderSelector = #selector(UIColor.init(coder:))
private static let swizzledCoderSelector = #selector(theme_color(withCoder:))
class func swizzleNamedColorInitToAddTheme() {
guard let originalCoderMethod = class_getInstanceMethod(self, originalCoderSelector),
let swizzledCoderMethod = class_getInstanceMethod(self, swizzledCoderSelector) else {
os_log("Unable to find UIColor methods to swizzle", log: .default, type: .error)
return
}
method_exchangeImplementations(originalCoderMethod, swizzledCoderMethod);
}
@objc func theme_color(withCoder coder: NSCoder) -> UIColor? {
print("coder being called")
print("coder test: \( coder.decodeObject(forKey: "backgroundColor") ) ")
print("coder test: \( coder.decodeObject(forKey: "color") ) ")
print("coder test: \( coder.decodeObject(forKey: "name") ) ")
print("coder test: \( coder.decodeObject(forKey: "namedColor") ) ")
print("coder test: \( coder.decodePropertyList(forKey: "backgroundColor") ) ")
print("coder test: \( coder.decodePropertyList(forKey: "color") ) ")
print("coder test: \( coder.decodePropertyList(forKey: "name") ) ")
print("coder test: \( coder.decodePropertyList(forKey: "namedColor") ) ")
return nil
}
}