当使用 Xcode 项目时
当使用 Swift Package Manager 清单时
选择包版本
1.1.1
production
一些帮助你们序列化东西的工具
一些帮助大家进行序列化操作的工具
Swift 的 JSON 编码和解码非常好!... 但是 API 可以更简洁易用一些。
这个软件包带来了这种便利!
// Let's start this example with a simple struct.
// It's got a little bit going on: there's two fields, each a different type, and one is `Optional`.
//
// Its Codable conformance is synthesized from its fields all being Codable.
// I'm also making it `Equatable` so we can make sure things work properly
struct NamedCount: Codable, Equatable {
let name: String
let count: UInt?
}
// Now let's make some instances to work with
let bananaCount = NamedCount(name: "Bananas", count: 7)
let tomorrowEventSecondsCount = NamedCount(name: "Number of Seconds In Tomorrow's Event", count: nil)
// With those made, what's it look like to serialize them?
// Well, before this package, you'd have to make a JSONEncoder object, then configure it, then use it, then.... dispose
// of it I guess? Kinda feels like Objective-C, doesn't it? (Swiftjective-C?)
//
// With this package, it's as simple as calling `.jsonString()`!
// You can even pass configuration to it as parameters! Very Swift-y
// `.jsonString()` creates a UTF-8 JSON string
let bananaCountJsonString = try bananaCount.jsonString()
// {"name":"Bananas","count":7}
// `.jsonData()` creates a UTF-8-encoded JSON string as raw `Data`
let tomorrowEventSecondsCountJsonData = try tomorrowEventSecondsCount.jsonData()
// Essentially {"name":"Number of Seconds In Tomorrow's Event"}
// Well that was easy! But what about decoding?
// That, too, is similarly natural and Swift-y:
let decodedBananaCount = try NamedCount(jsonString: bananaCountJsonString)
let decodedTomorrowEventSecondsCount = try NamedCount(jsonData: tomorrowEventSecondsCountJsonData)
// It's like JSON is a first-class citizen!
// And of course the decoded values are just the same as before they were encoded:
assert(decodedBananaCount == bananaCount)
assert(decodedTomorrowEventSecondsCount == tomorrowEventSecondsCount)
// And of course you can use literals with this too:
let countOfRoadsOneCanWalkDown = try NamedCount(jsonString: """
{
"name": "How many roads can one walk down?",
"count": 42
}
""")
Codable
是 Swift 对 NSCoding
的重新设计。我相信大家都会认同 Codable
好得多!
但是,有些情况(尤其是在 Apple 框架中)遵循 NSCoding
协议但不遵循 Codable
协议!那该怎么办呢?
别担心!解决方案*来了!
// Probably the most common way that I run into this is with AppKit and UIKit, so let's use those as examples!
struct User: Codable, Equatable {
let name: String
let avatar: UIImage.CodableBridge?
let favoriteColor: UIColor.CodableBridge
}
// I'll only use one instance this time, because I think it's enough to get the point across.
// Here's Redd. He likes the color red!
//
// Here we see the concession to the API user: they have to use `.codable` to create the codable bridge.
// I recommend making a sugary initializer which just takes the base type, like
// `init(name: String, avatar: UIImage, favoriteColor: UIColor)`
let redd = User(
name: "Redd",
avatar: UIImage(named: "Redd-avatar").codable,
favoriteColor: UIColor(hue: 0.111, saturation: 0.78, brightness: 0.96, alpha: 1).codable
)
// And I'm sure you expect this, but that struct needs nothing more special to be able to encode &and decode it!
let reddJsonString = try redd.jsonString()
// Essentially {"name":"Redd","avatar":"<insert Base64 nonsense here>","favoriteColor":"<insert Base64 nonsense here>"}
let decodedRedd = try Redd(jsonString: reddJsonString)
// And of course the decoded value is just the same as before it was encoded, just like any native `Codable` type:
assert(decodedRedd == redd)
// The other caveat is that accessing the base type's methods is a bit indirect as well:
redd.favoriteColor.value.set()
// But at least accessing fields is straightforawrd thanks to `@dynamicMemberLookup`:
print(redd.avatar.size)
* 由于 Swift 在引用类型初始化器处理方式上的限制,无法为所有
NSCoding
类型合成真正的Codable
实现,避免因无效数据导致崩溃的风险。因此,我决定为所有NSCoding
类型创建一个合成的子类型,它可以同样方便地进行编/解码。我尽力使其尽可能易用;如果您有任何更好的想法,请告诉我!