Swift中的对象序列化(iOS/macOS)
序列化是将复杂对象(结构体、类、实例)转换为便于存储或网络传输的格式(JSON、Property List、二进制数据)的过程。反序列化是从这些数据中恢复对象的逆向过程。在用于iOS和macOS的Swift中,有两种主要方法:现代协议Codable(及其组成部分Encodable和Decodable)以及来自Foundation框架的较旧协议NSCoding。在本文中,我们将通过代码示例详细分析这两种方法。
1. Codable协议(推荐方式)
Codable是一个结合了Encodable和Decodable的协议。如果结构体或类的所有属性也都遵循Codable(字符串、数字、日期、数组、字典等),它可以自动生成序列化和反序列化的代码。
1.1. 基本JSON序列化
考虑一个简单的用户结构体:
import Foundation
struct User: Codable { let id: Int var name: String var email: String}
// 创建实例let user = User(id: 1, name: "伊万·彼得罗夫", email: "ivan@example.com")
// 序列化为Data(JSON)let encoder = JSONEncoder()encoder.outputFormatting = .prettyPrinted // 为了可读性输出
do { let jsonData = try encoder.encode(user) if let jsonString = String(data: jsonData, encoding: .utf8) { print(jsonString) }} catch { print("序列化错误:\\(error.localizedDescription)")}1.2. 从JSON反序列化
// 假设我们有一个JSON字符串let jsonString = """{ "id": 2, "name": "玛丽亚·斯米尔诺娃", "email": "maria@test.com"}"""
let jsonData = Data(jsonString.utf8)let decoder = JSONDecoder()
do { let decodedUser = try decoder.decode(User.self, from: jsonData) print("姓名:\\(decodedUser.name), 邮箱:\\(decodedUser.email)")} catch { print("反序列化错误:\\(error.localizedDescription)")}1.3. 自定义键(CodingKeys)
如果Swift中的属性名称与JSON中的键不同,请使用CodingKeys枚举:
struct Article: Codable { var title: String var body: String var publicationDate: Date
enum CodingKeys: String, CodingKey { case title case body case publicationDate = "published_at" // JSON中的键 }}
let articleJSON = """{"title":"Swift Codable","body":"文章正文","published_at":"2024-01-15T10:00:00Z"}"""let articleData = Data(articleJSON.utf8)let decoder = JSONDecoder()decoder.dateDecodingStrategy = .iso8601 // 为了正确解析日期
if let article = try? decoder.decode(Article.self, from: articleData) { print("标题:\\(article.title), 日期:\\(article.publicationDate)")}1.4. PropertyListEncoder / PropertyListDecoder
要序列化为Property List格式(XML或二进制),请使用PropertyListEncoder:
let plistEncoder = PropertyListEncoder()plistEncoder.outputFormat = .xml
if let plistData = try? plistEncoder.encode(user) { // plistData可以保存到文件 let plistString = String(data: plistData, encoding: .utf8) print(plistString ?? "无效数据")}2. NSCoding协议(适用于继承自NSObject的类)
NSCoding是来自Objective-C的协议,至今仍用于类的序列化,特别是那些与UIKit/AppKit(例如UIView、UIViewController)一起工作的类。它要求类继承自NSObject并实现encode(with:)和init?(coder:)方法。