VJson

一个 Swift 框架,用于读取、写入和解析 JSON 格式。

VJson 是 Swiftfire Web 服务器项目的一部分。

Swiftfire 网站

参考手册

VJson 也被用作我们在 App Store 中的 proJSON 应用的核心。

特性

安装

VJson 可以通过 Swift Package Manager 使用。只需将其作为依赖项添加到您的包清单中即可。

或者,您可以克隆项目并以下列方式生成 Xcode 框架

  1. 克隆存储库并创建一个 Xcode 项目
$ git clone https://github.com/Balancingrock/VJson
$ cd VJson
$ swift package generate-xcodeproj
  1. 双击该项目以打开它。打开后,在创建框架之前,在 Build Settings -> Packaging 中将 Defines Module 设置为“yes”。(否则,在另一个项目中导入框架将不起作用)

  2. 在使用 VJson 的项目中,通过打开目标的 General 设置并将 VJson.framework 添加到 Embedded Binaries 来添加 VJson.framework。

  3. 在您想要使用它的 Swift 源代码中,在文件顶部导入 VJson。

示例

此代码可以直接使用

func testExample() {

    let top = VJson() // Create JSON hierarchy
    top["books"][0]["title"] &= "THHGTTG"
    let jsonCode = top.code
    
    do {
        let json = try VJson.parse(jsonCode)
        if let title = (json|"books"|0|"title")?.stringValue {
            XCTAssertEqual(title, "THHGTTG")
        } else {
            XCTFail("The title of the first book in the JSON code was not found")
        }
    } catch let error {
        XCTFail("Parser failed: \(error)")
    }
}

典型用例

创建一个空的顶级 JSON 项目

let json = VJson()

从输入创建一个 JSON 层次结构

let json = try VJson.parse(fileUrl)
let json = try VJson.parse(uInt8Ptr, numberOfBytes)
let json = try VJson.parse(string)
let json = try VJson.parse(nsMutableData)

或没有异常

let json = VJson.parse(fileUrl) {... error handler ...}
let json = VJson.parse(uInt8Ptr, numberOfBytes) {... error handler ...}
let json = VJson.parse(string) {... error handler ...}
let json = VJson.parse(nsMutableData) {... error handler ...}

注意 1:从 NSMutableData 创建会从缓冲区中删除使用的数据。

注意 2:错误处理程序的签名是 (code: Int, incomplete: Bool, message: String) -> Void

创建值

let n = VJson(8)
let n = VJson(3.12)
let b = VJson(true)
let s = VJson("A String")

创建集合类型

let a = VJson.array()
let o = VJson.object()

创建一个命名项目

let n = VJson(8, name: "AnyName")
let n = VJson(3.12, name: "AnyName")
let b = VJson(true, name: "AnyName")
let s = VJson("A String", name: "AnyName")
let a = VJson.array(name: "AnyName")
let o = VJson.object(name: "AnyName")

创建 VJson 层次结构的首选方式

let json = VJson()
json["description"] &= "Book price list"
json["books"][0]["title"] &= "Book Title"
json["books"][0]["price"] &= 12.34
json["books"][1]["title"] &= "Second Book Title"

从层次结构检查/检索的首选方式

guard let title = (json|"books"|0|"title")?.stringValue else {...}
guard let price = (json|"books"|0|"price")?.doubleValue else {...}

可以使用 guard let title = json["books"][0]["title"].stringValue else {...},但这可能会产生副作用,可以通过使用管道运算符来避免。请参阅下面的“注意”部分。

将(命名)项目添加到对象

let o = VJson.object()
o.add(VJson(8), name: "AnyName")		// {"AnyName":8}

等效于

let o = VJson.object()
o.add(VJson(8, name: "AnyName"))		// {"AnyName":8}

将项目添加到数组

let a = VJson.array()
a.append(VJson(8))				// [8]

在层次结构中创建项目

let json = VJson()				// {}
var i: Int?
json["first"].intValue = i		  	// {"first":null}

let json = VJson()				// {}
var i: Int?
i = 12
json["first"].intValue = i			// {"first":12}

或使用定义的运算符“&=”

json["first"] &= 23						// {"first":23}

将“first”的类型更改为字符串

json["first"] &= "second"  				// {"first":"second"}

使用下标访问器隐式创建 JSON OBJECT 和 ARRAY

let json = VJson()
json["books"][2]["Authors"][0] &= "Jane" // {"books":[null, null, {"Authors":["Jane"]}]}

显式地将 JSON OBJECT 添加到 JSON OBJECT

let json = VJson()						// {}
json["first"] &= "second"  				// {"first":"second"}
json.add(VJson.object(name: "Child"))	// {"first":"second","Child":{}}

显式地将 JSON ARRAY 添加到 JSON OBJECT

json.add(VJson.array(), name: "Array")	// {"first":"second","Child":{},"Array":[]}

显式地将 JSON OBJECT 添加到 JSON ARRAY

let json = VJson
json["Arr"].append(VJson.object(name: "No1")) // {"Arr":[{"No1":{}}]}

测试和检索值

guard let title = (json|"Book"|3|"Title")?.stringValue else { ... }

迭代对象(或数组)的所有子项

for child in json { ... }

以上示例都使用了“let”变量。如果使用“var”则有另一个选项可用于从 VJson 对象检索值

let json = try! VJson.parse(string: "{\"title\":\"A Good Read\"}")
var title: String?
title &= (json|"title")

注意

下标与管道运算符

下标访问器具有创建不存在的项目以满足完整路径的副作用。

let json = VJson()
guard let name = json["root"][2]["name"].stringValue else { return }

将创建解决该路径所需的所有项目。即使字符串值不会分配给 let 属性,因为它不存在。不必要的项目将在持久化层次结构之前自动删除。但是创建和销毁不必要的项目会花费可以以不同方式花费的时间。

要避免这些副作用,请使用管道运算符

let json = VJson()
guard let name = (json|"root"|2|"name")?.stringValue else { return }

作为一般规则:使用管道运算符从 JSON 层次结构中读取,并使用下标访问器创建 JSON 层次结构。

可以使用管道运算符将值分配给 JSON 层次结构,但前提是写入的项目已经存在

let json = VJson()         			// results in: {}
(json|"top"|2|"name")? &= 42 		// results in: {}
json["top"][2]["name"] &= 42		// results in: {"top":[null, null, {"name":42}]}

数组中具有名称的值

VJson 层次结构中的每个对象都是一个 VJson 对象。 这非常方便,但同时也带来了一些挑战:JSON 规范根据值是否包含在 ARRAY 或 OBJECT 中以不同的方式处理值。 在 OBJECT 中,这些值具有名称。 在 ARRAY 中,值只是没有名称的值。 但是,由于 VJson 仅为所有内容提供一种类型的对象,因此该对象必须具有名称组件。 因此,此名称的可选性取决于 VJson 对象的使用位置。 如果将具有指定名称的 VJson VALUE 插入到数组中会怎样? 好吧,该名称将被忽略。 这(可能)会导致信息丢失,但另一种选择是在层次结构中创建一个额外的对象。 如果这是首选行为,则由应用程序显式创建该对象。 举个例子

let json = VJson()
json["top"].append(VJson(12))				// results in: {"top":[12]}

let json = VJson()
json["top"].append(VJson(12, name: "one"))	// results in: {"top":[12]}

JSON 项目类型更改

允许使用没有可选性的下标访问器需要对 JSON 项目类型转换采取宽松的态度。 为了防止应用程序代码无意中更改 JSON 项目的类型,如果发生这种情况,将会抛出致命错误。

JSON NULL 类型的类型更改始终被认为是合法的。

所有其他类型更改 - 例如 - BOOL 到 ARRAY 或 STRING 到 NUMBER,当静态选项 fatalErrorOnTypeConversion 设置为 'true' 时(这是默认设置),将导致致命错误。 只能通过显式地通过 JSON NULL 类型进行转换才能进行此类类型更改。

要允许对不涉及 NULL 的类型更改采取宽松的态度,请将 fatalErrorOnTypeConversion 设置为“false”。

但请注意,“add”和“append”操作并不宽松。 也就是说,不可能“add”到 ARRAY 或“append”到 OBJECT,因为这可能会导致数据丢失。 但是,存在将 ARRAY 更改为 OBJECT 以及反之亦然的操作。

标准解析器或 Apple 的 NSJSONSerialization 解析器之间的差异

Apple 解析器的优点是它更快,大约是 MacBook Pro 和 PowerMac 上标准解析器的两倍。 然而,Apple 的解析器至少有两个缺点

版本历史

没有计划新功能。 根据需要临时进行更新以支持 Swiftfire 开发。

1.3.5, 1.3.6

1.3.4

1.3.1 - 1.3.3

1.3.0

1.2.2

1.2.1

1.2.0

1.1.0

1.0.0