使用可选类型时,RealmSwift和Codable

诺克斯

我在项目中使用RealmSwift和编码很久了,但是,我的api开发人员只给了我两个新属性,它们仅在对象的某些返回调用中存在。如果我致电getUserInfo,则会收到user model没有这两个属性的。在这种情况下,您可以在可编码中使用decodeIfPresent,并将数据类型设置为可选。但是,这两个字段是纪元时间值,使它们成为某种数字。域要求您的数据类型以开头@objc

@objc dynamic var scanIn:Double = 0

当然,所有数字原语都是这样工作的,但是NONE它们都是可选的。您必须使用NSNumber或类似的选项才能将可选项与一起使用ObjC,但是幸运的是,Codable它不适用于NSNumber我知道我在这里有很多不同的选择,但是我确实在寻找一种简单快捷的方法,不需要我通过映射来重建整个模型或在收到模型时进行转换。我现在将写出一种解决方法,但我真的很想让事情简单明了。

我试图设置一个值,如果没有返回,并且只使用这样的非可选类型

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

但是,由于某种原因,这会将ALL值设置为0。我不知道为什么要这么做,但是另一个开发人员建议它不能像这样在可编码中工作,因此我不得不将double设置为optional。我想澄清一下,此数字在转换之前立即存在,但在转换之后为0。

有什么容易解决的想法吗?也许我做错了什么?

诺克斯

Vin Gazoli给了我丢失的钥匙。

首先,需要将RealmOptional声明为let,因此在初始化中,您需要使用设置值myObject.myVariable.value = newValue然后,在任何使用它的地方都必须同时将它用作obj.variable.value。但是,RealmOptional不符合可编码要求,因此您必须编写一个扩展名。您可以在下面找到它以及指向我收到它的地方的链接。

对象的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
}

要使上述对象起作用,需要以下代码。从该链接与该页面的注释中的h1m5修复一起检索以下是Double。链接具有其他原语。

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何将列表类型与Codable结合使用?(RealmSwift)

的区别?和 !何时使用可选类型的实例?

使用 Codable 和 Combine 时转换 Alamofire 响应

Swift 3警告:检查可选项时使用的'String'类型的非可选表达式

检查可选内容时使用的'AnyObject'类型的非可选表达式

可选<>和返回类型缩小

对NSAttributedString使用Codable时出错

在使用ComboBox和本地存储时,queryMode:'local'是可选的吗?

在使用Swift inout和可选控件时需要帮助

无法简单重载时混合使用可选参数和参数

使用 Codable 时,如何在枚举 CodingKeys 中指定多个类型进行解码?

使用Swift 4的Codable进行类型转换

使用JSONEncoder编码类型为Codable的变量

在动态类型/对象上使用Codable

Swift Codable如何使用Any类型?

Swift 使用 Codable,但类型不正确

如何使RealmSwift RealmOptional与Swift Codable兼容?

使用PolyKinds和类型族时的歧义

使用 SCOOP 时的异常和类型错误

遍历它们时使`?:`类型保持可选

带有混合类型的 Swift 字典(可选和非可选)

快速可选的通用类型和嵌套的可选展开

类型与可空类型和可选类型不匹配

TypeScript条件类型解析和可选属性

TypeScript接口的可选属性和返回类型

当我使用泛型类型时,为什么“ void”不适用于可选参数?

等效类型但在使用可选索引签名时不可分配:为什么?

使用Codable时发生错误-Swift

使用 Codable 时链接 Realm 对象