2017-02-10 78 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