Swift3: пустая выборка при доступе к основным данным из расширения расширений через группы приложений

В настоящее время я работаю над обновлением для уже существующего приложения (переход на Swift 3). У меня есть цели для расширений Today, Search, Message и Watch. Каждой цели нужен доступ к базовой модели данных моего приложения, поэтому я создал группу приложений и включил функцию 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, Пока что я использую реализацию по умолчанию для основного стека данных:

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, кажется, работает изящно (я предполагаю, что Search-Extension тоже работает, но, как разработчик, я не могу это проверить). Попытка получить его с тем же запросом из расширения приложения Watch приводит к пустому массиву. Вот мой код получения:

    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 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, как описано в этом проекте, выборка остается пустой. Возможно, это может быть правильный путь, но Watch Framework - неправильный выбор. Буду держать вас в курсе.

Обновление 2: я уже проверил Руководство по программированию приложений для WatchOS иtransferFile:metadata: в API References, но не представляется подходящим способом отправить эти большие объемы данных в AppleWatch. Я просто не могу полагаться на то обстоятельство, что пользователь проверяет приложение чаще, чем выезжает из SETTINGS_MAXIMUM_FETCH_DISTANCE радиус и для местоположений с высокой плотностью POI эти данные еще более обширны.

Обновление 3: я переопределил ближайшую функцию для POI, чтобы получать только в заданном радиусе. Если это решит проблему для вас, ознакомьтесь с этой публичной суть.

1 ответ

Решение

Так как смотреть OS3, вы не можете получить доступ к CoreData использовать трюк App Group (потому что часы должны работать без телефона.

Так что вы должны использовать WatchConnectivity чтобы получить ваши данные

Другие вопросы по тегам