在CoreData中保存Swift CLLocation

8

我正在尝试将CLLocation数据保存在Core Data中,我的属性被设置为可转换的对象。

一些示例代码显示,可以使用此objc将位置数据保存为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`对象捕获到存储在`CoreData`中的`NSValue`中,以便在以后的某个时间从存储中恢复`CLLocation`对象。在测试各种方法时,我发现当尝试从Core Data存储中拆包`CLLocation`对象时返回了nil。我使用以下代码将`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对象会返回“found nil... error”错误。我是否遗漏了一些关于使用Swift存储/检索CLLocation对象的明显内容? 更新 Daniel的答案帮助我意识到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")

从数据存储中恢复对象图

在主视图控制器中,作为默认的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

在“保存CLLocation对象图”下,newManagedObject是什么?您能展示一下初始化该对象的代码行吗?谢谢。 - SMPLGRP
3个回答

4

当您为CLLocation对象创建NSManagedObject子类时,将会遇到较少的麻烦。然后创建用于存储和检索的方法以方便操作:

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

您需要根据此类设置实体来设置您的数据模型。

1
谢谢zisoft,这个解决方案没有问题,但是我更喜欢尽可能保持简单。如果可能的话,我会避免使用NSManaged对象子类。最终,根据问题中的更新,我使用了NSKeyedArchiver来捕获CLLocation的对象图。 - Tommie C.

3
你需要注意的是,NSValue适用于存储类型,即连续的内存块,而不是对象。CLLocation是一个对象。
为了将CLLocation存储在核心数据中,你需要存储每个属性。另一种选择是使用编码器。

谢谢,这非常有用。我决定将整个对象封装到数据字段中进行归档。NSValueTransformer 的实验就到此结束 :) - Tommie C.

1
这篇文章仍然有用,但有点过时。
为了保存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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接