如何修复“该解码器仅能解码遵循NSSecureCoding协议的类,类‘UIImageView’未遵循该协议”错误?
解决UIImageView归档/解档的NSSecureCoding错误
你遇到的错误核心原因很明确:UIImageView(包括它的父类UIView)并没有遵循NSSecureCoding协议,而你使用的NSKeyedUnarchiver.unarchivedObject(ofClass:from:)方法会强制要求被解档的类必须支持安全编码,所以直接解档整个UIImageView实例会触发这个报错。
下面给你两种可行的解决方案,优先推荐第二种更稳妥的实现方式:
方案一:使用非安全解档方法(仅临时兼容,不推荐)
如果你只是需要快速绕过这个问题,可以使用苹果已经标记为废弃的unarchiveObject(with:)方法,它不会强制要求安全编码:
do { if let imageView = NSKeyedUnarchiver.unarchiveObject(with: data!) as? UIImageView { self.backgroundIV = imageView print("Un Archived...") } } catch { print(error) }
⚠️ 注意:这个方法在iOS 12及以上版本被废弃,存在安全风险(可能被恶意利用注入非法数据),仅建议用于旧项目临时兼容,不推荐在新代码中使用。
方案二:归档视图关键属性(推荐最佳实践)
直接归档整个UIView或其子类从来都不是最优选择——视图包含大量内部状态、层级结构和非归档友好的属性,容易出现解档失败、状态不一致等问题。更好的方式是提取你需要保留的核心属性,归档这些属性,解档时重新创建视图并赋值:
归档代码:
// 提取UIImageView的核心属性(按需添加更多,比如layer的圆角、边框等) guard let image = self.backgroundIV?.image, let frame = self.backgroundIV?.frame, let contentMode = self.backgroundIV?.contentMode else { return } // 用字典封装需要归档的属性 let viewProperties: [String: Any] = [ "image": image, "frame": frame, "contentMode": contentMode.rawValue, "cornerRadius": self.backgroundIV?.layer.cornerRadius ?? 0, "borderWidth": self.backgroundIV?.layer.borderWidth ?? 0, "borderColor": self.backgroundIV?.layer.borderColor ?? UIColor.clear.cgColor ] // 归档字典数据 let data = try? NSKeyedArchiver.archivedData(withRootObject: viewProperties, requiringSecureCoding: false)
解档代码:
do { guard let viewProperties = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data!) as? [String: Any], let image = viewProperties["image"] as? UIImage, let frame = viewProperties["frame"] as? CGRect, let contentModeRaw = viewProperties["contentMode"] as? Int, let contentMode = UIView.ContentMode(rawValue: contentModeRaw) else { return } // 重新创建UIImageView并赋值属性 let imageView = UIImageView(frame: frame) imageView.image = image imageView.contentMode = contentMode // 还原layer相关属性 imageView.layer.cornerRadius = viewProperties["cornerRadius"] as? CGFloat ?? 0 imageView.layer.borderWidth = viewProperties["borderWidth"] as? CGFloat ?? 0 imageView.layer.borderColor = viewProperties["borderColor"] as? CGColor self.backgroundIV = imageView print("Un Archived...") } catch { print(error) }
这种方式的优势很明显:
- 规避了直接归档视图的安全和兼容性问题
- 只保存你真正需要的状态,缩小归档数据体积
- 解档后的视图状态完全可控,避免莫名的层级或渲染bug
内容的提问来源于stack exchange,提问作者Ali Akbar
相关产品推荐
相关产品推荐

