Core Data 使用 NSPredicate 按游戏类型数组过滤SavedGames实体
问题原因
你遇到的匹配异常主要来自两处代码错误:
- 部分谓词构造时多嵌套了一层数组,比如
argumentArray: [genres]写法,genres本身就是字符串数组,额外包装会变成嵌套数组,完全无法正常匹配。 - 「同时过滤类型和平台」的分支里,类型过滤的谓词写法错误,和单类型过滤分支的正确逻辑不一致,导致结果异常。
正确实现方案
你需要的过滤逻辑是:只要游戏关联的任意一个类型名称在筛选数组内,就返回该游戏,用SUBQUERY写法最稳妥,完全适配多对多关系的匹配场景,正确的谓词写法如下:
NSPredicate(format: "SUBQUERY(%K, $genre, $genre.name IN %@).@count > 0", #keyPath(SavedGames.genreType), genres)
上述逻辑会遍历当前游戏关联的所有类型对象,只要有至少一个类型的名称在筛选数组内就满足条件,完全匹配你的需求。
你只需要把switch分支里的「同时过滤类型和平台」部分的代码修正即可,完整的修正后代码如下:
switch (platforms.isEmpty, genres.isEmpty) { case (true, true): filterPredicate = NSPredicate(value: true) case (true, false): // 仅过滤类型,原有写法正确 filterPredicate = NSPredicate(format: "SUBQUERY(%K, $genre, $genre.name IN %@).@count > 0", #keyPath(SavedGames.genreType), genres) case (false, true): // 仅过滤平台,原有写法正确 filterPredicate = NSPredicate(format: "%K IN %@", #keyPath(SavedGames.platformID), platforms) case (false, false): // 同时过滤类型和平台,统一使用正确的类型过滤谓词 let genrePredicate = NSPredicate(format: "SUBQUERY(%K, $genre, $genre.name IN %@).@count > 0", #keyPath(SavedGames.genreType), genres) let platformPredicate = NSPredicate(format: "%K IN %@", #keyPath(SavedGames.platformID), platforms) filterPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [genrePredicate, platformPredicate]) }
此前尝试的写法错误说明
ANY genreType.name IN %@逻辑本身是成立的,但你之前传参时多套了一层数组导致匹配失效,SUBQUERY写法可以避免多对多关系下ANY的潜在匹配异常,更推荐使用。- 第二种SUBQUERY写法中多写了多余的
ANY关键字:$genre是遍历出来的单个类型对象,它的name是单个字符串,不需要再加ANY判断。 - 第三种SUBQUERY写法用
$genre.name = %@匹配数组:单个字符串和数组直接判断相等不可能成立,所以没有返回结果。 - 第四种循环生成OR复合谓词的写法逻辑正确,但类型数量较多时性能远低于SUBQUERY写法,不推荐使用。
内容的提问来源于stack exchange,提问作者thesuffering
相关产品推荐
相关产品推荐

