I am currently working on updating an existing application (switching to Swift 3). I have goals for Today-, Search-, Message- and Watch Extensions. Each goal should have access to the underlying data model of my application, so I created an AppGroup and enabled the feature for each goal. Although I have subclassed NSPsistentStoreCoordinator, so everything is stored in a shared folder:
import CoreData class PFPersistentContainer: NSPersistentContainer { override open class func defaultDirectoryURL() -> URL { if let url = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "add-groupname-here") { return url }
This class file, as well as my Core-Data-Model and the following class are in the target membership for all of the specified purposes. The object code is assigned a Class Definition value. For now, I am using the default implementation for 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)") } } } }
Now the weird part: accessing this data from Today- and Message-Extension seems to work gracefully (I assume Search-Extension works too, but as far as the developer I canβt verify this). Attempting to get it with the same request from the extension of the Observation application will result in an empty array. Here is my extraction code:
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 }
A little more context for a better understanding: The POI Entitie contains the latitude and longitude of the location. When I launch the application, I pre-calculate the distance to each point in the database from the user's current position. When Today-Extension tries to get the closest POIs x (in my case 8) to the user's current position, fetching all 15-kilobyte POIs and calculating their distance is reasonable memory. Therefore, I had to pre-calculate the distance (stored in locationDistanceCalculated ), then extract it in the specified radius (static SETTINGS_MAXIMUM_FETCH_DISTANCE ) and calculate the exact distance during the selection process (stored in the transition property locationDistanceTransient ).
The Watch ExtensionDelegate application implements the CLLocationManagerDelegate class a and calls the code when updating the user's location:
extension ExtensionDelegate: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { OperationQueue.main.addOperation{ if let watchDataManager = self.watchDataManager {
It has been tested in Simulator and on the device. context.fetch always returns an empty array (yes, the kernel data contains values ββand yes, I tested it without a predicate). I missed something new in Core Data that I haven't considered yet, or is it their limitations in WatchOS3, why doesn't it work? Somebody knows? Thank you for your help.
Update: When using the target Watch Framework to access master data, as described in this project , the selection remains empty. This may be the right way, but the Watch Framework is the wrong choice. Will keep you posted.
Update 2: I already checked the Application Programming Guide for WatchOS and transferFile:metadata: function in the API links, but it doesn't seem to be suitable for sending these large amounts of data to AppleWatch. I just cannot rely on the fact that the user checks the application more often than he leaves the radius of SETTINGS_MAXIMUM_FETCH_DISTANCE , and for locations with a high density of POI this data is even more extensive.
Update 3:. I redefined the Feature function for the POI to retrieve only in the given radius. If this solves the problem for you, check out this publicly available Gist .