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

Posted

技术标签:

【中文标题】使用 NSPredicate 根据数组属性过滤 CoreData 项列表【英文标题】:Filter a list of CoreData items based on an array property using NSPredicate 【发布时间】:2020-05-19 12:12:05 【问题描述】:

上下文

我有一个名为“任务”的核心数据实体

“任务”与另一个名为“标签”的实体有关系:@NSManaged public var tags: NSSet? 此数据存储为:

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

    return set.sorted 
        $0.wrappedTagTitle < $1.wrappedTagTitle
    

如果任务列表包含某个标签,即标题为“学校”,我正在尝试过滤它们。

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))

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

FilteredScrollView(tagFilterName: "School")

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

结果

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

【问题讨论】:

【参考方案1】:

直接的问题是您调用Tag() 来创建一个新实例,该实例不调用指定的初始化程序。要创建一个新的Tag,您需要使用Tag(context: NSManagedObjectContext)。您遇到崩溃是因为您尝试使用未正确初始化的对象。

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

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

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

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

【讨论】:

除了上面 Tom 的观点,请注意(对于 SQLite 存储)CoreData 在执行提取时将无法识别计算属性 tagsArray。但是您可以使用底层关系tags,而不是:即。 “任何标签。标题 == %@”。 哎呀,我忘了tagsArray 是一个计算属性。已修复并感谢您的捕获。

以上是关于使用 NSPredicate 根据数组属性过滤 CoreData 项列表的主要内容,如果未能解决你的问题,请参考以下文章

NSPredicate 根据本地化字符串条目过滤数组

使用 NSPredicate 根据 NSDictionary 键过滤 NSArray

NSPredicate 根据嵌套结构中的属性过滤自定义对象

使用 NSPredicate 过滤数组

使用 NSPredicate 过滤包含字典的数组数组

使用 NSPredicate 过滤对象中的数组