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

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

Некоторый пример кода показывает, что можно сохранить данные о местоположении, используя этот объект, преобразованный в 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 из хранилища позднее.

При тестировании различных методов я обнаружил, что nil возвращается при попытке развернуть объект 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 в этот момент возвращает ошибку "Найдено nil... error"

Я упустил что-то очевидное в хранении/извлечении объектов 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 в рамках подготовки по умолчанию к переходу данные восстанавливаются через контроллер выборки.

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

person Tommie C.    schedule 06.11.2014    source источник
comment
Что такое newManagedObject в разделе «Сохранение графика объекта CLLocation»? Можете ли вы показать строку кода, в которой вы это инициируете? Спасибо.   -  person SMPLGRP    schedule 29.12.2016


Ответы (3)


Чего вам не хватает, так это того, что NSValue предназначен для хранения типов, то есть непрерывных блоков памяти, а не объектов. CLLocation — это объект.

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

person Daniel T.    schedule 07.11.2014
comment
Спасибо, это было очень полезно. Я решил заархивировать весь объект, завернутый в поле данных. Так заканчивается эксперимент с NSValueTransformer :) - person Tommie C.; 09.11.2014

У вас будет гораздо меньше проблем, когда вы создадите подкласс 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
        )
    }

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

person zisoft    schedule 07.11.2014
comment
Спасибо, zisoft, в этом решении нет ничего плохого, однако я предпочитаю, чтобы все было как можно проще. По возможности я избегаю подклассов NSManaged Object. В итоге я использовал NSKeyedArchiver для захвата графа объектов для CLLocation в соответствии с обновлением в вопросе. - person Tommie C.; 09.11.2014

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

Чтобы сохранить 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)
person CodySig    schedule 16.05.2019