Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create NSPredicate with array contains element

I simply have Address entity with property favourites of type [String]

Address

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

Suppose I have some addresses:

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

Now I need to fetch all addresses with a inside favourites. SO the result should be: 1, 3, 4

In other words I need to check if ANY element in array is equal to specific string then object should be returned.

The following doesn't work:

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

This is how it is defined in xcdatamodel:

enter image description here

like image 425
Bartłomiej Semańczyk Avatar asked Oct 24 '25 05:10

Bartłomiej Semańczyk


2 Answers

You cannot search in an array defined as transformable attribute with a predicate. Better define another entity

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

and a one-to-many relationship from "Address" to "Favourite".

The you can fetch all addresses which have any (i.e.: at least one) favorite equal to the string "a" with the predicate

NSPredicate(format: "ANY favourites.name == %@", "a")

or better with a compiler-checked key path literal:

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

For a case-insensitive comparison you can use

NSPredicate(format: "ANY %K ==[c] %@", #keyPath(Address.favourites.name), "a")
like image 75
Martin R Avatar answered Oct 26 '25 18:10

Martin R


According to the cheatsheet, CONTAINS is for comparing strings. e.g. "Hello" CONTAINS "e".

For collections, you should use IN:

NSPredicate(format: "%@ IN favourites", "a")
like image 24
Sweeper Avatar answered Oct 26 '25 19:10

Sweeper