使用可选类型时,RealmSwift和Codable

使用可选类型时,RealmSwift和Codable,swift,swift3,realm,codable,Swift,Swift3,Realm,Codable,我在一个项目中使用了RealmSwift和Codable很长一段时间,但是,我的api开发人员给了我两个新属性,它们只存在于对象的一些返回调用中。如果我调用getUserInfo,我会收到一个没有这两个属性的用户模型。在这种情况下,您将使用codable中的decodeIfPresent并将数据类型设置为optional。然而,这两个字段是历代时间值,使它们成为某种数字。Realm要求数据类型的前缀为@objc @objc dynamic var scanIn:Double = 0 当然,所有

我在一个项目中使用了
RealmSwift
和Codable很长一段时间,但是,我的api开发人员给了我两个新属性,它们只存在于对象的一些返回调用中。如果我调用
getUserInfo
,我会收到一个没有这两个属性的
用户模型。在这种情况下,您将使用codable中的decodeIfPresent并将数据类型设置为optional。然而,这两个字段是历代时间值,使它们成为某种数字。Realm要求数据类型的前缀为
@objc

@objc dynamic var scanIn:Double = 0
当然,所有的数字原语都是这样工作的,但是没有一个是可选的。您必须使用
NSNumber
或类似的选项才能与
ObjC
一起使用,但幸运的是,
Codable
不能与
NSNumber
一起使用。我知道我在这里有很多不同的选择,但我真的在寻找一些简单而快速的东西,不需要我用映射重建整个模型,或者在收到它时转换所有东西。我现在会写一个解决方法,但我真的希望保持简单和干净

我试着在none返回时设置一个值,只使用这样一个非可选类型

scanIn = try container.decodeIfPresent(Double.self, forKey:.scanIn) ?? 0
但是,由于某些原因,这会将所有值设置为0。我不知道它为什么会这样做,但另一个开发人员建议它在codable中不能这样工作,我必须将double设置为可选。我想澄清的是,这个数字在转换之前就存在,但在转换之后是0


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

您可以使用
realmopational
类型

如合同所述:

可选数字类型使用
RealmOptional
类型声明:

let age=RealmOptional()
RealmOptional
支持
Int
Float
Double
Bool
,以及
Int
的所有大小版本(
Int8
Int16
Int32
Int64


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

首先,RealmOptional需要声明为let,因此在init中需要使用
myObject.myVariable.value=newValue
设置值。然后,无论在哪里使用它,都必须将其用作obj.variable.value。不过,RealmOptional不符合codable,所以您必须编写一个扩展。你可以在下面找到它以及我收到它的链接

对象的例外情况:

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
}
课堂参与者:对象,可编码{
@objc动态变量id=0
@objc动态变量attendeeId=0
@objc动态变量lanId=“”
@objc动态变量firstName=“”
@objc动态变量lastName=“”
@objc dynamic var email=“”
@objc动态变量employeeId=“”
@objc动态变量badgeId=“”
@objc动态var部门=“”
@objc动态变量图片:字符串?=nil
让scanIn=realmopational()
let scanOut=RealmOptional()
重写静态func primaryKey()->字符串{
返回“id”
}
私有枚举编码键:字符串,编码键{
案例id、与会者id、lanId、名字、姓氏、电子邮件、员工id、徽章id、部门、图片、扫描输入、扫描输出
}
必需的便利初始化(来自解码器:解码器)抛出{
self.init()
let container=try decoder.container(keyedBy:CodingKeys.self)
id=try container.decode(Int.self,forKey:.id)
attendeeId=尝试容器.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=尝试container.decodeIfPresent(Double.self,forKey:.scanIn)??0
self.scanOut.value=尝试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
    }
}
}
func assertTypeIsEncodable(utype:T.type,in-wrappingType:Any.type){
防护装置T.self是可编码的。请键入else{
如果T.self==Encodable.self | | T.self==Codable.self{
PremissionFailure(“\(wrappingType)不符合Encodable,因为Encodable不符合自身。必须使用具体类型进行编码或解码。”)
}否则{
PremissionFailure(“\(wrappingType)不符合Encodable,因为\(T.self)不符合Encodable。”)
}
}
}
func AssertTypesDecodable(type:T.type,包装类型中:Any.type){
防护装置T.self是可解码的。键入else{
如果T.self==Decodable.self | | T.self==Codable.self{
PreditionFailure(“\(wrappingType)不符合Decodable,因为Decodable不符合自身。您必须使用具体类型进行编码或解码。”)
}否则{
PreditionFailure(“\(wrappingType)不符合Decodable,因为\(T.self)不符合Decodable。”)
}
}
}
扩展RealmOptional:Encodable,其中值:Encodable{
公共函数编码(到编码器:编码器)抛出{
assertTypeIsEncodable(Value.self,in:type(of:self))
var container=encoder.singleValueContainer()
如果设v=self.value{
try(v为可编码的)。encode(to:encoder)//swiftlint:disable:this force\u cast
}否则{
尝试container.encodeNil()
}
}
}
扩展现实可选:可解码,其中值:可解码{
公共便利初始化(来自解码器:解码器)抛出{
//在这里初始化self,以便获得类型(of:self)。
self.init()
AssertTypesDecodable(Value.self
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
    }
}
}