首页 文章

领域:部分更新

提问于
浏览
0

我在我的Swift项目中使用了realm,我遇到了部分更新对象的问题 .

问题是我有一个对象,其中包含来自服务器 plus 用户生成的信息的信息 . 在我的情况下,默认情况下,主题可以是可见的或隐藏的,但用户可以更改可见性值 .

当我第一次启动我的应用程序时,我调用我的服务器API来获取信息以创建一个Topic对象:它具有 visibilityundefined . 然后用户做出选择并将 visibility 值设置为 visible .

第二次启动应用程序时,我再次从服务器获取信息,然后重新创建主题 . 然后我调用Realm方法 add:update: 来更新对象,但这甚至再次将 visibility 属性更新为 undefined .

我知道还有另一种方法 create:value:update: 但这意味着我必须创建一个包含我想要更新的所有值的大字典 . 我的模型对象不是那么小,在某些情况下我有很多属性,字典会很大 . 我不喜欢这种方法,维护起来很复杂 .

你对如何处理这样的案件有任何暗示吗?

一种可能的方法是创建另一个与Topic有关系的Object(表)和一个在我再次创建Topic时不会被覆盖的属性 visibility ,但是为这个东西创建一个表听起来很奇怪 .

2 回答

  • 1

    如果您将字典传递给 create:value:update: ,这可能会更容易解决,因为您可以简单地省略 visibility 属性,但正如您所说的大小约束,您正在使用已将 visibility 设置为不同的模型对象的新实例服务器响应的值,然后这不能真正得到帮助 . Realm无法告诉您希望保留此特定属性并更改其余属性 .

    如果您使用的是主键,那么最快的解决方法就是先预先通过主键获取原始对象,记下它的 visibility 属性,然后在执行更新后重新设置它 .

    visibility 属性分解为其自己的对象会起作用,但是您很可能遇到与将该属性设置为 nil 的新对象实例相同的问题 .

  • 0

    我的服务 endpoints 的运行方式也遇到了类似的问题 . 它提供了一个完整的实体视图,以及该实体上属性的较小视图,我想在它们被命中时更新模型 . 例:

    class User: Object {
      var id: Int
      var name: String
      var age: Int
      var average: Double
      likes: List<User>
    }
    

    一个 endpoints 获取所有4个字段,另一个 endpoints 只获得 averageid ,仅第三个 likesid ,但是我想从其中任何一个创建/更新模型 . 现在,我可以在返回的原始JSON上使用 create(value:update:) ,但是我的模型会映射不同的键名并执行其他转换的事情(还有Dates和其他东西),我想保留它们,因此可以使用JSON调用 create(value:update:) 字典 .

    我们通过利用Reflection和一个名为 Serializable 的协议解决了这个问题,它看起来像这样:

    protocol Serializable {
      func toDictionary() -> [String: Any]
    }
    
    extension Serializable {
      func toDictionary() -> [String: Any] {
        var propertiesDictionary: [String: Any] = [:]
        let mirror = Mirror(reflecting: self)
        for (propName, propValue) in mirror.children {
          guard let propName = propName else { continue }
          // Attempt to unwrap the value as AnyObject
          if let propValue: AnyObject = self.unwrap(propValue) as AnyObject? {
            switch propValue {
            case let serializablePropValue as Serializable:
              propertiesDictionary[propName] = serializablePropValue.toDictionary()
            case let arrayPropValue as [Serializable]:
              propertiesDictionary[propName] = Array(arrayPropValue.flatMap { $0.toDictionary() })
            case let data as Data:
              propertiesDictionary[propName] = data.base64EncodedString(options: .lineLength64Characters)
            case _ as Bool: fallthrough
            case _ as Int: fallthrough
            case _ as Double: fallthrough
            case _ as Float: fallthrough
            default:
              propertiesDictionary[propName] = propValue
            }
          } else {
            // Couldn't treat as AnyObject, treat as Any
            switch propValue {
            case let arrayPropValue as [Serializable]:
              propertiesDictionary[propName] = arrayPropValue.flatMap { $0.toDictionary() }
            case let primative as Int8:   propertiesDictionary[propName] = primative
            case let primative as Int16:  propertiesDictionary[propName] = primative
            case let primative as Int32:  propertiesDictionary[propName] = primative
            case let primative as Int64:  propertiesDictionary[propName] = primative
            case let primative as UInt8:  propertiesDictionary[propName] = primative
            case let primative as UInt16: propertiesDictionary[propName] = primative
            case let primative as UInt32: propertiesDictionary[propName] = primative
            case let primative as UInt64: propertiesDictionary[propName] = primative
            case let primative as Float:  propertiesDictionary[propName] = primative
            case let primative as Double: propertiesDictionary[propName] = primative
            case let primative as Bool:   propertiesDictionary[propName] = primative
            case let primative as String: propertiesDictionary[propName] = primative
            case let primative as Date:   propertiesDictionary[propName] = primative
            case let primative as Data:   propertiesDictionary[propName] = primative
            default: break
            }
          }
        }
        return propertiesDictionary
      }
      /// Unwraps 'any' object.
      /// See http://stackoverflow.com/questions/27989094/how-to-unwrap-an-optional-value-from-any-type
      /// - parameter any: Any, Pretty clear what this is....
      /// - returns: The unwrapped object.
      private func unwrap(_ any: Any) -> Any? {
        let mi = Mirror(reflecting: any)
        guard let displayStyle = mi.displayStyle else { return any }
        switch displayStyle {
        case .optional:
          if mi.children.count == 0 {
            return nil
          }
          if let (_, some) = mi.children.first {
            return some
          } else {
            return nil
          }
        case .enum:
          let implicitTypes: [Any.Type] = [ImplicitlyUnwrappedOptional<Int>.self,
                                           ImplicitlyUnwrappedOptional<String>.self,
                                           ImplicitlyUnwrappedOptional<Double>.self,
                                           ImplicitlyUnwrappedOptional<Bool>.self,
                                           ImplicitlyUnwrappedOptional<Float>.self,
                                           ImplicitlyUnwrappedOptional<Date>.self]
          if implicitTypes.contains(where: { $0 == mi.subjectType }) {
            if mi.children.count == 0 { return nil }
            if let (_, some) = mi.children.first {
              return some
            } else {
              return nil
            }
          }
          return any
        default: return any
        }
    }
    

    使用此功能,您可以序列化部分填充的对象,然后传递 create(value: obj.toDictionary(), update: true)

    需要注意的几点需要注意: RealmOptional<T>List<T>LinkingObjects<T> 不在此处理,您可以为 RealmOptional<T> 添加显式基元类型的案例,为 LinkingObjectsBase 添加跳过案例,为 ListBase 添加自定义处理的跳过案例(反射/不/ /很好地列表:/)

相关问题