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
чтобы получить ваши данные