Search code examples
swiftcore-datanspredicate

Compare integer with string in NSPredicate


I have in project array of workout programs (code for them are on Objective-C) and in every program I have @property (nullable, nonatomic, copy) NSString *scheduleStr; for program durations. This property stores values such as 1 week, 2 weeks, 3 weeks and etc. I need to filter all values bigger than 6 weeks. I'm trying to apply NSPredicate:

predicates.append(NSPredicate(format: "scheduleStr.integerValue >= 6"))

and after this I'm receiving only programs with length 6-9 weeks, but nothing more than 10 weeks, but for sure I have several programs in database with length equal 12 weeks. If I'm trying to apply something like this:

predicates.append(NSPredicate(format: "scheduleStr.integerValue >= 10"))

I will receive almost all the programs. How to get all programs with more than selected values?


Solution

  • The problem is that, although you specify integerValue, when using the predicate as part of a fetch, CoreData treats your string as a string. In string terms, 10 weeks is "less than" 6 weeks, so it's excluded from the results.

    You should store the number (as an Int) instead of storing the string. Adding the text " weeks" is then something you do for display purposes. If you store the number, rather than the string, then CoreData can do a numerical comparison and your predicate will work as you expect.

    If you really don't want to do that, there is one workaround, and one hack. The workaround is to filter the objects in memory rather than as part of a fetch. The integerValue will then be correctly interpreted and the comparison will be numerical.

    The hack is to force CoreData to treat your string as though it is a number, by using a numeric function, like abs (assuming you only have a positive number of weeks, taking the absolute value leaves the value unchanged):

    predicates.append(NSPredicate(format: "abs:(scheduleStr) >= 6"))