codable swift
For this article, I used Xcode 11.4.1 and Swift 5.2. I assume you’re familiar with the basics of Swift.
对于本文,我使用了Xcode 11.4.1和Swift 5.2。 我认为您熟悉Swift的基础知识。
To make iOS Swift apps be able to communicate with servers, we must convert Swift to JSON. In this article, we’ll be looking at how to convert Swift objects to JSON format and the other way around. To enable converting to and from JSON, we’ll be making use of Codable
.
为了使iOS Swift应用程序能够与服务器通信,我们必须将Swift转换为JSON。 在本文中,我们将研究如何将Swift对象转换为JSON格式以及其他方法。 为了实现与JSON的相互转换,我们将使用Codable
。
Codable
is a type that Swift objects can conform to which allows converters to transform the object into another format or from another format to Swift objects. The format can be any desired. Apple already offers JSON converters for Codable types out of the box.
Codable
是Swift对象可以遵循的一种类型,它允许转换器将对象转换为另一种格式或从另一种格式转换为Swift对象。 该格式可以是任何所需的格式。 Apple已经提供了针对Codable类型的JSON转换器 。
In this article, we’ll learn how to convert JSON objects to Swift (and back) by imitating an Apple accessories seller app. We’ll be converting the JSON object that represents the products the merchant sells. We’ll also be converting an order into JSON format.
在本文中,我们将通过模仿Apple配件销售商应用程序来学习如何将JSON对象转换为Swift(并反向转换)。 我们将转换代表商家销售产品的JSON对象。 我们还将把订单转换为JSON格式。
In this tutorial, we’ll make use of Xcode Playgrounds. Playgrounds offers us an easy way of creating and testing our code without the overhead of running an app.
在本教程中,我们将使用Xcode Playgrounds。 Playgrounds为我们提供了一种创建和测试代码的简便方法,而无需运行应用程序。
如何使用Swift Codable将JSON转换为Swift(反之亦然) (How to Convert JSON to Swift (and Vice Versa) Using Swift Codable)
The steps we’ll take:
我们将采取的步骤:
- Create a new Playground project 创建一个新的Playground项目
-
GET the
products
JSON response获取
products
JSON响应 -
Convert the
products
JSON to Swift using Decodable使用Decodable将
products
JSON转换为Swift -
Create the
Order
object and convert it to JSON using Encodable创建
Order
对象,并使用Encodable将其转换为JSON
Let’s dive in!
让我们潜入吧!
1.创建一个新的Playground项目 (1. Create a new Playground project)
First let’s open Xcode. From menu select File > New > Playground…
首先让我们打开Xcode。 从菜单中选择文件>新建>操场…
When prompted with “Choose a template for your new playground,” select the Blank option under the iOS tab. Then click Next.
当出现“选择新操场的模板”提示时,请选择“ iOS”选项卡下的“空白”选项。 然后单击“下一步”。
Name the file codable_json
, and then click Create.
将文件命名为codable_json
,然后单击“创建”。
2.获取“产品” JSON响应 (2. GETting the ‘products’ JSON response)
For this article, we’ll copy and paste the JSON response of the merchants GET products
API endpoint. We won’t be making any network requests, as that’s out of scope of this article. Rather, we’ll be working directly with the response body that’d be returned by the server.
对于本文,我们将复制并粘贴商家GET products
API端点的JSON响应。 我们不会发出任何网络请求,因为这超出了本文的范围。 相反,我们将直接使用服务器将返回的响应主体。
Copy and paste the following into codable_json
:
将以下内容复制并粘贴到codable_json
:
The above code allocates the JSON response string to a constant named productsJson
.
上面的代码将JSON响应字符串分配给名为productsJson
的常量。
The JSON response contains an array of products. Each product has three properties: product_id
, name
, and price
. product_id
is an integer and, name
and price
are strings.
JSON响应包含一系列产品。 每个产品都有三个属性: product_id
, name
和price
。 product_id
是整数, name
和price
是字符串。
3.使用Decodable将产品JSON转换为Swift (3. Convert the products JSON to Swift using Decodable)
Next, let’s convert the products JSON into a Swift object. We’ll first start with creating a Swift representation of a single product from the JSON array of products. The following represents a single product in JSON:
接下来,让我们将产品JSON转换为Swift对象。 我们首先要从产品的JSON数组创建单个产品的Swift表示形式。 以下内容代表JSON中的单个产品:
{
"product_id": 0,
"name": "iPhone 11 Clear Case",
"price": "38.99"
}
Add the following lines to the Playground:
将以下行添加到游乐场:
struct Product {
}
The Product
structure will represent a single product in the JSON string.
Product
结构将在JSON字符串中表示单个产品。
Next let’s add its properties. Let’s begin with name
and price
. Don’t worry about product_id
just yet — we’ll come back to it. Both name
and price
are strings. Within the product structure, add the following two lines:
接下来,让我们添加其属性。 让我们从name
和price
开始。 暂时不必担心product_id
,我们product_id
。 name
和price
都是字符串。 在产品结构中,添加以下两行:
let name: String
let price: String
Now we have a Product
JSON representation in Swift. Next let’s convert the JSON representation of the products to Swift. The converter from JSON to Swift provided by Apple is called JSONDecoder
. It’s called decoder because, from Swift’s perspective, it decodes JSON. In order for the decoder to decode JSON to its Swift representation, the Product
structure must conform to Decodable
.
现在我们在Swift中有了Product
JSON表示形式。 接下来,让我们将产品的JSON表示形式转换为Swift。 Apple提供的从JSON到Swift的转换器称为JSONDecoder
。 之所以称为解码器,是因为从Swift的角度来看,它可以解码JSON。 为了使解码器将JSON解码为其Swift表示形式, Product
结构必须符合Decodable
。
Next add : Decodable
to the Product
structure declaration. Our Product
struct should look like the following:
接下来添加: Decodable
到Product
结构声明中。 我们的Product
结构应如下所示:
struct Product:
let name: String
let price: String
}
Now let’s convert JSON to the Product
by adding the following line:
现在,通过添加以下行,将JSON转换为Product
:
let products = try! JSONDecoder().decode([Product].self, from: productsJson.data(using: .utf8)!)
Let’s print the Swift products to our console. Add the following line:
让我们将Swift产品打印到我们的控制台上。 添加以下行:
print(products)
Finally, run the code by clicking on the blue play button besides the print statement.
最后,通过单击打印语句旁边的蓝色播放按钮运行代码。
The console should show something like the following:
控制台应显示以下内容:
Great! The JSONDecoder
has successfully converted the JSON array of products into an array of Swift products. That was easy!
大! JSONDecoder
已成功将JSON产品数组转换为Swift产品数组。 那很简单!
Let’s now add the productId
property to our Swift Product
. Within the Product
struct add the following:
现在,将productId
属性添加到我们的Swift Product
。 在“ Product
结构中添加以下内容:
let productId: Int
Next, click on the play button next to the print
statement.
接下来,单击print
语句旁边的播放按钮。
You should see the same error as in the screenshot above. So what happened? While the name
and price
properties converted without a problem, productId
raises one.
您应该看到与上面的屏幕快照相同的错误。 所以发生了什么事? 虽然name
和price
属性转换没有问题,但productId
会加一。
The problem here is the property name in Swift is named productId
, while the JSON property name is product_id
. The decoder is smart enough to match property names that are equal. However, the JSON property naming usually follow snake_case styling (product_id
), whereas Swift follows camelCase styling (productId
).
这里的问题是Swift中的属性名称为productId
,而JSON属性名称为product_id
。 解码器足够聪明,可以匹配相等的属性名称。 但是,JSON属性命名通常遵循snake_case样式 ( product_id
),而Swift遵循camelCase样式 ( productId
)。
To solve the problem we can either:
要解决该问题,我们可以:
- Match the property name in Swift to the name on the JSON object 将Swift中的属性名称与JSON对象上的名称匹配
- Create custom property-name mapping on the Swift object 在Swift对象上创建自定义属性名称映射
The first one is an easy change: productId
becomes product_id
in the Swift Product
struct. Hit the play button again.
第一个是一个简单的更改: productId
在Swift Product
结构中成为product_id
。 再次点击播放按钮。
However, I prefer to keep camelCase styling to keep the code looking consistent throughout the code base. In that case, we must tell the JSON decoder how to map the properties. Add the following lines within the Product
struct:
但是,我更喜欢保持camelCase样式,以使代码在整个代码库中看起来保持一致。 在这种情况下,我们必须告诉JSON解码器如何映射属性。 在Product
结构中添加以下行:
enum CodingKeys: String, CodingKey {
case productId = "product_id"
case name = "name"
case price = "price"
}
The above tells the decoder the property name, or the key, in Swift and it’s equivalent in JSON. Unfortunately, we can’t custom map a single property. Thus, we must declare all Swift properties and their equivalent in JSON when opting in for custom-name mapping.
上面的内容告诉解码器Swift中的属性名称或键,在JSON中等效。 不幸的是,我们无法自定义映射单个属性。 因此,在选择自定义名称映射时,必须在JSON中声明所有Swift属性及其等效项。
Hit the play button again, and see it work!
再次点击播放按钮,看它是否起作用!
4.创建一个“订单”对象,并使用Encodable将其转换为JSON (4. Create an ‘Order’ object and convert it to JSON using Encodable)
In this final section, we’ll look at how to convert a Swift object to JSON. We’ll be mimicking an Order
creation in the Apple accessories seller’s app. The seller POST Order
endpoint expects the following to create an order:
在最后一节中,我们将研究如何将Swift对象转换为JSON。 我们将模仿Apple配件销售商的应用程序中的Order
创建。 卖方POST Order
端点期望以下内容创建订单:
{
products: [ProductQuantity]
}
The ProductQuantity
object for the sellers API looks like the following:
卖方API的ProductQuantity
对象如下所示:
{
"product_id": 999,
"quantity": 1
}
Here’s an order example where the customer wishes to buy the wireless charging pad (product ID 1):
这是一个订购示例,客户希望购买无线充电板(产品ID 1):
{
"products": [
{
"product_id": 1,
"quantity": 1
}
]
}
Let’s recreate this order in our Swift Playground. First, let create the ProductQuantity
Swift representation. Add the following lines:
让我们在Swift Playground中重新创建此顺序。 首先,让我们创建ProductQuantity
Swift表示形式。 添加以下行:
struct ProductQuantity {
let productId: Int
let quantity: Int
}
Next, in order to allow Swift to convert, or encode, ProductQuantity
into JSON, the struct must conform to Encodable
. Change the ProductQuantity
declaration to:
接下来,为了允许Swift将ProductQuantity
转换或编码为JSON,该结构必须符合Encodable
。 将ProductQuantity
声明更改为:
struct
Before we convert ProductQuantity
to JSON, we must make sure the property names (or keys) matches the one the server is expecting.
在将ProductQuantity
转换为JSON之前,我们必须确保属性名称(或键 s)与服务器期望的名称匹配。
As we saw before when converting the product
JSON to Swift, the productId
property name doesn’t match the one expected by the server (which is product_id
). Once again, we must tell the converter how to map the property names. Add the following within ProductQuantity
:
正如我们在将product
JSON转换为Swift时所看到的那样, productId
属性名称与服务器期望的名称不匹配(即product_id
)。 再一次,我们必须告诉转换器如何映射属性名称。 在ProductQuantity
添加以下内容:
enum CodingKeys: String, CodingKey {
case productId = "product_id"
case quantity = "quantity"
}
Next, let’s create the structure to represent an Order
. Add the following lines at the end of the Playground file:
接下来,让我们创建表示Order
的结构。 在Playground文件的末尾添加以下行:
struct Order: Encodable {
let products: [ProductQuantity]
}
Let’s create an order for the wireless charging pad with product ID 1. Add the following line of code:
让我们为产品编号为1的无线充电板创建一个订单。添加以下代码行:
let order = Order(products: [ProductQuantity(productId: 1, quantity: 1)])
Finally, let’s convert our order
to JSON and print it to the console. Add the following lines:
最后,让我们将order
转换为JSON并将其打印到控制台。 添加以下行:
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let orderJsonData = try! encoder.encode(order)print(String(data: orderJsonData, encoding: .utf8)!)
Above, we’ve created an instance of JSONEncoder
and configured its format to JSON in a nice readable format instead of a single line. Then, we’ve encoded our order. The encoder spits out Data
. Thus, we must convert it to String
in order to print it to the console. Hit play beside the new print statement.
上面,我们创建了一个JSONEncoder
实例,并将其格式配置为JSON格式,可读性好,而不是一行。 然后,我们对订单进行了编码。 编码器吐出Data
。 因此,我们必须将其转换为String
才能将其打印到控制台。 点击新印刷声明旁边的播放。
The result:
结果:
{
"products" : [
{
"product_id" : 1,
"quantity" : 1
}
]
}
We’ve converted the Swift order to JSON, and it’s ready to send to the server!
我们已经将Swift订单转换为JSON,并且可以发送到服务器了!
摘要 (Summary)
In this, we’ve learned:
在此过程中,我们了解到:
-
What Codable is
什么是可编码
-
How to convert JSON to Swift using Decodable and JSONDecoder
如何使用Decodable和JSONDecoder将JSON转换为Swift
-
How to convert Swift to JSON using Encodable and JSONEncoder
如何使用Encodable和JSONEncoder将Swift转换为JSON
- How to customise encoding and to decode JSON when not using matching property or key names 不使用匹配的属性或键名时如何自定义编码和解码JSON
最后说明 (Final Notes)
You can find the completed Playground down below:
您可以在下面找到完整的游乐场:
In this article, we covered how to either convert to an object from JSON or how to convert an object to JSON. You can do two-way conversions of an object to and from JSON by conforming to Codable instead of Encodable or Decodable.
在本文中,我们介绍了如何从JSON转换为对象或如何将对象转换为JSON。 您可以通过遵循Codable而不是Encodable或Decodable的方式来实现对象与JSON的双向转换。
Furthermore, this article has only covered the basic use cases of Codable. However, things can get more complicated — for example, when mapping a date string to and from a Date
object. That’d be an interesting topic to cover in the future.
此外,本文仅介绍了Codable的基本用例。 但是,事情可能会变得更加复杂-例如,在与Date
对象之间来回映射日期字符串时。 将来将是一个有趣的话题。
codable swift