2016-09-12 13 views
1

У меня есть пользовательский класс, содержащий много информации. Это приложение для отслеживания местоположений, поэтому мне нужны местоположения позже (в основном только x, y, z, но я использую CLLocations для удобства). Прямо сейчас у меня есть пользовательский класс, содержащий всю информацию о каждом отслеживании, например, файл записи/сохранения). Я использую Realm, чтобы сохранить это, и Realm отлично справляется с моими двойниками и строками, но у меня проблемы с массивами данных.Сохранение массивов данных или пользовательских классов с помощью Realm

Наиболее удобным решением, которое я могу найти, является преобразование данных в NSData. С помощью Google я нашел два метода для кодирования и декодирования. Но у меня нет опыта в этом, поэтому я не уверен, что он работает. И я не думаю, что это работает.

Я могу загрузить парные и струнные в порядке, но мои NSData кажутся пустыми. Я попытался просто закодировать мой класс в NSData и сохранить его с помощью Realm, но это, похоже, не работает, поэтому моя теория о том, что функции кодирования/декодирования работают неправильно.

TL; DR У меня есть свой пользовательский класс (запись данных), который я хотел бы сохранить с помощью Realm. Как мне обойти это лучше всего?

Мой класс:

class DataRecord { 
    var startLocation : CLLocation = CLLocation.init() 
    var endLocation : CLLocation = CLLocation.init() 
    var duration : Double = 0.0 
    var distance: Double = 0.0 

    var avgSpeed : Double = 0.0 
    var topSpeed : Double = 0.0 

    var locations : [CLLocation] = [] 
    var altitudes : [Double] = [] 
    var angles : [Double] = [] 
    var speeds : [Double] = [] 
} 

Мои NSData кодирования/декодирования

func encode<T>(value: T) -> NSData { 
    var val = value 
    return withUnsafePointer(&val) { p in 
     NSData(bytes: p, length: sizeofValue(value)) 
    } 
} 

func decode<T>(data: NSData) -> T { 
    let pointer = UnsafeMutablePointer<T>.alloc(sizeof(T.Type)) 
    data.getBytes(pointer, length: sizeof(T)) 

    return pointer.move() 
} 

Класс Realm имеют почти такой же, как мои записи, следовательно, причина, почему это было бы проще просто закодировать запись и сохранить его в Царстве. Но вот это:

class Record: Object { 
    dynamic var name = "" 
    dynamic var locations = NSData() 
    dynamic var altitudes = NSData() 
    dynamic var angles = NSData() 
    dynamic var speeds = NSData() 
    dynamic var distance = 0.0 
    dynamic var duration = 0.0 
    dynamic var topSpeed = 0.0 
    dynamic var avgSpeed = 0.0 
    dynamic var topAngle = 0.0 
    dynamic var avgAngle = 0.0 
} 

ответ

3

Realm поддерживает только базовые типы данных, так что вы правы в необходимости «перевести» данные из CLLocation к чему-то, что Realm может хранить.

В этом случае, вместо того, чтобы пытаться сериализовать CLLocation к NSData, это было бы намного проще просто сделать еще один Realm Object подкласс, который содержит те же данные, CLLocation, и может создавать объекты этого типа на лету.

Кроме того, в то время как это несколько ограничивает, Realm может хранить только другие Realm Object s в своих List свойствах. Поэтому в этом случае необходимо будет обернуть другие значения (например, высоты и т. Д.) В своих собственных подклассах Realm Object.

class Location: Object { 
    dynamic var latitude = 0.0 
    dynamic var longitude = 0.0 
    var clLocation: CLLocation { 
     return CLLocation(latitude: self.latitude, longitude: self.longitude) 
    } 

    init(clLocation: CLLocation) { 
     self.latitude = clLocation.latitude 
     self.longitude = clLocation.longitude 
    } 
} 

class Altitude: Object { 
    dynamic var altitudeValue = 0.0 
} 

class Angle: Object { 
    dynamic var angleValue = 0.0 
} 

class Speed: Object { 
    dynamic var speedValue = 0.0 
} 

class Record: Object { 
    dynamic var name = "" 

    dynamic var startLocation: Location? 
    dynamic var endLocation: Location? 

    dynamic var distance = 0.0 
    dynamic var duration = 0.0 
    dynamic var topSpeed = 0.0 
    dynamic var avgSpeed = 0.0 
    dynamic var topAngle = 0.0 
    dynamic var avgAngle = 0.0 

    let locations = List<Location>() 
    let altitudes = List<Altitude>() 
    let angles = List<Angle>() 
    let speed = List<Speed>() 
} 
+0

Ура! Работает! :) спасибо. Его на самом деле довольно удобно сохранять, но не так удобно для доступа, так как мне придется добавить дополнительную информацию, чтобы получить значения из каждого объекта.Для меня самого, я поместил toDataRecord в объект Record, чтобы преобразовать его в мой класс DataRecord, чтобы он работал по назначению на всем моем приложении. Самый большой аргумент в пользу этого - использование CLLocations, но в основном другие списки могут остаться нетронутыми. Но для согласованности я сделал функцию toDataRecord, которая делает вещи намного проще :) – dkcas11

+0

Отлично! Я рад, что это работает! :) Ах, справедливо! Одной вещью, которую вы также можете рассмотреть, является преобразование в 'String' вместо' NSData'. Я закончил работу с Realm в одном из своих приложений, чтобы сохранить значение CGRect. – TiM

0

Если ваш модельный класс подтверждает протокол NSCoding, то это, как вы можете поместить его в Царство.

Пример: Маршрут - это моя модель.

struct Route { 
    fileprivate (set) var locations: [CLLocation] 

    init() { 
     locations = [] 
    } 

    init(withLocations locations: [CLLocation]) { 
     self.locations = locations 
    } 
} 

RouteRealm оборачивает для маршрута дает возможность сохранить объект Realm

class RouteRealm: Object { 
    dynamic var locations: Data? = nil 

    convenience init(route: Route) { 
     self.init() 
     self.locations = NSKeyedArchiver.archivedData(withRootObject: route.locations) 
    } 

    func route() -> Route { 
     if let locations = locations, 
      let clLocations = NSKeyedUnarchiver.unarchiveObject(with: locations) as? [CLLocation] { 
      return Route(withLocations: clLocations) 
     } 
     return Route() 
    } 
} 

Хранение:

struct RealmStore: DataStore { 
    let realm = try! Realm() 

    func store(route: Route) { 
     let routeRealm = RouteRealm(route: route) 
     try! realm.write { 
      realm.add(routeRealm) 
     } 
    } 

    func routes() -> [Route] { 
     let routesRealm = realm.objects(RouteRealm.self) 
     let routes = routesRealm.map() { $0.route() } 
     return Array(routes) 
    } 
} 

protocol DataStore { 
    func store(route: Route) 
    func routes() -> [Route] 
}