Сравнить целое число со строкой в ​​NSPredicate

Sep 23 2020

У меня есть в проекте множество программ тренировок (код для них находится на Objective-C) и в каждой программе, которая у меня есть @property (nullable, nonatomic, copy) NSString *scheduleStr;для продолжительности программы. Это свойство хранит такие значения, как 1 неделя , 2 недели , 3 недели и т. Д. Мне нужно отфильтровать все значения, превышающие 6 недель. Я пытаюсь применить NSPredicate:

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

и после этого я получаю только программы продолжительностью 6-9 недель, но не более 10 недель, но наверняка у меня в базе есть несколько программ продолжительностью 12 недель. Если я пытаюсь применить что-то вроде этого:

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

Я получу почти все программы. Как получить все программы с более чем выбранными значениями?

Ответы

1 pbasdf Sep 24 2020 at 03:48

Проблема в том, что, хотя вы и указываете integerValue, при использовании предиката как части выборки CoreData обрабатывает вашу строку как строку. В строковом выражении 10 weeksэто «меньше чем» 6 weeks, поэтому оно исключается из результатов.

Вы должны сохранить число (как Int) вместо сохранения строки. Добавление текста «недели» - это то, что вы делаете для отображения. Если вы храните число, а не строку, CoreData может выполнять численное сравнение, и ваш предикат будет работать так, как вы ожидаете.

Если вы действительно не хотите этого делать, есть один обходной путь и один взлом. Обходной путь - фильтровать объекты в памяти, а не как часть выборки. Тогда integerValueбудет правильно интерпретировано, и сравнение будет числовым.

Хакерство заключается в том, чтобы заставить CoreData обрабатывать вашу строку, как будто это число, с помощью числовой функции, например abs(при условии, что у вас есть только положительное количество недель, взятие абсолютного значения оставляет значение без изменений):

predicates.append(NSPredicate(format: "abs:(scheduleStr) >= 6"))
AnjaliAggarwal Sep 23 2020 at 22:26

Чтобы получить целую часть в строке в вашем случае, вы можете посмотреть что-то вроде:

Предположим, что element - это ваша строка, тогда

let component = element.components(separatedBy: .letters) // this will give you the non letter values 
let integerValues = component.filter({ $0 != "" }) 
print(integerValues[0]) // As first value in your input string is an integer

Это даст вам целую часть строки, которую можно использовать для фильтрации массива.