带有函数参数的 CoreData 谓词

CoreData Predicate with Function Argument

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

假设您有一个 Places 的核心数据实体,其属性为 纬度和经度。

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

I tried the code below but I receive an error message of "Problem with 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)}

如果可以在谓词中包含 block/function,您如何获取对正在评估的实体对象的属性的引用?

如有任何指导,我们将不胜感激。

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

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

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

因此,无论是使用内存存储,还是代码过滤,都需要将这 35,000 项放入内存,暴力破解的性能会很差。

有一个复杂点,SQL 不再适用 – 使用 真实 代码可以获得更好的性能。我认为你的要求远远超出了这一点。这将是一个有趣的计算机科学优化项目。您需要进行一些预计算,类似于将 index 添加到数据库。考虑向您的 place 实体添加一个 region 属性,然后编写您的谓词以获取目标位置区域内的所有地点和所有直接邻居。然后在代码中过滤那些候选人。我敢肯定其他人已经这样做了——想想单元 phone 网络中的单元——但 Core Data 不会免费 给你这个 .

对遇到类似问题的其他人的额外观察。

考虑到上面 pbasdf 和 Jerry 的建议,至少在我的情况下,没有理由非要一个区域是圆的。我将起草一个名称,表示一个近乎矩形的区域。我 运行 一些带有纬度和经度值的测试。这些纬度和经度值可以缩放为一个矩形,该矩形包含用户指定的圆形半径。芝加哥纬度的一度约为 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 segues 到封闭的 mapView 时填充的。