2017-02-10 40 views
0

我有一个NSManagedObject派生类(实体),其实例在本地SQL-lite存储中持久化。该类还具有经度和纬度属性,我需要根据距特定坐标的距离来获取实体。我试图用自定义函数来使用NSPredicate,但是我找不到有关如何实现函数的文档(...如果它支持的话)。有没有人有关于如何对Core Data实体执行这种动态过滤的想法?我尝试使用NSPredicate withBlock,但它不适用于在SQL-Lite数据库上保存的对象。请帮忙。通过距动态位置的距离过滤核心数据实体

回答

3

你不能用Core Data来做到这一点。在获取实体之后,您可以使用Transient属性来建模与动态位置的距离,甚至可以根据该Transient属性对项目进行排序。但是如果它们是持久性属性,则只能从持久性存储中获取属性。

实际上,如果坐标是索引的,我发现在矩形窗口中查询点非常快。如果是未投影数据(纯粹经纬度,不是UTM或类似网格),则通过获取动态位置的经纬度,加/减搜索半径,为经度窗口调整余弦(纬度)调整窗口来构建窗口。

如果真的不够快,你可以在你的实体上存储一个geohash,它给你一个字符串,你可以做一个前缀搜索。讨论请参阅https://en.wikipedia.org/wiki/Geohash。或者你可以实现一个真正的空间索引。但是我从来没有发现核心数据性能问题,因此值得实施这两种方法之一。

0

我将数据模型中的位置存储为纬度/经度坐标。然后,我写了一些辅助扩展名来查找纬度/经度坐标的半方矩形区域并按此查询。这极大地限制了结果集,所以如果您需要按位置排序,则可以使用CLLocation距离计算器对结果对象进行排序。

我创建一个CLCircularRegion,你可以看到我的buildPredicate()函数创建查询。

下面是我使用的代码:

斯威夫特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

不正是我需要的... TX – Sergiob