Swift4.0 Codable踩坑之派生类数据的保存

swift 用 UserDefaults 及 Codable 保存类对象或结构实例数组 swift 用 UserDefaults 及 Codable保存类对象或结构实例数组 以前写过一篇《swift 用 UserDefaults 及 NSSecureCoding 保存类对象数组》的文章,虽然能实现类及结构数组的保存,但实际使用时要对每个要保存的类或结构进行编码和解码扩展,保存和读取时的代码也比较多,使用起来比较繁锁,尤其在保存和读取数组比较频繁时。 本篇用 swift4.0带来的协议 Codable 来解决以上所述存在的问题。 Coda... 阅读详情

本以为之前使用Codable的过程中踩的坑已经够多了,今天博主有遇到一个坑,调了一个下午才解决,问题不大,但是中文的技术文里都很少涉及这个问题。

问题描述:遵循了Codable协议的自定义类,派生出的子类JSON化与反JSON化。

简单来说,就是这儿有一个类遵循了Codable协议,其自身可以很方便地使用JSONEncoder和JSONDecoder来JSON化和反JSON化。但是子类就不是那么方便了。系统提示需要实现一个require init?(from:)的初始化方法。通过这次踩坑,博主总结出了两点在使用Codable的过程中需要注意的点。

首先我们通过一个例子来说明吧。
实现一个Person类,包含属性firstName(姓)、lastName(名)、fullName(全名)、age(年龄)和gender(性别)。gender需要使用枚举类型。包含初始化方法,并且可以使用print直接输出,并可以JSON和反JSON化。
再实现一个Student类,继承自Person,并包含自己的stuNo(学号)和department(公寓)属性。department属性需要使用枚举类型。包含初始化方法,并且可以使用print直接输出,并可以JSON和反JSON化。

看要求两个类需要实现的功能不多且相似,本以为会很简单地解决,但编程就是这么有趣。
首先来实现Person类,我们需要一个性别的枚举

//性别的枚举
enum Gender: Int {
    case male    //男性
    case female  //女性
    case unknow  //未知
}

然后就可以实现Person类了。

//人类
class Person: CustomStringConvertible, Codable {
    var firstName: String  //姓
    var lastName: String  //名
    var age: Int  //年龄
    var gender: Gender  //性别

    var fullName: String {  //全名
        get {
            return firstName + lastName
        }
    }

    //构造方法
    init(firstName: String, lastName: String, age: Int, gender: Gender) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
        self.gender = gender
    }

    //实现CustomStringConvertible协议中的计算属性,可以使用print直接输出对象内容
    var description: String {
        return "fullName: \(self.fullName), age: \(self.age), gender: \(self.gender)"
    }
}

Person类的实现非常方便,其中的fullName博主选择使用计算属性,因为它与姓和名相关。然后为了可以使用print输出,Person类遵循了CustomStringConvertible协议,读者也可以继承自NSObject去重写其中的description计算属性,看个人爱好。最后为了可以转换为JSON属性,遵循了Codable协议。编译一下代码,系统报错,说Person类没有遵循Codable协议,然后博主就纳闷儿了。尝试了半天,发现如果自定义的类中嵌套了自定义的类、结构体或枚举,使用Codable协议时,这些嵌套的类型也需要遵循Codable协议,所以,解决方法很简单,直接在Gender枚举上遵循Codable协议就好。
更改代码如下:

enum Gender: Int, Codable {
    case male    //男性
    case female  //女性
    case unknow  //未知
}

然后就是Student类了,基础的实现代码如下:

//学生类
class Student: Person {
    var stuNo: Int  //学号
    var department: Department  //公寓

    //构造方法
    init(stuNo: Int, firstName: String, lastName: String, age: Int, gender: Gender, department: Department) {
        self.stuNo = stuNo
        self.department = department
        super.init(firstName: firstName, lastName: lastName, age: age, gender: gender)
    }

    //重写父类的计算属性
    override var description: String {
        return "stuNo: \(self.stuNo), fullName: \(self.fullName), age: \(self.age), gender: \(self.gender), department: \(self.department)"
    }
}

这时我们就会发现xcode提示你需要实现一个初始化方法,我们点击fix之后自动生成代码如下:

required init(from decoder: Decoder) throws {
        fatalError("init(from:) has not been implemented")
    }

然后,年轻的博主以为问题解决了,试试将Student的实例转换为JSON数据。

//学生实例
var student = Student(stuNo: 20151101001, firstName: "李", lastName: "四", age: 19, gender: .male, department: .two)

print(student)
print()

//JSON化
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let studentData = try encoder.encode(student)

print(String(data: studentData, encoding: .utf8)!)
print()

输出结果如下:
这里写图片描述
哎?没问题呀,别慌。我们再试试将JSON数据转换为Student实例

//反JSON化
let newStudent = try JSONDecoder().decode(Student.self, from: studentData)
print(newStudent)

很不幸,程序crash了。报错的部分截图如下:
这里写图片描述

看到红色部分的错误提示,感觉似曾相识,往上看一下代码,WC,这不跟系统自己生成的初始化方法里面的那句话,一毛一样么?
既然这里错了,我们就需要在这里改正。

到这里,博主开始优快云、简书、知乎各种翻,没有具体的解决代码,于是只有自己试一试了。于是便在改初始化方法中敲下了decoder并用”.”来查看改参数里面有的属性或方法,万幸,不多,一个一个试,发现只有一个container(keyedBy: CodingKey.Protocol)方法可以使用。然后经历几个小时的折磨(一把辛酸泪)。终于找到了解决方法。
我们需要自定义一个遵循CodingKey协议的枚举,可以自定义其枚举值,不过博主推荐跟相应要保存的属性同名,之所以需要定义这个枚举,是decoder的container(容器)需要通过key来反JSON化对应的属性值,具体的实现代码如下:

//自定义CodingKey
enum Key: String, CodingKey {
    case stuNo
    case department
}

使用这个枚举来反序列化相应的属性

required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Key.self)
        self.stuNo = try container.decode(Int.self, forKey: .stuNo)
        self.department = try container.decode(Department.self, forKey: .department)

        try super.init(from: decoder)
    }

到这里,博主的第六感告诉自己,应该还没完(其实吧,是运行继续崩溃)。因为我们只使用自定义的CodingKey枚举来反JSON化,而并没有使用它来JSON化。所以,我们需要重写一个方法

override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: Key.self)
        try container.encode(stuNo, forKey: Key.stuNo)
        try container.encode(department, forKey: Key.department)

        try super.encode(to: encoder)
    }

到这里,构建、运行程序,结果如下:
这里写图片描述
其实这两个方法,在你遵循的那个类中,在编译之后,系统会将其生成在代码当中,我们只是将Person类中的这两个方法重写了而已。

所有的代码如下:

//性别的枚举
enum Gender: Int, Codable {
    case male    //男性
    case female  //女性
    case unknow  //未知
}

//公寓的枚举
enum Department: String, Codable {
    case one, two, three
}


//人类
class Person: CustomStringConvertible, Codable {
    var firstName: String  //姓
    var lastName: String  //名
    var age: Int  //年龄
    var gender: Gender  //性别

    var fullName: String {  //全名
        get {
            return firstName + lastName
        }
    }

    //构造方法
    init(firstName: String, lastName: String, age: Int, gender: Gender) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
        self.gender = gender
    }

    //实现CustomStringConvertible协议中的计算属性,可以使用print直接输出对象内容
    var description: String {
        return "fullName: \(self.fullName), age: \(self.age), gender: \(self.gender)"
    }
}

//自定义CodingKey
enum Key: String, CodingKey {
    case stuNo
    case department
}

//学生类
class Student: Person {
    var stuNo: Int  //学号
    var department: Department  //公寓

    //构造方法
    init(stuNo: Int, firstName: String, lastName: String, age: Int, gender: Gender, department: Department) {
        self.stuNo = stuNo
        self.department = department
        super.init(firstName: firstName, lastName: lastName, age: age, gender: gender)
    }

    //编码方法
    override func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: Key.self)
        try container.encode(stuNo, forKey: Key.stuNo)
        try container.encode(department, forKey: Key.department)

        try super.encode(to: encoder)
    }

    //解码方法
    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: Key.self)
        self.stuNo = try container.decode(Int.self, forKey: .stuNo)
        self.department = try container.decode(Department.self, forKey: .department)

        try super.init(from: decoder)
    }

    //重写父类的计算属性
    override var description: String {
        return "stuNo: \(self.stuNo), fullName: \(self.fullName), age: \(self.age), gender: \(self.gender), department: \(self.department)"
    }
}

//学生实例
var student = Student(stuNo: 20151101001, firstName: "李", lastName: "四", age: 19, gender: .male, department: .two)

print(student)
print()

//JSON化
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let studentData = try encoder.encode(student)

print(String(data: studentData, encoding: .utf8)!)
print()

//反JSON化
let newStudent = try JSONDecoder().decode(Student.self, from: studentData)
print(newStudent)

最后博主总结如下:
1、遵循了Codable协议的类,其嵌套类型也需要遵循Codable协议;
2、遵循了Codable协议的类的派生类,需要重写override func encode(to encoder: Encoder) throws方法和required init(from decoder: Decoder) throws方法。这两个方法都需要使用容器来编码和解码,容器中属性的key与自定义遵循了CodingKey协议的枚举值对应,在将子类中的属性编码和解码之后,需要调用父类的编码或解码方法。

iOS开发 - Swift Codable协议实战:快速、简单、高效地完成JSON和Model转换! Codable是Swift 4.0引入的一种协议,它是一个组合协议,由Decodable和Encodable两个协议组成。它的作用是将模型对象转换为 JSON 或者是其它的数据格式,也可以反过来将 JSON 数据转换为模型对象。Encodable和Decodable分别定义了和两个协议函数,分别用来实现数据模型的归档和外部数据的解析和实例化。最常用的场景就是刚提到的 JSON 数据与模型的相互转换,但是 Codable 的能力并不止于此。 阅读详情

相关推荐

ios-Moya(Alamofire) Codable转modle,简单封装.zip

git地址: https://github.com/XiaojieManager/SwiftProject 简化请求代码,json转换,如图

ios swift5 Codable 本地存储(存取) 字典转模型

参考博客:Swift:缓存Codable数据 - 简书

baidu_40537062的博客 1625

【Web实战】微信小程序逆向

2E 70 6E 67”为带存放路径的文件名称,“00 00 11 7C”对应文件在小程序包中的具体偏移位置,“00 01 01 F7“对应文件在小程序包中的数据长度。但这并不是最初的原项目文件结构,原因是微信服务器会将小程序源码中所有的“js”文件压入“app-service.js”文件中,将所有的“json”文件压入“app-config.json”中,将所有的“wxml”文件压入“page-frame.html”文件中,“wxss”则在处理之后以“html”文件的形式存留在对应页面目录之下。

若有战,召必回 1944

Swift 基于Codable协议使用

Codable协议 继承自 Decodable & Encodable。

书弋江山的博客 733

去面试游戏测试工程师,面试官看着我的简历呆住了

!我个人整理了我这几年软件测试生涯整理的一些技术资料,包含:电子书,简历模块,各种工作模板,面试宝典,自学项目等。欢迎大家点击下方名片免费领取,千万不要错过哦。

MXB1220的博客 7328

【AI】在RK3576上,使用RKNN实现MeloTTS(文本转语音)

在瑞芯微的RK3576上实现TTS(文本转语音)功能,使用CPU实现时,几乎把CPU资源全部耗尽,没有实用价值。通过将MeloTTS转为onnx,再转为RKNN,来使用RK3576的NPU硬件加速,成功实现TTS。

郭老二 563

IOS-Codable简单使用-Swift

在Swift中,需要将Json数据转为实体时,一种简单的方式就是使用系统提供的JSONDecoder进行解码,这种方式需要实体类或结构体继承(实现)(java说法)一个类型别名(typealias)为Codable的东西。

butterfly_new的博客 978

司法AI系统的架构设计:法律知识图谱如何辅助智能庭审?架构师亲测

简单来说,法律知识图谱是一种采用图数据结构(节点Node + 边Edge/关系Relation)来组织和表达法律领域知识的语义网络。它以。

AI 算法实战派 1088

标题:利用`CodableWrapper`提升Swift编码解码体验

标题:利用CodableWrapper提升Swift编码解码体验 在Swift开发中,Codable协议为我们提供了便利的序列化和反序列化功能。然而,它有时也会暴露出一些局限性,例如默认值处理、类型转换以及键映射等。为了解决这些问题,我们向您推荐一个开源项目——CodableWrapper。这个项目借助Swift 5.9引入的宏(macro)特性,极大地增强了Codable的使用体验。 项目介绍 ...

gitblog_00033的博客 441

【3天快速入门WPF】从小白到新手入门教程

嘿,小伙伴们!如果你已经有一定的C#开发基础,但想快速掌握WPF开发,达到企业级水准,那接下来的这个三天快速入门计划绝对适合你!虽然听起来有点挑战,但别担心,只要跟着这个高强度、结构化的学习计划,你一定能搞定它。首先,我们得搞清楚,WPF的核心知识点到底有哪些。要想达到企业级开发水准,XAML、数据绑定、MVVM、控件使用、命令系统、样式模板这些统统都得拿下。听起来是不是有点多?别急,我们把任务分解到三天里,每天安排合理的内容,保证理论和实践相结合,让你学得扎实又高效。

Zy100Papa的博客 1422

【Reality Capture 】01:Reality Capture1.5中文版安装教程(附安装包下载)

本文详细介绍了Reality Capture 1.5中文版的安装步骤。首先,下载并解压Reality Capture v1.4.0汉化版安装包,运行EpicInstaller并更改安装路径。接着,启动Epic Games Launcher,登录或注册账号后下载并安装软件。安装完成后,进入主界面并设置中文语言。此外,还提供了中文补丁的拷贝方法,将ui.xml和RealityCapture_CHS.exe文件分别放置到指定目录,并运行RealityCapture_CHS.exe以完成汉化。最后,文章提供了Rea

智慧空间实验室 1749

swift Codable的使用及简单封装

swift在4.0之前,一直没有一套数据解析的方法。现在4.0后,终于有了Codable可以直接将json转成对象,有望取代OC的KVC机制。 先来看看Codable public typealias Codable = Decodable & Encodable 基本使用 它和NSCoding很像,可以重写decoder和encoder。基本的使用很简单 class Pe

NickQCX的博客 1万+

【嘉立创EDA】PCB 多层板如何交换内层,4层板交换板层

本文使用嘉立创EDA,描述如何在PCB设计时,如何交换各个板层,特别是4层板需要交换内层时,应该如何操作,以供有需要的读者参考。

l64481000的博客 2013

Swift之Codable自定义解析将任意数据类型解析为想要的类型

一、前言 大多数现代应用程序的共同点是,它们需要对各种形式的数据进行编码或解码。无论是通过网络下载的 Json 数据,还是存储在本地的模型的某种形式的序列化表示形式,对于几乎任何 Swift 代码库而言,能够可靠地编码和解码不同的数据都是必不可少的。 这就是为什么 Swift 的 Codable API 能成为 Swift 4.0 的新功能一部分时,具有如此重要的重要原因。从那时起,它已发展成为一种标准的,健壮的机制,可以在 Apple 的各种平台中使用编码和解码包括服务器端 Swift。 Codable

╰つ栺尖篴夢ゞ 5万+

SAP-MM-采购过账接口(与WMS集成)-代码

1、判断传入值非空检验; 2、判断过账日期是否允许在当前期间; 3、判断是否为集采订单业务,是否审批完成; 4、判断是否发布标准成本发布(此业务场景与价格控制3+S有关) 5、保存日志表; 6、判断业务公司订单审批状态; 7、创建STO交货单、集采公司订单过账、STO公司间创建交货单、交货单过账(两步法)、过账失败回滚(冲销交货、删除交货单、冲销集采入库)

qq_32198063的博客 420

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Swift4.0 Codable协议:JSON和模型的转换

简单说明 在OC中,以及Swift4.0之前,系统一直没有一套数据解析的方法。在Swift4.0后,终于推出了Codable协议,可实现json数据和数据模型的相互转换。 首先来下 Codable ,它其实是一个组合协议,有 Decodable 和 Encodable 两个协议组成。 /// A type that can convert itself into and out of an ...

LOLITA0164的博客 1万+

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Swift 之 Codable

自从Swift 4.0 之后取代HandyJSON 的原生解析model 的类 关于 官方文档 /// A type that can convert itself into and out of an external representation. /// /// `Codable` is a type alias for the `Encodable` and `Decodable` pr...

weixin_33755649的博客 797

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

13、Swift中的Codable

13、Swift中的JSON解析1.1 Codable简介1.2 Codable的痛点1.3 Codable的简单使用1.4 json中的key和模型中的Key不对应1.4.1、实现CodingKey协议进行枚举映射1.4.2 keyDecodingStrategy1.5 使用嵌套的JSON对象1.6 处理Sex1.7 处理数组 1.1 Codable简介 Codable 是 Swift 4.0 以后推出的一个编解码协议,可以配合 JSONDecoder 和 JSONEncoder 用来进行 JSON 解

重楼的博客 1983

迁移指南:从Wrap到Swift内置Codable的平滑过渡

Wrap作为一款曾经广受欢迎的Swift JSON编码工具,随着Swift语言的不断发展,其功能已逐渐被Swift内置的Codable协议所取代。本指南将为你提供从Wrap无缝迁移到Codable的完整步骤,帮助你快速掌握这一高效、原生的JSON处理方案。 [![Wrap项目logo](https://raw.gitcode.com/gh_mirrors/wr/Wrap/raw/1aed6e2c

gitblog_00626的博客 922

12、Swift Codable简单使用

一、简介 大多数现代应用程序的共同点是,它们需要对各种形式的数据进行编码或解码。无论是通过网络下载的JSON数据,还是存储在本地的模型的某种形式的序列化表示形式,对于几乎任何Swift代码库而言,能够可靠地编码和解码不同的数据都是至关重要的。 这就是为什么Swift的Codable API是Swift 4.0的一部分时具有如此重要的新功能的重要原因-从那时起,它已成长为Apple平台上针对几种不同类型的编码和解码的标准,健壮的机制、平台以及服务器端Swift。Codable之所以如此出色,是因为它紧密集

Holothurian 2124

为什么选择MetaCodable?对比原生Swift Codable的10大优势

MetaCodable是一个基于Swift宏编程的强大工具,它通过元编程技术增强了Swift原生Codable的实现能力。对于Swift开发者来说,数据序列化和反序列化是日常工作中不可或缺的部分,而MetaCodable正是为解决原生Codable的痛点而生,让这一过程变得更加高效和灵活。 ## 1. 告别繁琐的CodingKeys定义 ✨ 原生Swift Codable要求开发者为每个需要自

gitblog_00459的博客 867

在 Swift 5 中使用 JSON 和 Codable

作者 | Simon Ng来源 | AppCodahttps://www.appcoda.com/json-codable-swift/首先,什么是 JSON?JSON(JavaScr...

iOS_开发 2007

【Swift】 Codable解析以及需要注意的问题

Codable解析注意事项

weixin_43504072的博客 4134

swift Codable 的用法和原理

Codable 也可以代表苹果为 Swift 开发的一套编解码系统,从 Swift 4 开始引入,包含了 Encoder 和 Decoder 协议和他们的两个实现 JSONEncoder、JSONDecoder 和 PropertyListEncoder、PropertyListDecoder。其中 Codable 及其相关协议放在了标准库中,而具体的 Encoder、Decoder 类放在了 Foundation 框架中。

gcs的博客 1959

swift 5.1 Json转换之Codable

对于开发的人员来说,接受后台的数据,并转换成自己的数据模型是常见的事情。但是作为苹果开发者,并没有一个很好的工具去直接转换,必须借助与第三方的开发的库。那么比较好用的有YYModel、MJExtension。当然还有其他的库。但是有个问题,对于第三方库,如果使用过多对于我们开发者来说并不是一件好事。简单分析一下:优点:功能强大,使用方便,提高开发效率,相对较安全出现bug几率较...

海阔天空的专栏 2471

Swift 模型 Codable的使用 model Json转Codable Codable常见问题

一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络,希望未来技术之巅上有你们也有我。

weixin_38716347的博客 253
上一篇: (作业)TableView、Delegate、DataSource
下一篇: (作业)View,Layer,Animation和Gesture
麻豆_matou
博客等级 码龄10年 41粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值