2017-02-10 19 views
0

У меня есть производный класс (сущность) NSManagedObject, экземпляры которого хранятся в локальном хранилище SQL-lite. Класс также имеет свойства долготы и широты, и мне нужно получить объекты на основе расстояния от конкретных координат. Я попытался использовать NSPredicate с пользовательскими функциями, но я не смог найти документацию о том, как реализовать функцию (... если она это поддерживает). Кто-нибудь знает, как выполнить такую ​​динамическую фильтрацию на объектах Core Data? Я пытался с NSPredicate withBlock, но он не работает с объектами, которые сохраняются в базе данных SQL-Lite. Пожалуйста помоги.Отфильтровать объекты данных ядра на расстоянии от динамического положения

ответ

3

Вы не можете сделать это с помощью Core Data. Вы можете использовать свойство Transient для моделирования расстояния от вашего динамического местоположения, после того, как объекты были извлечены, и даже упорядочить элементы на основе этого свойства Transient. Но вы можете только извлекать свойства из постоянного хранилища, если они являются постоянными свойствами.

На практике я обнаружил, что очень быстро запрашивать точки в прямоугольном окне, если координаты индексируются. Постройте окно, выбрав широту/долготу динамической позиции, плюс/минус радиус поиска, введя корректировку косинуса (широты) для окна долготы, если это непроектированные данные (чистый lat/lon, а не UTM или подобная сетка).

Если это действительно не так быстро, вы можете сохранить geohash на своих сущностях, что дает вам строку, которую вы можете использовать в префиксном поиске. См. https://en.wikipedia.org/wiki/Geohash для обсуждения. Или вы можете реализовать истинный пространственный индекс. Но у меня никогда не было проблемы с базовыми данными, что сделало его целесообразным для реализации любого из этих подходов.

0

Я сохраняю свои местоположения в модели данных в виде координат широты/долготы. Затем я написал некоторые вспомогательные расширения, чтобы найти полупрямую область координат lat/lon и запрос к этому. Это значительно ограничивает набор результатов, поэтому, если вам нужно отсортировать по местоположению, вы можете отсортировать полученные объекты с помощью калькулятора расстояния CLLocation.

Я создаю CLCircularRegion, и вы можете увидеть мою функцию buildPredicate(), которая создает запрос.

Вот код, я использую:

Swift 3

extension CLLocationDegrees { 
     static var north: CLLocationDegrees { 
      return 90.0 
     } 
     static var south: CLLocationDegrees { 
      return -90.0 
     } 
     static var east: CLLocationDegrees { 
      return 180.0 
     } 
     static var west: CLLocationDegrees { 
      return -180.0 
     } 

     var radians: Double { 
      return Double.pi * self/180.0 
     } 
    } 

    extension CLLocationCoordinate2D { 
     var metersPerDegreeLatitude: CLLocationDistance { 
      return 111319.4907932736 
     } 
     var metersPerDegreeLongitude: CLLocationDistance { 
      return max(0.0, cos(self.latitude.radians) * self.metersPerDegreeLatitude) 
     } 
    } 

    extension CLCircularRegion { 
     var northernmostLatitude: CLLocationDegrees { 
      let longitude = self.center.latitude + self.radius/self.center.metersPerDegreeLatitude 
      return min(longitude, .north) 
     } 

     var southernmostLatitude: CLLocationDegrees { 
      let longitude = self.center.latitude - self.radius/self.center.metersPerDegreeLatitude 
      return max(longitude, .south) 
     } 

     var easternmostLongitude: CLLocationDegrees { 
      guard self.northernmostLatitude <= .north else { 
       return .east 
      } 
      guard self.southernmostLatitude >= .south else { 
       return .east 
      } 
      return min(.east, self.center.longitude + self.radius/(self.center.metersPerDegreeLongitude + 0.0001)) 
     } 

     var westernmostLongitude: CLLocationDegrees { 
      guard self.northernmostLatitude <= .north else { 
       return .west 
      } 
      guard self.southernmostLatitude >= .south else { 
       return .west 
      } 
      return max(.west, self.center.longitude - self.radius/(self.center.metersPerDegreeLongitude + 0.0001)) 
     } 

     func buildPredicate(latitudeName: String = "latitude", longitudeName: String = "longitude") -> NSPredicate { 
      let args = [self.southernmostLatitude, self.northernmostLatitude, self.westernmostLongitude, self.easternmostLongitude] 
      return NSPredicate(format: "\(latitudeName) >= %@ && \(latitudeName) <= %@ && \(longitudeName) >= %@ && \(longitudeName) <= %@", argumentArray: args) 
     } 
    } 
+0

Нет именно то, что мне нужно ... ТХ – Sergiob