【问题标题】:How to define CoreData relationship in Swift?如何在 Swift 中定义 CoreData 关系?
【发布时间】:2014-08-12 13:39:14
【问题描述】:

在 CoreData 中,我定义了从 NodeTag 的无序对多关系。我创建了一个这样的 Swift 实体:

import CoreData
class Node : NSManagedObject {
    @NSManaged var tags : Array<Tag>
}

现在我想将Tag 添加到Node 的实例中,如下所示:

var node = NSEntityDescription.insertNewObjectForEntityForName("Node", inManagedObjectContext: managedObjectContext) as Node
node.tags.append(tag)

但是,这会失败并出现以下错误:

由于未捕获的异常“NSInvalidArgumentException”而终止应用程序,原因:“对多关系不可接受的值类型:property = “tags”;所需类型 = NSSet;给定类型 = _TtCSs22ContiguousArrayStorage000000000B3440D4;值 = ( “<_ttc8motornav3tag>(实体:标签;ID:0xb343800;数据:{...})” )。'

对多关系的正确类型是什么?

【问题讨论】:

  • NSSet 在 Swift 中不可用?你在哪里找到的?
  • 还有错误信息表明关系是有序的,而不是无序的。
  • @BryanChen 啊是的,你的评论让我意识到 NSSet 可以通过Foundation 获得。
  • @MartinR 我已经复制了错误消息,它仍然被定义为有序集。
  • @bouke:错误消息仍然提到“.. value for ordered to-many relationship”。您能否将实际的错误消息复制/粘贴到问题中,以避免将来的读者混淆?

标签: core-data swift ios8


【解决方案1】:

为了能够在 Swift 中处理一对多关系,您需要将属性定义为:

class Node: NSManagedObject {
    @NSManaged var tags: NSSet
}

如果您尝试使用NSMutableSet,更改将不会保存在 CoreData 中。当然建议在Node中定义反向链接:

class Tag: NSManagedObject {
    @NSManaged var node: Node
}

但是 Swift 仍然不能在运行时生成动态访问器,所以我们需要手动定义它们。在extension 类中定义它们并放入Entity+CoreData.swift 文件中非常方便。下面是Node+CoreData.swift文件的内容:

extension Node {
    func addTagObject(value:Tag) {
        var items = self.mutableSetValueForKey("tags");
        items.addObject(value)
    }

    func removeTagObject(value:Tag) {
        var items = self.mutableSetValueForKey("tags");
        items.removeObject(value)
    }
}

用法:

// somewhere before created/fetched node and tag entities
node.addTagObject(tag)

重要提示:为了使这一切正常工作,您应该验证 CoreData 模型中实体的类名称是否包含您的模块名称。例如。 MyProjectName.Node

【讨论】:

  • 嘿 Keenie,当我使用你的扩展程序时,我收到错误:"'NSSet' does not have a member named 'addTagObject'"。知道我可能做错了什么吗?
  • @Pirijan,您必须在 tags: NSSet 属性上调用 addTagObject 方法,而您应该在具有 tags 属性的对象上调用它。
  • 谢谢 Keenle,我想不通,所以我在这里发布了一个更彻底的问题:stackoverflow.com/questions/25127090/…
  • 谢谢,虽然稍后发布,但你的回答更完整,我会奖励你:)。
  • 这对我不起作用。在对多对关系的父级调用 remove 函数后,尝试保存失败,因为子级仍然存在,但其与父级的所需关系为零。
【解决方案2】:

以@Keenle 的回答为基础,如果你想厚脸皮、简洁并能够说出来

node.tags.append(tag)

可以包装对 self.mutableSetValueForKey 的调用:

class Node: NSManagedObject {

    var tags: NSMutableOrderedSet {
        return self.mutableOrderedSetValueForKey("tags")
    }
}

【讨论】:

    【解决方案3】:

    从 Xcode 7 和 Swift 2.0 开始,release note 17583057 声明:

    NSManaged 属性可以与方法一起使用,也可以用于 属性,用于访问 Core Data 自动生成的 与许多访问者的键值编码兼容。

    @NSManaged var employees: NSSet
    
    @NSManaged func addEmployeesObject(employee: Employee)
    @NSManaged func removeEmployeesObject(employee: Employee)
    @NSManaged func addEmployees(employees: NSSet)
    @NSManaged func removeEmployees(employees: NSSet)
    

    这些可以在你的 NSManagedObject 子类中声明。 (17583057)

    因此,您只需声明以下方法,CoreData 将负责其余的工作:

    @NSManaged func addTagsObject(tag: Tag)
    @NSManaged func removeTagsObject(tag: Tag)
    @NSManaged func addTags(tags: NSSet)
    @NSManaged func removeTags(tags: NSSet)
    

    【讨论】:

      【解决方案4】:

      其实你可以定义:

      @NSManaged var employees: Set<Employee>
      

      并直接使用Setinsertremove方法。

      【讨论】:

      • 你检查过这个真的有效吗?如果这样修改员工设置后保存模型,是否真的会保存修改?
      • 我实际上是在同一时刻使用这种方法并且它正在工作。
      • 有趣!我不知道这是可能的。我认为 Apple 真的应该澄清 Core Data/Swift 的用法……
      • 是否存在 set 应该是 Optional 的常见情况?还是最好按照您的示例定义它?
      • 这很有帮助,谢谢。我发现很多 Core Data 信息都包含在 Objective-C 约定中,因此非常感谢特定于 Swift 的解释。
      猜你喜欢
      • 2020-07-15
      • 2014-09-05
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 2014-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多