【问题标题】:How to implement Codable while using Realm如何在使用 Realm 时实现 Codable
【发布时间】:2019-04-19 08:09:01
【问题描述】:

我正在开发使用 Realm 和 Alamofire 的应用程序。我很高兴在我的 iOS 项目中使用这些库。

但是我必须发布一个包含多个模型列表的模型列表。所以这太深奥了,我的意思是 List inside List 包含模型,而那些模型包含几个模型的列表

为了演示,让我们以我的模型为例

@objcMembers public class MyModel : Object{
    dynamic var Id: String = ""
    dynamic var Name: String = ""
    dynamic var Favorites: List<String>? = nil 
    dynamic var Subjects: List<UserSubject>? = nil 
}


@objcMembers public class UserSubject: Object{
    dynamic var Id: String = ""
    dynamic var Name: String = ""
    dynamic var Teachers: List<Publications>? = nil 
}


@objcMembers public class Publications: Object{
    dynamic var Id: String = ""
    dynamic var Name: String = ""
    dynamic var Editors: List<Editors>? = nil 
}

所以你可以看到这些是列表中的模型,其中包含另一个模型列表。

由于 Realm,我使用 List 作为列表来创建 RelationShip。

问题: 但是现在当我尝试在 Models/Struct 上实现 Codable 时,它​​真的无法识别 List 属性。

我真的不知道如何解决这个问题?有人知道怎么做吗?

更新: 我使用的是 Swift 4.0,基础 sdk 是 11.2

【问题讨论】:

    标签: ios realm swift4 alamofire codable


    【解决方案1】:

    我可以建议你使用Unrealm
    它是一个强大的库,可让您将 Swift 原生类型(结构、枚举、ArraysDictionaries)保存到 Realm 数据库中。所以你不必再担心 Lists 和 Codable 的兼容性了。

    An example model with Codable implementation

    【讨论】:

    【解决方案2】:

    在一个项目中遇到了同样的问题,写了这些扩展:

    import Foundation
    import RealmSwift
    
    extension RealmSwift.List: Decodable where Element: Decodable {
        public convenience init(from decoder: Decoder) throws {
            self.init()
            let container = try decoder.singleValueContainer()
            let decodedElements = try container.decode([Element].self)
            self.append(objectsIn: decodedElements)
        }
    }
    
    extension RealmSwift.List: Encodable where Element: Encodable {
        public func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            try container.encode(self.map { $0 })
        }
    }
    

    通过这些扩展,您可以轻松地使领域对象可编码。像这样

    @objcMembers public class MyModel: Object, Codable {
        dynamic var id: String = ""
        dynamic var name: String = ""
        var favorites = List<String>()
        var subjects = List<UserSubject>()
    }
    
    @objcMembers public class UserSubject: Object, Codable {
        dynamic var id: String = ""
        dynamic var name: String = ""
        var teachers = List<Publications>()
    }
    
    
    @objcMembers public class Publications: Object, Codable {
        dynamic var id: String = ""
        dynamic var name: String = ""
        var editors = List<Editor>()
    }
    
    @objcMembers public class Editor: Object, Codable {
    
    }
    

    【讨论】:

    • 它给了我错误“带有约束的'List'类型的扩展不能有继承子句”
    • List&lt;T&gt; 的属性不必是动态的。你是否让所有元素都实现了Codable 协议?
    • 我不知道如何实现它是主要问题
    • 我更新了我的答案,现在包含您使用 Codable 协议的课程。其实我很简单:当你创建一个类Codable时,它的所有成员也必须是Codable
    【解决方案3】:

    您可以使用列表的扩展名

    斯威夫特 4.1

    extension List: Decodable  where Element: Decodable {
        public convenience init(from decoder: Decoder) throws {
        // Initialize self here so we can get type(of: self).
        self.init()
        assertTypeIsDecodable(Element.self, in: type(of: self))
        let metaType = (Element.self as Decodable.Type) // swiftlint:disable:this force_cast
    
        var container = try decoder.unkeyedContainer()
        while !container.isAtEnd {
            let element = try metaType.init(__from: &container)
            self.append(element as! Element) // swiftlint:disable:this force_cast
        }
      }
    }
    
    extension List: Encodable where Element: Decodable {
        public func encode(to encoder: Encoder) throws {
           assertTypeIsEncodable(Element.self, in: type(of: self))
           var container = encoder.unkeyedContainer()
           for element in self {
               // superEncoder appends an empty element and wraps an Encoder around it.
               // This is normally appropriate for encoding super, but this is really what we want to do.
               let subencoder = container.superEncoder()
               try (element as! Encodable).encode(to: subencoder) // swiftlint:disable:this force_cast
           }
       }
    }
    

    【讨论】:

    • 容易出错。它在扩展行上给出的第一个错误是“带约束的 List 类型扩展不能有继承子句”
    • 以上代码片段适用于 Swift 4+
    • 这使用了 Swift 4.1 中添加的条件一致性
    • 好的,谢谢斯文
    • 它给了我以下错误 1> 带有约束的“列表”类型的扩展不能有继承子句 2> 使用未解析的标识符“assertTypeIsDecodable” 3> 调用中的参数标签不正确(有 '__form; 预期'来自:')
    【解决方案4】:

    试试这个:

    extension List: Decodable where Element: Decodable {
        public convenience init(from decoder: Decoder) throws {
            self.init()
            var container = try decoder.unkeyedContainer()
            while !container.isAtEnd {
                let element = try container.decode(Element.self)
                self.append(element)
            }
        }
    }
    
    extension List: Encodable where Element: Encodable {
        public func encode(to encoder: Encoder) throws {
            var container = encoder.unkeyedContainer()
            for element in self {
                try element.encode(to: container.superEncoder())
            }
        }
    }
    

    在这里找到它:How to use List type with Codable? (RealmSwift)

    【讨论】:

    • 它给了我错误“带有约束的'List'类型的扩展不能有继承子句”
    • 你是在导入“Realm”还是“RealmSwift”?
    • 我正在导入 RealmSwift
    • 你还有其他的列表扩展吗?它是否在导入 RealmSwift 的单独文件中?您是否尝试在构建之前清理项目?抱歉问,但我记得在尝试实现此扩展时看到此错误,并且在这些条件下已解决!
    • 不,我没有一个与 RealmSwift 相关的扩展
    猜你喜欢
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 2018-08-11
    相关资源
    最近更新 更多