2017-02-16 2 views
7

zur Zeit arbeite ich an einem Update für eine bereits existierende App (Migration nach Swift 3). Ich habe Ziele für Today-, Search-, Message- und Watch Extensions. Jedes Ziel muss auf das Kerndatenmodell meiner App zugreifen. Daher habe ich eine AppGroup erstellt und die Funktion für jedes Ziel aktiviert. Obwohl ich die NSPersistentStoreCoordinator subclassed, so ist alles in einem freigegebenen Ordner gespeichert:Swift3: Leerer Abruf beim Zugriff auf Core-Daten von Watch Extension über 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() 
    } 
} 

Diese Klasse-Datei, sowie meine Kern-Data-Modell und die folgende Klasse alle in Ziel Mitgliedschaft aller sind die genannten Ziele. Das Codegen der Entitäten wird auf Class Definition festgelegt. Bisher habe ich die Standardimplementierung für den Core Data-Stack bin mit:

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)") 
      } 
     } 
    } 
} 

Nun ist die seltsame Teil: Der Zugriff auf diese Daten aus dem heute- und Message-Erweiterung scheint ordnungsgemäß zu arbeiten (ich gehe davon aus das Suche- Extension funktioniert auch, aber soweit ich als Entwickler das nicht testen kann). Der Versuch, es mit derselben Anfrage von der Erweiterung der Watch-App zu holen, führt zu einem leeren Array. Hier ist mein Abrufcode:

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 
    } 

Ein bisschen mehr Kontext zum besseren Verständnis: Die POI Entitie enthält geografische Breite und Länge eines Orts. Beim Start der App berechne ich die Entfernung zu jedem Punkt in der Datenbank von der aktuellen Benutzerposition aus. Wenn die Today-Extension versucht, die nächsten x (in meinem Fall 8) POIs an die aktuelle Benutzerposition zu bringen, ist das Abrufen aller 15k POIs und das Berechnen ihrer Entfernung zu viel Speicher. Also musste ich den Abstand vorberechnen (gespeichert in locationDistanceCalculated), dann in einem bestimmten Radius (dem statischen SETTINGS_MAXIMUM_FETCH_DISTANCE) abholen und eine genaue Entfernung während des Holprozesses berechnen (gespeichert in einer transienten Eigenschaft locationDistanceTransient).

In dem ExtensionDelegate Klasse Watch App ein CLLocationManagerDelegate implementiert und der Code wird aufgerufen, wenn der Standort des Benutzers aktualisiert:

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) 
      } 
     } 
    } 
} 

Es in Simulator und auf einem Gerät getestet wurde. Die context.fetch gibt immer ein leeres Array zurück (Ja, Kerndaten enthalten Werte und ja, ich habe es ohne Prädikat getestet). Fehle ich etwas Neues in Core Data, das ich noch nicht in Betracht gezogen habe, oder sind es irgendwelche Einschränkungen in WatchOS3, warum dies nicht funktioniert? Hat jemand eine Ahnung? Danke für Ihre Hilfe.

Update: Wenn Sie ein Watch Framework-Ziel für den Zugriff auf Core-Daten verwenden, wie beschrieben in this project, bleibt der Abruf leer. Vielleicht könnte dies der richtige Weg sein, aber ein Watch Framework ist die falsche Wahl. Wird dich auf dem Laufenden halten.

Update 2: Ich habe bereits überprüft die App Programming Guide für WatchOS und die transferFile:metadata:function in den API-Referenzen, aber es scheint nicht ein geeigneter Weg zu sein, um diese großen Datenmengen an den Apple Watch zu senden. Ich kann mich einfach nicht auf den Umstand verlassen, dass der Nutzer die App öfter überprüft als er aus dem Radius SETTINGS_MAXIMUM_FETCH_DISTANCE fährt und für Orte mit hoher POI-Dichte sind diese Daten noch umfangreicher.

Update 3: Ich habe das in der Nähe befindliche Feature für POIs, die nur in einem bestimmten Radius abgerufen werden sollen, erneut implementiert. Wenn dies ein Problem für Sie löst, lesen Sie diese öffentliche Gist.

Antwort

2

Seit Uhr OS3 Sie können nicht auf eine CoreData Basis App Gruppe Trick (weil die Uhr ohne Telefon funktionieren soll.

So haben Sie WatchConnectivity zu benutzen, um Ihre Daten

+0

Dank holen für Ihre Hinweis auf WatchConnectivity, dies ist in der Nähe einer möglichen Lösung, aber nicht das, was ich implementieren wollte.Vielleicht werde ich es versuchen und den Rest der Implementierung darum wickeln.Sie erhalten die Belohnung. – cr0ss

Verwandte Themen