如何使用包含元素的数组创建 NSPredicate

How to create NSPredicate with array contains element

我只有 Address 个 属性 favourites 类型 [String]

的实体

地址

@objc(Address)
class Address: NSManagedObject, Observer {
    @NSManaged var favourites: [String]
}

假设我有一些地址:

1: favourites: ["a", "b", "c"]
2: favourites: ["b", "c"]
3: favourites: ["a", "c"]
4: favourites: ["a"]
5: favourites: ["b"]

现在我需要获取所有在 favourites 内带有 a 的地址。所以结果应该是:1, 3, 4

换句话说,我需要检查数组 is equal 中的 ANY element 是否为特定字符串,然后应返回对象。

以下无效:

NSPredicate(format: "favourites CONTAINS %@", "a")

xcdatamodel中是这样定义的:

根据cheatsheetCONTAINS用于比较字符串。例如"Hello" CONTAINS "e".

对于集合,您应该使用IN:

NSPredicate(format: "%@ IN favourites", "a")

您不能在定义为带有谓词的可转换属性的数组中进行搜索。最好定义另一个实体

@objc(Favourite)
class Favourite: NSManagedObject {
    @NSManaged var name: String
}

和从 "Address" 到 "Favourite" 的 one-to-many 关系。

您可以使用谓词

获取所有(即:至少一个)收藏夹等于字符串"a"的所有地址
NSPredicate(format: "ANY favourites.name == %@", "a")

或使用 compiler-checked 键路径文字更好:

NSPredicate(format: "ANY %K == %@", #keyPath(Address.favourites.name), "a")

要进行 case-insensitive 比较,您可以使用

NSPredicate(format: "ANY %K ==[c] %@", #keyPath(Address.favourites.name), "a")

如前所述,您无法在可变形属性中进行搜索。

额外实体的替代方法是将使用唯一分隔符连接的字符串数组保存为一个字符串,并声明计算 属性 以将字符串转换为数组,反之亦然

@NSManaged var favourites: String

private let uniqueSeparator = "®¥ð"

var favs : [String] {
    get { return favourites.components(separatedBy: uniqueSeparator) }
    set { favourites = newValue.joined(separator: uniqueSeparator)}
}

那你就可以简单的写

favs.contains("a")