代码之家  ›  专栏  ›  技术社区  ›  Nox

使用可选类型时的RealmSwift和Codable

  •  3
  • Nox  · 技术社区  · 7 年前

    RealmSwift 但是,我的api开发人员给了我两个新属性,它们只存在于对象的一些返回调用中。如果我打电话 getUserInfo ,我收到 user model 没有这两个属性。在这种情况下,可以在codable中使用decodeIfPresent并将数据类型设置为optional。然而,这两个字段是纪元时间值,使它们成为某种数字。领域要求数据类型以前缀 @objc .

    @objc dynamic var scanIn:Double = 0
    

    NONE 它们中的一个是可选的。你必须使用 NSNumber ObjC ,但幸运的是, Codable 不适用于

    我试着设置一个值,如果没有返回,就使用一个非可选类型

    scanIn = try container.decodeIfPresent(Double.self, forKey:.scanIn) ?? 0
    

    但是,由于某些原因,这会将所有值设置为0。我不知道为什么它会这样做,但另一个开发人员建议它不能像那样在可编码的环境下工作,我不得不将double设置为optional。我想澄清一下,这个数字在转换之前就存在,但在转换之后是0。

    有什么简单的解决办法吗?也许我做错了什么?

    2 回复  |  直到 7 年前
        1
  •  4
  •   Vin Gazoil    7 年前

    你可以用 RealmOptional<Double> 键入。

    documentation :

    可选的数值类型使用 RealmOptional 类型:

    let age = RealmOptional<Int>()
    

    支架 Int , Float , Double Bool ,以及所有大小版本的 内景 Int8 , Int16 , Int32 Int64 ).

        2
  •  0
  •   Nox    7 年前

    文·加佐利给了我丢失的钥匙。

    myObject.myVariable.value = newValue . 然后,无论您在哪里使用它,都必须将其用作obj.variable.value。realmopnational不符合codable,因此必须编写扩展。你可以在下面找到它以及我收到它的地方的链接。

    对象的ex:

    class Attendee: Object,Codable {
    
    @objc dynamic var id = 0
    @objc dynamic var attendeeId = 0
    @objc dynamic var lanId = ""
    @objc dynamic var firstName = ""
    @objc dynamic var lastName = ""
    @objc dynamic var email = ""
    @objc dynamic var employeeId = ""
    @objc dynamic var badgeId = ""
    @objc dynamic var department = ""
    @objc dynamic var picture:String? = nil
    let scanIn = RealmOptional<Double>()
    let scanOut = RealmOptional<Double>()
    
    override static func primaryKey () -> String? {
        return  "id"
    }
    
    private enum CodingKeys: String, CodingKey {
        case id, attendeeId, lanId, firstName, lastName, email, employeeId, badgeId, department, picture, scanIn, scanOut
    }
    
    required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey:.id)
        attendeeId = try container.decodeIfPresent(Int.self, forKey:.attendeeId) ?? 0
        lanId = try container.decode(String.self, forKey:.lanId)
        firstName = try container.decode(String.self, forKey:.firstName)
        lastName = try container.decode(String.self, forKey:.lastName)
        email = try container.decode(String.self, forKey:.email)
        employeeId = try container.decode(String.self, forKey:.employeeId)
        badgeId = try container.decode(String.self, forKey:.badgeId)
        department = try container.decode(String.self, forKey:.department)
        picture = try container.decodeIfPresent(String.self, forKey:.picture)
        self.scanIn.value = try container.decodeIfPresent(Double.self, forKey:.scanIn) ?? 0
        self.scanOut.value = try container.decodeIfPresent(Double.self, forKey:.scanOut) ?? 0
    }
    

    下面的代码是实现上述对象功能所必需的。恢复 from this link 与h1m5在该页评论中的修正一起。下面是双人间。链接有其他原语。

    func assertTypeIsEncodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
    guard T.self is Encodable.Type else {
        if T.self == Encodable.self || T.self == Codable.self {
            preconditionFailure("\(wrappingType) does not conform to Encodable because Encodable does not conform to itself. You must use a concrete type to encode or decode.")
        } else {
            preconditionFailure("\(wrappingType) does not conform to Encodable because \(T.self) does not conform to Encodable.")
        }
    }
    }
    
    func assertTypeIsDecodable<T>(_ type: T.Type, in wrappingType: Any.Type) {
    guard T.self is Decodable.Type else {
        if T.self == Decodable.self || T.self == Codable.self {
            preconditionFailure("\(wrappingType) does not conform to Decodable because Decodable does not conform to itself. You must use a concrete type to encode or decode.")
        } else {
            preconditionFailure("\(wrappingType) does not conform to Decodable because \(T.self) does not conform to Decodable.")
        }
    }
    }
    
    extension RealmOptional : Encodable where Value : Encodable {
    public func encode(to encoder: Encoder) throws {
        assertTypeIsEncodable(Value.self, in: type(of: self))
    
        var container = encoder.singleValueContainer()
        if let v = self.value {
            try (v as Encodable).encode(to: encoder)  // swiftlint:disable:this force_cast
        } else {
            try container.encodeNil()
        }
    }
    }
    
    extension RealmOptional : Decodable where Value : Decodable {
    public convenience init(from decoder: Decoder) throws {
        // Initialize self here so we can get type(of: self).
        self.init()
        assertTypeIsDecodable(Value.self, in: type(of: self))
    
        let container = try decoder.singleValueContainer()
        if !container.decodeNil() {
            let metaType = (Value.self as Decodable.Type) // swiftlint:disable:this force_cast
            let element = try metaType.init(from: decoder)
            self.value = (element as! Value)  // swiftlint:disable:this force_cast
        }
    }
    }