首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UIColor initWithCoder提取颜色名称

UIColor initWithCoder提取颜色名称
EN

Stack Overflow用户
提问于 2022-04-22 16:36:26
回答 1查看 65关注 0票数 0

我正在尝试通过swizzling iOS构造函数方法向UIColor添加一种形式的主题支持。当控件使用“命名颜色”(手动添加到资产目录中的颜色)时,我遇到了来自情节提要的场景的问题。在将堆栈跟踪打印到我所使用的UIColor(named: ....)构造函数之前,它会调用UIColor initWithCoder。我想,如果我能用它来代替,提取在故事板中输入的“名称”,它将解决我的问题。(我知道这个值将在另一个构造函数中传递,但我需要看看它是否可能来自编码器构造函数,长话短说)

我很难理解如何从NSCoder中获取这个值。我找不到关于它的底层UINibDecoder类型的任何信息,调试器没有提供任何有用的信息,我不知道对象使用什么键/类型,所以我不能调用coder.decode...函数,我也找不到任何关于如何打印所有键/类型的在线信息。如有任何见解/帮助,将不胜感激

我目前拥有的代码大致如下:

代码语言:javascript
复制
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
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-23 09:12:06

利用this answer中的这种技术,我们可以通过对NSKeyedUnarchiver.decodeObject(forKey:)进行切换来获得编码密钥。

代码语言:javascript
复制
extension NSKeyedUnarchiver {
    private static let originalDecodeObject = #selector(NSKeyedUnarchiver.decodeObject(forKey:))
    private static let swizzledDecodeObject = #selector(swizzledDecodeObject)

    @objc
    func swizzledDecodeObject(forKey key: String) -> Any? {
        print("Key:", key)
        return swizzledDecodeObject(forKey: key)
    }

    class func swizzle() {
        if let orig = class_getInstanceMethod(self, originalDecodeObject),
           let new = class_getInstanceMethod(self, swizzledDecodeObject) {
            method_exchangeImplementations(orig, new)
        }
    }
}

然后,您可以对颜色进行编码和解码,以查看哪些键被解码:

代码语言:javascript
复制
let data = try! NSKeyedArchiver.archivedData(withRootObject: UIColor(named: "foo"), requiringSecureCoding: false)
let decoded = try! NSKeyedUnarchiver.unarchivedObject(ofClass: UIColor.self, from: data)

在iOS 15.0上,这是我在资产目录中添加的颜色的打印:

代码语言:javascript
复制
Key: root
Key: UIDynamicModifiedBaseColor
Key: UIDynamicCatalogName
Key: UIDynamicCatalogBundleIdentifier
Key: UIDynamicCatalogBundleLibraryName

从列表中可以看出,使用一些常识,UIDynamicCatalogName似乎是您要寻找的关键。

请注意,这将不适用于基色如systemRed,或系统颜色如systemBackground。对于后者,您应该使用键UISystemColorName (您可以通过编码和解码.systembackground找到这一点)。对于前者,还不清楚用什么键来编码它。通过编码和解码.systemYellow,我们可以看到与.systembackground相同的密钥,但使用UISystemColorName似乎不起作用。可能是不同的编码方式..。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71972024

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档