Предикат CoreData с аргументом функции - PullRequest
2 голосов
/ 02 апреля 2019

Я пытаюсь включить функцию в определение предиката. Возможно ли это?

Допустим, у вас есть сущность Базовых Данных Мест с атрибутами для широта и долгота.

Я хотел бы добавить аннотации к карте этих мест в пределах указанное расстояние от местоположения пользователя. Я могу, конечно, пройтись по всей базе данных и рассчитать расстояние между каждым Местом и местоположение пользователя, но у меня будет около 35000 мест, и казалось бы, было бы более эффективно иметь предикат в Установка fetchedResultsController.

Я попробовал код ниже, но я получаю сообщение об ошибке «Проблема с субпредикат BLOCKPREDICATE (0x2808237b0) с userInfo (ноль) "

func myDistanceFilter(myLat : CLLocationDegrees, myLong : CLLocationDegrees, cdLat : CLLocationDegrees, cdLong : CLLocationDegrees) -> Bool {

    let myLocation = CLLocation(latitude: myLat, longitude: myLong)
    let cdLocation = CLLocation(latitude: cdLat, longitude: cdLong)

    if myLocation.distance(from: cdLocation) < 5000.0 {
        return true
    } else {
        return false
    }
}//myDistancePredicate

А внутри извлеченного контроллера результатов:

let distancePredicate = NSPredicate {_,_ in self.myDistanceFilter(myLat: 37.774929, myLong: -122.419418, cdLat: 38.0, cdLong: -122.0)}

Если внутри предиката возможно иметь блок / функцию, как получить ссылку на атрибут для оцениваемого объекта сущности?

Любое руководство будет оценено.

Ответы [ 2 ]

2 голосов
/ 03 апреля 2019

Дополнительное наблюдение для всех, кто борется с подобной проблемой.

Учитывая предложения pbasdf и Джерри, приведенные выше, по крайней мере, в моем случае, нет причин, по которым регион должен быть круглым.Я напишу имя, обозначающее почти прямоугольную область.Я провел несколько тестов со значениями широты и долготы.Эти значения широты и долготы можно масштабировать до прямоугольника, охватывающего круговой радиус, указанный пользователем.Один градус широты составляет около 69 миль, а один градус долготы на широте Чикаго - около 51 мили.Я использовал следующее:

var myUserLatitude : CLLocationDegrees!
var myUserLongitude : CLLocationDegrees!

В файле инициализации для представления:

guard let userLatitude = locationManager.location?.coordinate.latitude else {return}
guard let userLongitude = locationManager.location?.coordinate.longitude else {return}
myUserLatitude = userLatitude
myUserLongitude = userLongitude

Внутри создания переменной fetchedResultsController:

let latitudeMinPredicate = NSPredicate(format: "latitude >= %lf", myUserLatitude - 1.0)
let latitudeMaxPredicate = NSPredicate(format: "latitude <= %lf", myUserLatitude + 1.0)
let longitudeMinPredicate = NSPredicate(format: "longitude >= %lf", myUserLongitude - 1.0)
let longitudeMaxPredicate = NSPredicate(format: "longitude <= %lf", myUserLongitude + 1.0)

var compoundPredicate = NSCompoundPredicate()
compoundPredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [anotherUnrelatedPredicate,latitudeMinPredicate,latitudeMaxPredicate,longitudeMinPredicate, longitudeMaxPredicate])
fetchRequest.predicate = compoundPredicate        

Очевидно, я создамдругое свойство для масштабирования значения 1.0 для желаемой пользователем области.Начальные тесты, кажется, работают, и лучше всего я не могу поверить, насколько быстро это происходит.Буквально tableView заполняется ко времени перехода viewController к включающему mapView.

1 голос
/ 02 апреля 2019

Ну, да, это возможно . NSPredicate имеет +predicateWithBlock: и init(block:).

Однако, если вы прокрутите страницу вниз, вы увидите плохие новости:

Базовые данные поддерживают основанные на блоках предикаты в оперативной памяти и атомарных хранилищах, но не в хранилище на основе SQLite.

Таким образом, независимо от того, используете ли вы хранилище в памяти или выполняете фильтрацию в коде, в любом случае вам нужно перенести эти 35 000 элементов в память, и производительность метода грубой силы будет низкой.

Существует сложность, при которой SQL больше не подходит - вы получаете лучшую производительность с реальным кодом. Я думаю, что ваше требование намного выше этого уровня. Это будет интересный информатический проект по оптимизации. Вам нужно выполнить некоторые предварительные вычисления, аналогичные добавлению index в вашу базу данных. Рассмотрите возможность добавления атрибута region к вашим place сущностям, а затем напишите свой предикат, чтобы выбрать все места в пределах области целевого местоположения и всех ближайших соседей. Затем отфильтруйте эти кандидатов в коде. Я уверен, что это было сделано другими - подумайте о сотах в сети сотовой связи - но Core Data не собирается давать вам это бесплатно .

...