IkigaJSON 是一个非常快速的 JSON 解析器。在基准测试中,IkigaJSON 与现代 Foundation JSON 具有竞争力,并且在很大程度上优于旧版本的 Foundation JSON。
除了性能更高之外,IkigaJSON 还具有更低且更稳定的内存占用!根据设计,IkigaJSON 在处理更大的 JSON 负载时比 Foundation 扩展性更好。同时,它还提供了一个易于使用的 API,并支持 Codable。
加入我们的 Discord,提出任何问题和进行友好交流。
请注意,Swift 库需要在 RELEASE 编译模式下构建,以便评估性能。如果您在 DEBUG 构建中测试性能,您会发现编译器存在严重的优化不足,这些问题无法在库中合理地修复。在 DEBUG 编译模式下构建 Swift 代码时,它可能比 RELEASE 模式下的等效代码慢 10-20 倍。
上述性能声明是在 macOS 和 iOS 的 Foundation 上测试的。如果您在 Linux 上使用 Swift 5.5,并且使用新的 Foundation for Linux,您的性能会略好一些。Swift 5.5 并不会提高 macOS 或 iOS 上 Foundation 的 JSON 性能。JSON 负载越大,IkigaJSON 的性能就越优于 Linux 的 Foundation JSON。
1.x 版本依赖于 SwiftNIO 1.x,对于 SwiftNIO 2.x 的支持,请使用 2.x 版本的 IkigaJSON。
// SwiftNIO 1.x
.package(url: "https://github.com/orlandos-nl/IkigaJSON.git", from: "1.0.0"),
// Or, for SwiftNIO 2
.package(url: "https://github.com/orlandos-nl/IkigaJSON.git", from: "2.0.0"),
import IkigaJSON
struct User: Codable {
let id: Int
let name: String
}
let data: Data = ...
var decoder = IkigaJSONDecoder()
let user = try decoder.decode(User.self, from: data)
像这样使 Ikiga 符合 Hummingbird 的协议
extension IkigaJSONEncoder: HBResponseEncoder {
public func encode(_ value: some Encodable, from request: HBRequest, context: some HBBaseRequestContext) throws -> HBResponse {
// Capacity should roughly cover the amount of data you regularly expect to encode
// However, the buffer will grow if needed
var buffer = context.allocator.buffer(capacity: 2048)
try self.encodeAndWrite(value, into: &buffer)
return HBResponse(
status: .ok,
headers: [
.contentType: "application/json; charset=utf-8",
],
body: .init(byteBuffer: buffer)
)
}
}
extension IkigaJSONDecoder: HBRequestDecoder {
public func decode<T>(_ type: T.Type, from request: HBRequest, context: some HBBaseRequestContext) async throws -> T where T : Decodable {
let data = try await request.body.collate(maxSize: context.maxUploadSize)
return try self.decode(T.self, from: data)
}
}
像这样使 Ikiga 符合 Vapor 4 的协议
extension IkigaJSONEncoder: ContentEncoder {
public func encode<E: Encodable>(
_ encodable: E,
to body: inout ByteBuffer,
headers: inout HTTPHeaders
) throws {
headers.contentType = .json
try self.encodeAndWrite(encodable, into: &body)
}
public func encode<E>(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws where E : Encodable {
var encoder = self
encoder.userInfo = userInfo
headers.contentType = .json
try encoder.encodeAndWrite(encodable, into: &body)
}
public func encode<E>(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws where E : Encodable {
var encoder = self
encoder.userInfo = userInfo
headers.contentType = .json
try encoder.encodeAndWrite(encodable, into: &body)
}
}
extension IkigaJSONDecoder: ContentDecoder {
public func decode<D: Decodable>(
_ decodable: D.Type,
from body: ByteBuffer,
headers: HTTPHeaders
) throws -> D {
return try self.decode(D.self, from: body)
}
public func decode<D>(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Sendable]) throws -> D where D : Decodable {
let decoder = IkigaJSONDecoder(settings: settings)
decoder.settings.userInfo = userInfo
return try decoder.decode(D.self, from: body)
}
public func decode<D>(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders, userInfo: [CodingUserInfoKey : Any]) throws -> D where D : Decodable {
let decoder = IkigaJSONDecoder(settings: settings)
decoder.settings.userInfo = userInfo
return try decoder.decode(D.self, from: body)
}
}
像这样将编码器/解码器注册到 Vapor
var decoder = IkigaJSONDecoder()
decoder.settings.dateDecodingStrategy = .iso8601
ContentConfiguration.global.use(decoder: decoder, for: .json)
var encoder = IkigaJSONEncoder()
encoder.settings.dateEncodingStrategy = .iso8601
ContentConfiguration.global.use(encoder: encoder, for: .json)
IkigaJSON 支持原始 JSON 类型(JSONObject 和 JSONArray),就像许多其他库一样,以及上面描述的 codable API。关键的区别在于 IkigaJSON 内联编辑 JSON,因此从 Swift 类型到 JSON 没有额外的转换开销。
var user = JSONObject()
user["username"] = "Joannis"
user["roles"] = ["admin", "moderator", "user"] as JSONArray
user["programmer"] = true
print(user.string)
print(user["username"].string)
// OR
print(user["username"] as? String)
编码器和解码器支持 SwiftNIO。
var user = try JSONObject(buffer: byteBuffer)
print(user["username"].string)
我们还添加了将 IkigaJSONEncoder 和 IkigaJSONDecoder 与 JSON 一起使用的功能。
let user = try decoder.decode([User].self, from: byteBuffer)
var buffer: ByteBuffer = ...
try encoder.encodeAndWrite(user, into: &buffer)
上述方法可以用于通过套接字异步地从数据库等源流式传输多个实体。这可以大大减少内存使用量。
根据设计,您可以在任何数据存储之上构建,只要它公开指针 API 即可。这样,IkigaJSON 不需要从您的缓冲区复制任何数据,从而保持轻量级。整个解析器只需 1 次内存分配即可运行,并允许重用 Decoder 以重用内存分配。
此分配(称为 JSONDescription)充当原始数据集的过滤器,指示 IkigaJSON 键、值和对象的开始/结束位置。因此,IkigaJSON 可以进行非常快速的内联修改,并提供诸如 JSONObject/JSONDescription 之类的对象,这些对象在读取单个值时性能极高。这也使得 IkigaJSON 可以从其自身的辅助类型(如 JSONObject 和 JSONArray)解码,因为它不需要重新生成 JSONDescription 并且手头有原始缓冲区。
JSONObject
和 JSONArray
进行 Codable 解码\u
转义的 Unicode 字符