繁体   English   中英

Swift3:通过AppGroups从Watch Extension访问Core Data时的空提取

[英]Swift3: Empty fetch when accessing Core Data from Watch Extension via AppGroups

目前我正在为已有的App(迁移到Swift 3)进行更新。 我有针对Today-,Search-,Message-和Watch Extensions的目标。 每个目标都需要访问我的应用程序的核心数据模型,因此我创建了一个AppGroup并为每个目标启用了Capability。 虽然我已经将NSPersistentStoreCoordinator子类化,但所有内容都存储在共享文件夹中:

import CoreData
class PFPersistentContainer: NSPersistentContainer {
    override open class func defaultDirectoryURL() -> URL {
        if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "add-groupname-here") {
            return url
        }
        // Fallback
        return super.defaultDirectoryURL()
    }
}

这个类文件,以及我的Core-Data-Model和下面的类都是所有提到的目标的目标成员。 实体的Codegen设置为Class Definition 到目前为止,我正在使用Core Data Stack的默认实现:

class DataManager {
    /**
     * Singleton Implementation
     */
    internal static let sharedInstance:DataManager = {
        let instance = DataManager()
        return instance
    }()

    // MARK: - Core Data stack
    lazy var persistentContainer: PFPersistentContainer = {
        let container = PFPersistentContainer(name: "Data")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

    // MARK: - Core Data Saving support

    func saveContext () {
        let context = persistentContainer.viewContext
        if context.hasChanges {
            do {
                try context.save()
            } catch {
                let nserror = error as NSError
                fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
            }
        }
    }
}

现在奇怪的部分:从Today-和Message-Extension访问这些数据似乎工作得很好(我假设搜索扩展也正常工作,但就开发人员而言,我无法测试它)。 尝试使用来自Watch App扩展的相同请求获取它会产生一个空数组。 这是我的获取代码:

    internal func getLimitedPOIsWithCalculatedDistance(andCurrentLocation currentLocation:CLLocation) -> Array<POI> {
        var poiArray:Array< POI > = []
        guard let context = self.backgroundContext else { return [] }
        do {
            // Initialize Fetch Request
            let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "POI")

            // Create Entity Description
            let entityDescription = NSEntityDescription.entity(forEntityName: "POI", in: context)

            // Configure Fetch Request
            request.entity = entityDescription

            // Configure Predicate
            let predicate = NSPredicate(format: "(disabled == NO) AND (locationDistanceCalculated <= \(SETTINGS_MAXIMUM_FETCH_DISTANCE))")
            request.predicate = predicate
            if let result = try context.fetch(request) as? Array<POI> {
                for poi in result {
                    let poiLocation = CLLocation(latitude: poi.locationLatitude, longitude: poi.locationLongitude)
                    let distance = currentLocation.distance(from: poiLocation)
                    poi.locationDistanceTransient = Double(distance)
                }

                poiArray = result.filter({ (poi) -> Bool in
                    return poi.locationDistanceTransient > 0.0
                })

                poiArray.sort { (first, second) -> Bool in
                    return first.locationDistanceTransient < second.locationDistanceTransient
                }
            }
        } catch {
            print("Error in WatchDataInterface.getLimitedPOIsWithCalculatedDistance(): \(error.localizedDescription)")
        }
        return poiArray
    }

更多理解的上下文: POI Entitie包含位置的纬度和经度。 启动应用程序时,我从当前用户的位置预先计算到数据库中每个点的距离。 当Today-Extension尝试将最接近的x(在我的情况下为8)POI提供给当前用户位置时,获取所有15k POI并计算它们的距离对于记忆很大。 所以我必须预先计算距离(存储在locationDistanceCalculated ),然后在给定半径内获取(静态SETTINGS_MAXIMUM_FETCH_DISTANCE )并在获取过程中计算精确距离(存储到瞬态属性locationDistanceTransient )。

在Watch App的ExtensionDelegate类中,当用户位置更新时,将实现CLLocationManagerDelegate并调用代码:

extension ExtensionDelegate: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        OperationQueue.main.addOperation{
            if let watchDataManager = self.watchDataManager {
                // getNearestPOIs() calls the getLimitedPOIsWithCalculatedDistance() function and returns only a numberOfPOIs
                self.nearbyPOIs = watchDataManager.getNearestPOIs(numberOfPOIs: 4)
            }
        }
    }
}

它在模拟器和设备上进行了测试。 context.fetch总是返回一个空数组(是的,核心数据包含值,是的,我在没有谓词的情况下测试过它)。 我是否遗漏了Core Data中的任何新内容,我还没有考虑过,或者他们在WatchOS3中有任何限制,为什么这个没有用? 有人有线索吗? 谢谢你的帮助。

更新:当使用Watch Framework目标访问Core Data时,就像在此项目中描述的那样 ,fetch保持为空。 也许这可能是正确的道路,但Watch Framework是错误的选择。 会让你保持最新。

更新2:我已经检查了WatchOS的App编程指南和API参考中的transferFile:metadata: 函数 ,但它似乎不是将这些大量数据发送到AppleWatch的合适方式。 我不能依赖于这样的情况:用户正在检查应用程序的频率高于他在SETTINGS_MAXIMUM_FETCH_DISTANCE范围之外的距离,对于具有高密度POI的位置,此数据甚至更广泛。

更新3:我重新实现了附近的POI功能,只能在给定的半径内获取。 如果这为您解决了问题,请查看此公开要点

从Watch OS3开始,您无法使用App Group技巧访问CoreData基础(因为手表应该在没有手机的情况下工作。

因此,您必须使用WatchConnectivity来获取数据

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM