使用 NSPredicate 根据数组 属性 过滤 CoreData 项目列表

Filter a list of CoreData items based on an array property using NSPredicate

上下文

我有一个名为 'Task'

的核心数据实体

'Task' 与另一个名为 'Tag' 的实体有关系:@NSManaged public var tags: NSSet? 此数据存储为:

public var tagsArray: [Tag] {
    let set = tags as? Set<Tag> ?? []

    return set.sorted {
        [=11=].wrappedTagTitle < .wrappedTagTitle
    }
}

我正在尝试根据包含特定标签(即标题为 "School" 的任务)过滤任务列表。

var fetchRequest: FetchRequest<Task>

init(tagFilterName: String) {
    let tag = Tag()
    tag.title = tagFilterName
    fetchRequest = FetchRequest<Task>(entity: Task.entity(), sortDescriptors: [], predicate: NSPredicate(format: "tagsArray CONTAINS %@", tag))
}

这是在 parent 视图中初始化的:

FilteredScrollView(tagFilterName: "School")

(请原谅 init 中的杂乱无章的代码,我只是想了解我正在尝试做的事情。)

结果

就目前而言,这会在运行时崩溃。 任何帮助将不胜感激。

眼前的问题是您正在调用 Tag() 来创建一个新实例,它不会调用指定的初始值设定项。要创建新的 Tag,您需要使用 Tag(context: NSManagedObjectContext)。您遇到崩溃是因为您尝试使用未正确初始化的 object。

但这只是问题的一部分。如果你修复它,你将修复崩溃,但你将得到零结果。另一个问题是您不应该为提取创建一个新的 Tag。 Core Data 谓词寻找完全匹配——没有像 Equatable 这样的东西,它不会寻找其他具有相同标题的 Tag。它将寻找那个确切的标签。但是由于您刚刚创建了该标签并且它没有连接到任何任务,因此您将得到零结果。 CONTAINS 运算符不会匹配任何内容,因为没有 Task 包含您刚刚创建的 Tag

要通过关系匹配 属性 值——在这种情况下,通过 tags 关系匹配 Tag.title——你的谓词看起来像

NSPredicate(format: "any tags.title = %@", tagFilterName)

在获取 Task 时,这会要求任何 Task,其中 tags 关系的任何成员的值都等于 tagFilterName