具有函数参数的CoreData谓词

问题描述 投票:2回答:2

我试图在Predicate定义中包含一个函数。这可能吗?

假设您有一个“核心数据”实体,其中包含纬度和经度属性。

我想在距离用户位置指定距离内的那些地方的地图视图中添加注释。当然,我可以遍历整个数据库并计算每个Place和用户位置之间的距离,但是我将有大约35000个位置,看起来在fetchedResultsController设置中有一个谓词会更有效。

我尝试了下面的代码但是我收到一条错误消息“subpredicate BLOCKPREDICATE(0x2808237b0)with userInfo of(null)”

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

在fetchedResultsController里面:

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

如果可以在谓词中包含块/函数,那么如何获得对正在评估的实体对象的属性的引用?

任何指导将不胜感激。

ios swift core-data nspredicate cllocation
2个回答
1
投票

嗯,是的,这是可能的。 NSPredicate确实有+predicateWithBlock:init(block:)

但是,如果您向下滚动该页面,则会看到坏消息:

Core Data支持内存和原子存储中基于块的谓词,但不支持基于SQLite的存储。

因此,无论您是使用内存存储,还是在代码中进行过滤,无论哪种方式,您都需要将这35,000个项目存入内存,并且执行蛮力方法的效果会很差。

SQL不再合适有一定的复杂性 - 使用真实代码可以获得更好的性能。我认为你的要求远远超出了这一点。这将是一个有趣的计算机科学项目进行优化。您需要进行一些预先计算,而不是在数据库中添加索引。考虑将region属性添加到place实体,然后编写谓词以获取目标位置区域内的所有位置以及所有直接邻居。然后在代码中过滤那些候选人。我确信这已经由其他人完成 - 想想手机网络中的细胞 - 但Core Data不会免费提供给你。


2
投票

对于遇到类似问题的其他人的另一个观察。

考虑到pbasdf和Jerry的建议,至少在我的情况下,没有理由为什么一个地区必须是圆的。我将制作一个表示近乎矩形区域的名称。我用纬度和经度值运行了一些测试。这些纬度和经度值可以缩放到包围用户指定的圆形半径的矩形。一度纬度约为69英里,芝加哥纬度的一度经度约为51英里。我使用了以下内容:

var myUserLatitude : CLLocationDegrees!
var myUserLongitude : CLLocationDegrees!

在视图的init文件中:

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时填充。

© www.soinside.com 2019 - 2024. All rights reserved.