You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Core Data中存储UIView子类或UIBezierPath?

嘿,我之前也碰到过这个坑!你这里的问题其实出在对NSValue的用法理解上——myView as NSValue是行不通的,因为NSValue是用来包装基础数据类型(比如CGRect、CGPoint这类)的,不是直接把UIView整个转成NSValue。咱们分两种情况来解决,看你实际需求是存frame还是整个View:

方案1:只存View的Frame(最简单,不需要自定义Transformer)

如果你的目标只是存储View的frame,那完全不用搞复杂的ValueTransformer,直接处理CGRect就行:

  1. 先在Core Data模型里,给对应的实体加一个Transformable类型的属性(比如命名为storedFrame),默认配置就够用,不用额外改Transformer类。
  2. 存储时,把View的frame转成NSValue再存:
    let frameValue = NSValue(cgRect: myView.frame)
    yourCoreDataEntity.storedFrame = frameValue
    // 记得保存Core Data上下文
    try? context.save()
    
  3. 读取时,把NSValue转回到CGRect:
    if let savedFrameValue = yourCoreDataEntity.storedFrame as? NSValue {
        myView.frame = savedFrameValue.cgRectValue
    }
    

方案2:存整个UIView(需要自定义ValueTransformer)

如果你确实要存储整个UIView(而不只是frame),那才需要用到自定义ValueTransformer,利用UIView遵循的NSCoding协议来归档/解档:

步骤1:创建自定义Transformer类

class ViewArchiveTransformer: ValueTransformer {
    // 告诉Core Data转换后的类型是Data
    override class func transformedValueClass() -> AnyClass {
        return Data.self
    }
    
    // 支持逆向转换(Data转回UIView)
    override class func allowsReverseTransformation() -> Bool {
        return true
    }
    
    // 把UIView归档成Data
    override func transformedValue(_ value: Any?) -> Any? {
        guard let targetView = value as? UIView else { return nil }
        do {
            return try NSKeyedArchiver.archivedData(withRootObject: targetView, requiringSecureCoding: false)
        } catch {
            print("归档View失败:\(error.localizedDescription)")
            return nil
        }
    }
    
    // 把Data解档回UIView
    override func reverseTransformedValue(_ value: Any?) -> Any? {
        guard let viewData = value as? Data else { return nil }
        do {
            return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(viewData) as? UIView
        } catch {
            print("解档View失败:\(error.localizedDescription)")
            return nil
        }
    }
}

步骤2:注册Transformer并配置Core Data

  • 在App启动时(比如AppDelegate的didFinishLaunchingWithOptions里)注册这个Transformer:
    ValueTransformer.setValueTransformer(ViewArchiveTransformer(), forName: NSValueTransformerName("ViewArchiveTransformer"))
    
  • 回到Core Data模型,给实体加一个Transformable类型的属性,在属性检查器里把Transformer Class改成ViewArchiveTransformer(注意类名要完全匹配)。

步骤3:存储和读取View

// 存储
yourCoreDataEntity.storedView = myView
try? context.save()

// 读取
if let savedView = yourCoreDataEntity.storedView as? UIView {
    // 拿到保存的View后可以直接使用
    self.view.addSubview(savedView)
}

总结一下:如果只是存frame,方案1足够简单;如果要存整个View,再用方案2的自定义Transformer。你之前的错误是试图直接把UIView转成NSValue,这不符合NSValue的设计初衷——它是用来包装基础数据类型的,不是NSObject子类哦。

内容的提问来源于stack exchange,提问作者Todanie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 12:14:58