无法用另一个更新一个RealmSwift.List的内容

时间:2017-08-03 05:32:57

标签: swift realm realm-list

有类设置,设备和属性:

class SettingType: CustomStringConvertible {
    let key: Attributes.Keys

    init(key: Attributes.Keys) {
        self.key = key
    }

    var name: String? {
        return self.key.description
    }

    var description: String {
        return "no value in SettingsType"
    }
}

class Setting<T>: SettingType {
    var value: T

    init(key: Attributes.Keys, value: T) {
        self.value = value
        super.init(key: key)
    }

    override var description: String {
        guard let descriptible = value as? CustomStringConvertible else {
            return "value has not description"
        }
        return descriptible.description
    }
}

class Device: Object, Mappable, Extensible {
    override static func primaryKey() -> String? {
        return "id"
    }

    var id = RealmOptional<Int>()
    dynamic var attributes: Attributes!
    dynamic var name: String!
    dynamic var phone: String!
    dynamic var uniqueId: String!
    dynamic var category: String?
    dynamic var contact: String?
    let geofenceIds = RealmSwift.List<Integer>()
    let groupId = RealmOptional<Int>()
    dynamic var lastUpdate: String?
    dynamic var model: String?
    let positionId = RealmOptional<Int>()
    dynamic var status: String?
    dynamic var photo: Data?

    convenience init(id: Int? = nil, attributes: Attributes = Attributes.empty, name: String, phone: String, uniqueId: String) {
        self.init()
        self.id.value = id
        self.attributes = attributes
        self.name = name
        self.phone = phone
        self.uniqueId = uniqueId
    }

    required convenience init?(map: Map) {
        self.init()
    }

    func mapping(map: Map) {
        id.value            <- map["id"]
        attributes          <- map["attributes"]
        name                <- map["name"]
        phone               <- map["phone"]
        uniqueId            <- map["uniqueId"]
        category            <- map["category"]
        contact             <- map["contact"]
        geofenceIds         <- map["geofenceIds"]
        groupId.value       <- map["groupId"]
        lastUpdate          <- map["lastUpdate"]
        model               <- map["model"]
        positionId.value    <- map["positionId"]
        status              <- map["status"]
    }
}

extension Device {
    var settings: [SettingType] {
        get {
            var result = [SettingType]()
            for key in Attributes.Keys.settings {
                switch key {
                case .showOnMap         :
                    result.append(Setting<Bool>(key: key, value: self.attributes.showOnMap))
                case .observers         :
                    result.append(Setting<RealmSwift.List<Observer>>(key: key, value: self.attributes.listObservers))
                case .trackingMode      :
                    guard let trackMode = self.attributes.trackingMode else {
                        result.append(Setting<TrackMode>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<TrackMode>(key: key, value: trackMode))
                case .timeZone          :
                    guard
                        let rawTimeZone = self.attributes.rawTimeZone,
                        let timeZone = TimeZone(rawValue: rawTimeZone)
                        else {
                            result.append(Setting<TimeZone>.defaultValue(for: key)!)
                            break
                    }
                    result.append(Setting<TimeZone>(key: key, value: timeZone))
                case .language          :
                    guard let language = self.attributes.language else {
                        result.append(Setting<Language>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<Language>(key: key, value: language))
                case .sosContacts       :
                    result.append(Setting<RealmSwift.List<Contact>>(key: key, value: self.attributes.listSosContacts))
                case .favoriteContacts  :
                    result.append(Setting<RealmSwift.List<Contact>>(key: key, value: self.attributes.listFavoriteContacts))
                case .alarms            :
                    result.append(Setting<RealmSwift.List<Alarm>>(key: key, value: self.attributes.listAlarms))
                case .silentMode        :
                    result.append(Setting<RealmSwift.List<SilentInterval>>(key: key, value: self.attributes.listSilentMode))
                case .pedometer         :
                    result.append(Setting<Bool>(key: key, value: self.attributes.pedometer))
                case .watchBattery      :
                    result.append(Setting<Bool>(key: key, value: self.attributes.watchBattery))
                case .notifyOnRemoval   :
                    result.append(Setting<Bool>(key: key, value: self.attributes.notifyOnRemoval))
                case .settingModel      :
                    guard let model = self.model else {
                        result.append(Setting<String>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<String>(key: key, value: model))
                case .settingPhone      :
                    guard let phone = self.phone else {
                        result.append(Setting<String>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<String>(key: key, value: phone))
                case .settingUniqueId   :
                    guard let uniqueId = self.uniqueId else {
                        result.append(Setting<String>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<String>(key: key, value: uniqueId))
                case .settingName       :
                    guard let name = self.name else {
                        result.append(Setting<String>.defaultValue(for: key)!)
                        break
                    }
                    result.append(Setting<String>(key: key, value: name))
                default                 :   break
                }
            }
            return result
        }
        set {
            for setting in newValue {
                switch setting.key {
                case .showOnMap         :   self.attributes.showOnMap = (setting as! Setting<Bool>).value

                case .observers         :
                    self.attributes.listObservers.removeAll()
                    self.attributes.listObservers.append(objectsIn: (setting as! Setting<RealmSwift.List<Observer>>).value)

                case .sosContacts       :
                    self.attributes.listSosContacts.removeAll()
                    self.attributes.listSosContacts.append(objectsIn: (setting as! Setting<RealmSwift.List<Contact>>).value)

                case .favoriteContacts  :
                    self.attributes.listFavoriteContacts.removeAll()
                    self.attributes.listFavoriteContacts.append(objectsIn: (setting as! Setting<RealmSwift.List<Contact>>).value)

                case .alarms            :
                    self.attributes.listAlarms.removeAll()
                    self.attributes.listAlarms.append(objectsIn: (setting as! Setting<RealmSwift.List<Alarm>>).value)

                case .silentMode        :
                    self.attributes.listSilentMode.removeAll()
                    self.attributes.listSilentMode.append(objectsIn: (setting as! Setting<RealmSwift.List<SilentInterval>>).value)

                case .trackingMode      :   self.attributes.trackingMode = (setting as! Setting<TrackMode>).value
                case .timeZone          :   self.attributes.rawTimeZone = (setting as! Setting<TimeZone>).value.rawValue
                case .language          :   self.attributes.language = (setting as! Setting<Language>).value
                case .pedometer         :   self.attributes.pedometer = (setting as! Setting<Bool>).value
                case .watchBattery      :   self.attributes.watchBattery = (setting as! Setting<Bool>).value
                case .notifyOnRemoval   :   self.attributes.notifyOnRemoval = (setting as! Setting<Bool>).value
                case .settingModel      :   self.model = (setting as! Setting<String>).value
                case .settingPhone      :   self.phone = (setting as! Setting<String>).value
                case .settingUniqueId   :   self.uniqueId = (setting as! Setting<String>).value
                case .settingName       :   self.name = (setting as! Setting<String>).value
                default                 :   break
                }
            }
        }
    }
}

class Attributes: Object, Mappable {
    static let empty = Attributes()

    enum Keys: String {
        case showOnMap
        case observers
        case trackingMode
        case timeZone
        case language
        case sosContacts
        case favoriteContacts
        case alarms
        case silentMode
        case pedometer
        case watchBattery
        case notifyOnRemoval
        case settingModel
        case settingPhone
        case settingUniqueId
        case settingName
        case emptySetting

        case modified

        case sat
        case rssi
        case battery
        case steps
        case ip
        case distance
        case totalDistance

        static let settings: [Keys] = [.showOnMap, .observers, .trackingMode, .timeZone, .language, .sosContacts, .favoriteContacts, .alarms, .silentMode, .pedometer, .watchBattery, .notifyOnRemoval, .settingModel, .settingPhone, .settingUniqueId, .settingName]

    let sat = RealmOptional<Int>()
    let rssi = RealmOptional<Int>()
    dynamic var battery: String?
    let steps = RealmOptional<Int>()
    dynamic var ip: String?
    let distance = RealmOptional<Double>()
    let totalDistance = RealmOptional<Double>()

    dynamic var showOnMap = false

    dynamic var rawTrackingMode: String?
    var trackingMode: TrackMode? {
        set {
            guard
                let newValue = newValue
                else {
                    self.rawTrackingMode = nil
                    return
            }
            self.rawTrackingMode = newValue.rawValue
        }
        get {
            guard
                let rawTrackingMode = self.rawTrackingMode,
                let trackMode = TrackMode(rawValue: rawTrackingMode)
                else {
                    return nil
            }
            return trackMode
        }
    }

    dynamic var rawTimeZone: String?

    dynamic var rawLanguage: String?
    var language: Language? {
        set {
            guard let newValue = newValue else {
                self.rawLanguage = nil
                return
            }
            self.rawLanguage = newValue.rawValue
        }
        get {
            guard
                let rawLanguage = self.rawLanguage,
                let language = Language(rawValue: rawLanguage)
                else {
                    return nil
            }
            return language
        }
    }

    let listObservers = RealmSwift.List<Observer>()
    let listSosContacts = RealmSwift.List<Contact>()
    let listFavoriteContacts = RealmSwift.List<Contact>()
    let listAlarms = RealmSwift.List<Alarm>()
    let listSilentMode = RealmSwift.List<SilentInterval>()

    dynamic var pedometer = false
    dynamic var watchBattery = false
    dynamic var notifyOnRemoval = false

    dynamic var modified: String?

    dynamic var alarm: String?

    required convenience init?(map: Map) {
        self.init()
    }

    func mapping(map: Map) {
        sat.value           <- map[Keys.sat.rawValue]
        rssi.value          <- map[Keys.rssi.rawValue]
        battery             <- map[Keys.battery.rawValue]
        steps.value         <- map[Keys.steps.rawValue]
        ip                  <- map[Keys.ip.rawValue]
        distance.value      <- map[Keys.distance.rawValue]
        totalDistance.value <- map[Keys.totalDistance.rawValue]
        showOnMap           <- map[Keys.showOnMap.rawValue]

        listObservers           <- map[Keys.observers.rawValue]
        listAlarms              <- map[Keys.alarms.rawValue]
        listSosContacts         <- map[Keys.sosContacts.rawValue]
        listFavoriteContacts    <- map[Keys.favoriteContacts.rawValue]
        listSilentMode          <- map[Keys.silentMode.rawValue]

        trackingMode        <- (map[Keys.trackingMode.rawValue], EnumTransform<TrackMode>())
        rawTimeZone         <- map[Keys.timeZone.rawValue]
        language            <- (map[Keys.language.rawValue], EnumTransform<Language>())
        pedometer           <- map[Keys.pedometer.rawValue]
        watchBattery        <- map[Keys.watchBattery.rawValue]
        notifyOnRemoval     <- map[Keys.notifyOnRemoval.rawValue]
        modified            <- map[Keys.modified.rawValue]
        alarm               <- map["alarm"]
    }
}

问题是,当我尝试使用&#34;设置界面&#34;:

更新设备的属性时
func updateSettings(of device: Device, settings: [SettingType], handler: ((Device) -> Void)? = nil) {
    do {
        try RealmManager.shared.realm.write {
            device.settings = settings
        }
        handler?(device)
    } catch {
        self.fail(with: error)
    }
}

错误地列出了设备更新的属性,我将丢失未更改列表的数据。可能是问题是列表还包含Realm管理对象(Observer,Alarm,Contact,SilentInterval)但它们没有主键?

非常感谢任何帮助。

更新1:找到&#34;错误&#34;,当我从&#34; old&#34;删除所有对象时列表,它还删除&#34; new&#34;中的所有对象一个......但为什么呢?如何摆脱它?

1 个答案:

答案 0 :(得分:1)

由于课程为reference types,当您撰写let newList = oldListoldListRealm List时,您不会复制该列表的内容,只是复制参考。这意味着newListoldList都将指向内存中的相同对象,因此如果您修改其中一个,则两者都将被修改。

要将oldList的所有值复制到newList,您可以在oldList中创建对象的新非托管副本,并使用

将其存储在newList

let newList = oldList.map{Setting(value:$0)}

这样,您应用于其中一个列表的更改就不会反映在另一个列表中。