Swift 和 CoreData 与自定义类作为可转换对象

Posted

技术标签:

【中文标题】Swift 和 CoreData 与自定义类作为可转换对象【英文标题】:Swift And CoreData With Custom Class As Transformable Object 【发布时间】:2018-01-15 02:47:25 【问题描述】:

我正在尝试使用带有 swift 和 CoreData 的自定义类作为可转换对象。我一直在浪费时间试图弄清楚但不能。我不断收到两个错误:无法将属性标记为 @NSManaged,因为它的类型无法在 Objective-C 中表示,并且无法将属性声明为 public,因为它的类型使用内部类型。 非常感谢您的帮助。谢谢。

我有一个名为 User 的 CoreData 对象。我还有一个名为 Site 的对象。 我不希望 Site 对象成为 CoreData 对象,因为大多数时候我创建 Site 对象时我不希望它添加到 CoreData 上下文中。

您将在下面看到“Site”类型的“primarySite”和“Site”类型的数组“sites”。这两行给出了我上面列出的两个相同的错误。

数据模型

用户+CoreDataClass

import Foundation
import CoreData

public class User: NSManagedObject 

用户+CoreDataProperties

import Foundation
import CoreData

extension User 
    @nonobjc public class func fetchRequest() -> NSFetchRequest<User> 
        return NSFetchRequest<User>(entityName: "User");
    

    @NSManaged public var firstName: String?
    @NSManaged public var lastName: String?
    @NSManaged public var role: String?
    @NSManaged public var primarySite: Site
    @NSManaged public var sites: [Site]

网站

import UIKit

class Site: NSCoding 
    let identifier: Int32
    let name: String
    let note: String

    init(with values: Dictionary<String,Any>) 
        identifier = Int32(values["identifier"] as! String)!
        name = values["name"] as! String
        note = values["note"] as! String
    

    required convenience init(coder decoder: NSCoder) 
        var siteValues = [String:Any]()
        siteValues["identifier"] = decoder.decodeObject(forKey: "identifier") as! String
        siteValues["name"] = decoder.decodeObject(forKey: "name") as! String
        siteValues["note"] = decoder.decodeObject(forKey: "note") as!
        self.init(with: siteValues)
    

     func encode(with coder: NSCoder) 
        coder.encode(String(self.identifier), forKey: "identifier")
        coder.encode(self.name, forKey: "name")
        coder.encode(self.note, forKey: "note")
    

【问题讨论】:

除非您的站点实际上比您的代码 sn-p 所暗示的更复杂,否则我会将其添加为新实体,并将 primarySite 和站点定义为从用户到站点的关系,而不是可转换的属性。 您表明User 正在使用手动/无代码生成,并且您在User 上有一个扩展。 User 类在哪里定义? 用户有两个由 Xcode 生成的文件。 User+CoreDataClass.swift 除了类声明之外没有包含任何其他内容,所以我没有考虑包含它。 【参考方案1】:

我想出了如何解决这两个错误。

1) “属性不能被标记为@NSManaged,因为它的类型不能在Objective-C中表示” 感谢@Tom 的回答,我通过将 Site 设为 NSObject 的子类来解决此错误。

class Site: NSObject, NSCoding 

2) “属性不能被声明为公共,因为它的类型使用了内部类型” 我通过在类之前添加“public”以及编码器和解码器函数来解决此错误。

public class Site: NSObject, NSCoding 
...
public func encode(with coder: NSCoder) ...
public required convenience init(coder decoder: NSCoder) ...

【讨论】:

【参考方案2】:

Property cannot be marked @NSManaged because its type cannot be represented in Objective-C

这是因为Site 没有从NSObject 继承。 Swift 类不必从 NSObject 继承,但 Core Data 可转换类可以。如果添加NSObject,则不会出现该错误。

还有一些其他问题 - 例如,您的 init(coder decoder: NSCoder) 没有分配任何属性值 - 但这些应该很容易弄清楚。

【讨论】:

我忘记复制 init(coder decoder: NSCoder) 中调用 self.init() 的行。我编辑了这个问题。谢谢。【参考方案3】:

由于 Site 是一个自定义类,您不能将其用作 NSManagedObject 中的数据类型。

就我而言,我在您的数据模型中将其类型设为“二进制数据”。 因此,使其类型为 NSData,它是目标 c 中的数据类型。

在此之后,您可以取消归档数据。

例如:

if let sitesArray = NSKeyedUnarchiver.unarchiveObject(with: sites) as? [[String : Any]] 
    //enter your processing code here to convert them to site objects

【讨论】:

以上是关于Swift 和 CoreData 与自定义类作为可转换对象的主要内容,如果未能解决你的问题,请参考以下文章

NSManagedObjectID 与自定义 UUID 标识符属性 - 获取性能

iOS版;以编程方式uicollectionView与自定义标头

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?

如何在 Swift 3 中将自定义类保存为 CoreData 实体的属性?

Swift:在 Core Data 中存储自定义类的数组

任何逻辑。建模过程库。库存元素(如源或队列)与自定义类之间的连接