Сохранение Swift CLLocation в CoreData

Я пытаюсь спасти CLLocation данные в основных данных. Мое свойство установлено как Преобразуемый объект.

Некоторые примеры кода показывают, что можно сохранить данные о местоположении, используя этот объект, преобразованный в NSValue,

CLLocationCoordinate2D myLocation;
NSValue *locationValue = [NSValue valueWithBytes:&myLocation objCType:@encode(CLLocationCoordinate2D)]
// then put locationValue into storage - maybe an ObjC collection class or core data etc.

Получение объекта из хранилища данных должно работать с использованием этой парадигмы.

CLLocationCoordinate2D myLocation;
NSValue *locationValue = // restored from your database or retrieved from your collection class
[locationValue getValue:&myLocation];

Я пытаюсь экстраполировать эту идею и охватить всю CLLocation возражать в NSValue Хранится в CoreDataс целью восстановить CLLocation Объект из магазина в более позднее время.

При тестировании различных методов я обнаружил, что при попытке развернуть CLLocation объект из основного хранилища данных. Я размещаю CLLocation Объект в магазин, используя следующее:

//verified that I have a good CLLocation here
newManagedObject.setValue(location as CLLocation, forKey: "location")

Позже я пытаюсь развернуть CLLocation

let location = detail.valueForKey("location")! as CLLocation

Но я считаю, что объект не разворачивается должным образом.

cllocation

Развернутый объект выглядит так:

(CLLocation) location = 0x00007fff59537c90 {
  ObjectiveC.NSObject = {}
}

Так что любое использование CLLocation объект в этот момент возвращает "найдена ноль... ошибка"

Я упускаю что-то очевидное о хранении / получении CLLocation объекты, использующие Swift?

ОБНОВИТЬ

Ответ Даниэля помог мне понять, что NSValueTransformer не будет работать на меня, поэтому я вернулся к подходу, который использовал ранее. В основном кодируйте объектный граф, используя NSKeyedArchiver. Моя цель, как всегда, состоит в том, чтобы использовать самое простое из возможных решений, поэтому я решил не использовать подклассы управляемых объектов, поскольку нужные мне свойства уже находятся в существующем объекте CLLocation. Я изменил трансформируемое поле на Двоичные данные с выбранной опцией (Сохранить во внешнем файле записи). Я решил протестировать этот процесс с минимальными изменениями в шаблоне основных деталей.

модель данных

Сохранение графа объекта CLLocation

//assuming location is a valid CLLocation and data model has a binary data field
let archivedLocation = NSKeyedArchiver.archivedDataWithRootObject(location)
newManagedObject.setValue(archivedLocation, forKey: "location")

Восстановление графа объекта из хранилища данных

На основном vc как часть подготовки по умолчанию к segue данные восстанавливаются через контроллер выборки.

let object = self.fetchedResultsController.objectAtIndexPath(indexPath) as NSManagedObject
let controller = (segue.destinationViewController as UINavigationController).topViewController as DetailViewController
                    controller.detailItem = object 

На подробностях vc я разворачиваю свой граф объектов, используя NSKeyedUnarchiver

var lc = NSKeyedUnarchiver.unarchiveObjectWithData(detail.valueForKey!("location") as NSData) as CLLocation

2 ответа

Решение

Что вам не хватает, так это то, что NSValue предназначен для хранения типов, т. Е. Смежных блоков памяти, а не объектов. CLLocation - это объект.

Чтобы сохранить CLLocation в основных данных, вам нужно будет сохранить каждое из свойств. Альтернатива - использовать кодер.

У вас будет гораздо меньше проблем, когда вы создадите NSManagedObject подкласс для CLLocation объекты. Затем создайте методы для хранения и извлечения для удобства:

import Foundation
import CoreData
import CoreLocation

class LocationPoint: NSManagedObject {

    @NSManaged var latitude: NSNumber!
    @NSManaged var longitude: NSNumber!
    @NSManaged var altitude: NSNumber!
    @NSManaged var timestamp: NSDate!
    @NSManaged var horizontalAccuracy: NSNumber
    @NSManaged var verticalAccuracy: NSNumber
    @NSManaged var speed: NSNumber
    @NSManaged var course: NSNumber

    func initFromLocation(location: CLLocation) {
        self.latitude           = location.coordinate.latitude
        self.longitude          = location.coordinate.longitude
        self.altitude           = location.altitude
        self.timestamp          = location.timestamp

        self.horizontalAccuracy = location.horizontalAccuracy > 0.0 ? location.horizontalAccuracy : 0.0
        self.verticalAccuracy   = location.verticalAccuracy > 0.0 ? location.verticalAccuracy : 0.0
        self.speed              = location.speed > 0.0 ? location.speed : 0.0
        self.course             = location.course > 0.0 ? location.course : 0.0
    }

    func location() -> CLLocation {
        return CLLocation(
            coordinate: CLLocationCoordinate2D(latitude: self.latitude.doubleValue, longitude: self.longitude.doubleValue),
            altitude: self.altitude.doubleValue,
            horizontalAccuracy: self.horizontalAccuracy.doubleValue,
            verticalAccuracy: self.verticalAccuracy.doubleValue,
            course: self.course.doubleValue,
            speed: self.speed.doubleValue,
            timestamp: self.timestamp
        )
    }

Вы должны настроить свою модель данных с сущностью в соответствии с этим классом.

Этот пост все еще полезен, но немного устарел.

Для сохранения CLLocation я использую:

let clocation: [CLLocation]

let archivedLocation = NSKeyedArchiver.archivedData(withRootObject: clocation)

И получить с помощью основных данных:

let unarchivedLocation = NSKeyedUnarchiver.unarchiveObject(with: (coreDataLocation.value(forKey: "location") as! NSData) as Data) as! CLLocation)
Другие вопросы по тегам