如何归档文本带渐变色的UITextField?归档遇NSInternalInconsistencyException错误
解决NSKeyedArchiver归档渐变色UITextField时的颜色空间错误
这个问题我之前踩过坑!你碰到的NSInternalInconsistencyException错误,核心原因很明确:NSKeyedArchiver在处理颜色相关归档时,只支持RGBA或White单色空间的颜色,而渐变色本质是由多个颜色点组成的渐变图层,不属于这两种基础颜色空间,直接归档整个UITextField肯定会报错。
下面给你一套可行的解决方案,核心思路是:不直接归档UITextField实例,而是归档渐变色的关键参数,之后再通过这些参数重新构建控件和渐变效果。
步骤1:定义渐变信息的归档模型
先写一个遵循NSCoding的结构体,专门用来存储渐变色的必要参数(这样才能被归档):
import UIKit struct GradientInfo: NSCoding { let colors: [UIColor] let locations: [NSNumber]? let startPoint: CGPoint let endPoint: CGPoint // 编码逻辑:把参数存入NSCoder func encode(with coder: NSCoder) { coder.encode(colors, forKey: "colors") coder.encode(locations, forKey: "locations") coder.encode(startPoint.x, forKey: "startX") coder.encode(startPoint.y, forKey: "startY") coder.encode(endPoint.x, forKey: "endX") coder.encode(endPoint.y, forKey: "endY") } // 解码逻辑:从NSCoder中读取参数 init?(coder: NSCoder) { guard let colors = coder.decodeObject(forKey: "colors") as? [UIColor] else { return nil } self.colors = colors self.locations = coder.decodeObject(forKey: "locations") as? [NSNumber] let startX = coder.decodeDouble(forKey: "startX") let startY = coder.decodeDouble(forKey: "startY") self.startPoint = CGPoint(x: startX, y: startY) let endX = coder.decodeDouble(forKey: "endX") let endY = coder.decodeDouble(forKey: "endY") self.endPoint = CGPoint(x: endX, y: endY) } // 便捷初始化,方便创建渐变信息 init(colors: [UIColor], locations: [NSNumber]?, startPoint: CGPoint, endPoint: CGPoint) { self.colors = colors self.locations = locations self.startPoint = startPoint self.endPoint = endPoint } }
步骤2:归档时只存必要数据,不存整个UITextField
替换你原来的归档代码,提取UITextField的文本内容和渐变参数,打包后再归档:
// 先从你的UITextField中获取渐变层的信息(假设渐变是背景渐变,通过sublayer添加的) guard let gradientLayer = testerText.layer.sublayers?.first(where: { $0 is CAGradientLayer }) as? CAGradientLayer else { // 如果是文字渐变(用mask实现的),这里要换成你记录渐变参数的逻辑 return } // 封装渐变信息 let gradientInfo = GradientInfo( colors: gradientLayer.colors as? [UIColor] ?? [], locations: gradientLayer.locations, startPoint: gradientLayer.startPoint, endPoint: gradientLayer.endPoint ) // 打包需要归档的所有数据:文本、富文本(如果有)、渐变信息 let textFieldArchiveData: [String: Any] = [ "text": testerText.text ?? "", "attributedText": testerText.attributedText, "gradientInfo": gradientInfo ] // 执行归档 do { let data = try NSKeyedArchiver.archivedData(withRootObject: textFieldArchiveData, requiringSecureCoding: false) // 现在把这个data存入Core Data就没问题了 } catch { print("归档出错:\(error.localizedDescription)") }
步骤3:解归档时重建UITextField和渐变效果
在viewDidLoad或者需要恢复控件的地方,解码数据并重新构建控件:
override func viewDidLoad() { super.viewDidLoad() // 先从Core Data中取出归档的data(这里替换成你的实际取数逻辑) guard let archivedData = /* 你的Core Data获取代码 */ else { return } do { // 解码归档数据 guard let textFieldData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(archivedData) as? [String: Any] else { return } // 重建UITextField let restoredTextField = UITextField(frame: testerText.frame) restoredTextField.text = textFieldData["text"] as? String restoredTextField.attributedText = textFieldData["attributedText"] as? NSAttributedString // 重建渐变层 if let gradientInfo = textFieldData["gradientInfo"] as? GradientInfo { let gradientLayer = CAGradientLayer() gradientLayer.colors = gradientInfo.colors.map { $0.cgColor } gradientLayer.locations = gradientInfo.locations gradientLayer.startPoint = gradientInfo.startPoint gradientLayer.endPoint = gradientInfo.endPoint gradientLayer.frame = restoredTextField.bounds // 如果是背景渐变,把渐变层插入到最底层 restoredTextField.layer.insertSublayer(gradientLayer, at: 0) // 如果是文字渐变,把渐变层设为mask: // restoredTextField.layer.mask = gradientLayer } // 把重建好的UITextField添加到视图 view.addSubview(restoredTextField) } catch { print("解归档出错:\(error.localizedDescription)") } }
几个关键提醒
- 不要直接归档UI控件:UITextField这类UI控件包含大量视图层级和非归档友好的属性,直接归档很容易出问题,只存业务数据和样式参数才是稳妥的做法。
- 文字渐变的特殊处理:如果你的渐变色是文字颜色(不是背景),通常是通过给UITextField的layer设置mask实现的,这时候归档和解归档时要注意把渐变层设为mask,而不是普通的sublayer。
- 确保所有归档对象遵循NSCoding:比如
UIColor默认支持,但自定义的结构体/类必须自己实现编码和解码逻辑。
内容的提问来源于stack exchange,提问作者MD. Rejaul Hasan
相关产品推荐
相关产品推荐

