В настоящее время я работаю над обновлением для уже существующего приложения (переход на Swift 3). У меня есть цели для Today-, Search-, Message- и Watch Extensions. Каждая цель должна получить доступ к базовой модели данных моего приложения, поэтому я создал AppGroup и включил возможность для каждой цели. Хотя я подклассы в NSPersistentStoreCoordinator, так что все хранится в общей папке:Swift3: Пустая выборка при доступе к основным данным из продления часов через AppGroups
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-модели и следующий класс являются все цели членства всех указанных целей. Кодек объектов установлен в 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)")
}
}
}
}
Теперь странная часть: Доступ к этой информации из Сегодня- и 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 пытается получить ближайшие POI-объекты x (в моем случае 8) в текущую позицию пользователя, выборка всех 15-килобайтовых POI и вычисление их расстояния - это разумная память. Поэтому мне пришлось предварительно рассчитать расстояние (хранящееся в
locationDistanceCalculated
), затем извлечь в заданном радиусе (статическийSETTINGS_MAXIMUM_FETCH_DISTANCE
) и рассчитать точное расстояние во время процесса выборки (сохранено в свойство переходного процессаlocationDistanceTransient
).
В Сторожевой приложения ExtensionDelegate
Class A 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 - неправильный выбор. Будет держать вас в курсе.
Update 2: Я уже проверил App Programming Guide для WatchOS и transferFile:metadata:
function в API Ссылки, но это, кажется, не является подходящим способом отправить эти большие объемы данных в AppleWatch. Я просто не могу положиться на то обстоятельство, что пользователь проверяет приложение чаще, чем он выходит из радиуса SETTINGS_MAXIMUM_FETCH_DISTANCE
, и для местоположений с высокой плотностью POI эти данные еще более обширны.
Обновление 3: Я переопределил функцию, предназначенную для объектов POI, чтобы получать только в заданном радиусе. Если это решает проблему для вас, ознакомьтесь с этой публикацией Gist.
Спасибо за ваш намек на WatchConnectivity, это близко к возможному решению, но не то, что я намеревался реализовать. Возможно, я дам ему попробовать и обернуть остальную реализацию вокруг него. Вы получите вознаграждение. – cr0ss