idea 枚举快速_快速可枚举的枚举

idea 枚举快速

I had a very basic knowledge of Codable which was limited to how to convert JSON data into primitive types such as String, Int, Bool, etc. or how to work with nested JSON objects and Arrays. I have been using it for quite a long time and it was sufficient for the project code to work. But Codable is more powerful than this.

我对Codable有非常基础的知识,其知识仅限于如何将JSON数据转换为基本类型(例如StringIntBool等)或如何使用嵌套的JSON对象和数组。 我已经使用了很长时间了,足以使项目代码正常工作。 但是Codable比这更强大。

In this article, we will discuss a scenario where the JSON we receive has an enum type. Earlier if I had received an enum(which means the value for this key would be within a set of values) in response, I would have converted it to primitive type first, and later in the presenter or view-model layer, I would have converted it to an enum. I am sure most of you would have done the same.

在本文中,我们将讨论一个场景,其中我们收到的JSON具有枚举类型。 早些时候,如果我收到一个枚举 (这意味着此键的值将在一组值之内)作为响应,我将首先将其转换为原始类型,然后在presenter或view-model层中,将其转换为枚举 。 我相信你们大多数人都会做同样的事情。

Now, let’s learn how to convert data to enum in the network layer itself.

现在,让我们学习如何将数据转换为网络层本身中的枚举

Let’s make our network layer more powerful.

让我们使网络层更强大。

具枚举的枚举 (Enums With Decodable)

Let’s consider the following JSON for example:

让我们以下面的JSON为例:

{
"order": {
"id": 12678,
"status": "Shipped",
"item": {
"id": 1209,
"handleWithCare": false
}
}
}

Here, status can hold a pre-defined set of values like Pending, Shipped, Approved, etc. Generally, I would have kept the type for status as String while parsing and later on I would have converted it into an enum. So my JSON model would look something like this:

在这里, status可以包含一组预定义的值,例如PendingShipped,Approved等。通常,在解析时,我会将status的类型保留为String ,以后再将其转换为enum 。 因此,我的JSON模型如下所示:

struct OrderResponse : Decodable {var order: Order?
}struct Order: Decodable {var id: Int?var status: String?var item: Item?
}struct Item: Decodable {var id: Int?var handleWithCare: Bool?
}

status can easily be converted into an Enum type as shown below:

状态可以轻松地转换为Enum类型,如下所示:

struct OrderResponse: Decodable {var order: Order?
}struct Order: Decodable {var id: Int?var status: OrderStatus?var item: Item?
}struct Item: Decodable {var id: Int?var handleWithCare: Bool?
}enum OrderStatus: String, Decodable {case pending = "Pending"case approved = "Approved"case shipped = "Shipped"case delivered = "Delivered"case cancelled = "Cancelled"
}

You might be thinking, so what’s a big deal in that? How you have created a struct for Item, you could have created an enum with raw values for status. This is what I have done in the example as well.

您可能在想,那有什么大不了的? 如何为Item创建结构 您可能已经创建了带有原始状态值的枚举 这也是我在示例中所做的。

This would work perfectly in an ideal situation where the value of status is anything from this pre-defined set only. Now consider a case where this code is in the production environment and what if backend has decided to add a new value, InProcess to this set. You would handle the new value in the existing code. But what will happen to the production app? In this scenario, the JSON data will not be parsed and hence will error out with Swift.DecodingError.dataCorrupted.

这在状态价值为 仅来自此预定义集中的任何内容。 现在考虑这种代码在生产环境中的情况,以及如果后端决定向此集合添加新值InProcess的情况。 您将在现有代码中处理新值。 但是生产应用程序会发生什么? 在这种情况下,将不会解析JSON数据,因此会因Swift.DecodingError.dataCorrupted错误而出错

如何解决这个问题? (How to resolve this problem?)

To solve this, we have to make changes to the enum which we have just created. Add an unknown case with an associated type. As associated values cannot have raw values, you have to remove all the raw values. Now your enum would look something like this:

为了解决这个问题,我们必须对刚刚创建的枚举进行更改。 添加具有关联类型的未知案例。 由于关联值不能具有原始值,因此必须删除所有原始值。 现在,您的枚举将如下所示:

enum OrderStatus: Decodable {case pending, approved, shipped, delivered, cancelledcase unknown(value: String)
}

Now, there is an issue here. Since your parser doesn’t know which JSON key should be mapped to which case, Xcode will throw Type ‘OrderStatus’ does not conform to protocol ‘Decodable’ error when you try to compile the code. Let’s go ahead and add the stub:

现在,这里有一个问题。 由于您的解析器不知道哪个JSON密钥应映射到哪种情况,因此Xcode会抛出类型“ OrderStatus”不符合协议“可解码”错误 当您尝试编译代码时。 让我们继续并添加存根:

enum OrderStatus: Decodable {case pending, approved, shipped, delivered, cancelledcase unknown(value: String)init(from decoder: Decoder) throws {
}
}

You have to add the mapping inside the initializer. But how to do that? You have to use a container for that. Codable provides two containers: KeyedDecodingContainer and SingleValueDecodingContainer. KeyedDecodingContainer is used when you are working with keys. You need to pass the keys to the container and it will return the value for the respective keys. As the name suggests SingleValueDecodingContainer can be used when you are not working with key-value pairs, which is the current scenario.

您必须在初始化器中添加映射。 但是该怎么做呢? 您必须为此使用一个容器。 Codable提供了两个容器: KeyedDecodingContainerSingleValueDecodingContainer 。 使用键时使用KeyedDecodingContainer 。 您需要将密钥传递给容器,容器将返回各个密钥的值。 顾名思义,当您不使用键值对时(当前情况),可以使用SingleValueDecodingContainer

We will create a SingleValueDecodingContainer and retrieve the String data. Now, this data could be mapped to different enum cases as shown below:

我们将创建一个SingleValueDecodingContainer 检索字符串数据。 现在,可以将这些数据映射到不同的枚举实例,如下所示:

enum OrderStatus: Decodable {case pending, approved, shipped, delivered, cancelledcase unknown(value: String)init(from decoder: Decoder) throws {let container = try decoder.singleValueContainer()let status = try? container.decode(String.self)switch status {case "Pending": self = .pendingcase "Approved": self = .approvedcase "Shipped": self = .shippedcase "Delivered": self = .deliveredcase "Cancelled": self = .cancelleddefault:self = .unknown(value: status ?? "unknown")
}
}
}

Now build and run the code. You can see that the errors are gone and the status is parsed into OrderStatus type. Now go ahead and change the value of status in JSON to InProcess. Now status is mapped correctly to the unknown case with value InProcess: unknown(value: “InProcess”). With this even if new values are sent in status, your production code will not break and work just fine. You just need to handle generic unknown(value) case in the app.

现在构建并运行代码。 您可以看到错误消失了,并且状态被解析为OrderStatus类型。 现在,将JSON status值更改为InProcess 。 现在,状态已正确映射到值为InProcess未知案例: unknown(值:“ InProcess”)。 这样,即使状态中发送了新值,您的生产代码也不会中断并且可以正常工作。 您只需要在应用程序中处理一般的unknown(value)大小写。

The entire code would look like this:

整个代码如下所示:

let testJson = """
{
"order": {
"id": 12678,
"status": "InProcess",
"item": {
"id": 1209,
"handleWithCare": false
}
}
}
""".data(using: .utf8)struct OrderResponse : Decodable {var order: Order?
}struct Order: Decodable {var id: Int?var status: OrderStatus?var item: Item?
}struct Item: Decodable {var id: Int?var handleWithCare: Bool?
}enum OrderStatus: Decodable {case pending, approved, shipped, delivered, cancelledcase unknown(value: String)init(from decoder: Decoder) throws {let container = try decoder.singleValueContainer()let status = try? container.decode(String.self)switch status {case "Pending": self = .pendingcase "Approved": self = .approvedcase "Shipped": self = .shippedcase "Delivered": self = .deliveredcase "Cancelled": self = .cancelleddefault:self = .unknown(value: status ?? "unknown")
}
}
}if let orderResponse = try? JSONDecoder().decode(OrderResponse.self, from: testJson!) {
print(orderResponse)
}

Go ahead, paste this code in the playground, and try it yourself. You can try different values for the status and check if it is working fine or not.

继续,将此代码粘贴到操场上,然后自己尝试。 您可以为状态尝试不同的值,并检查其是否工作正常。

I hope this was helpful. Thank you!

我希望这可以帮到你。 谢谢!

翻译自: https://medium.com/swlh/enums-with-decodable-in-swift-2bbc2ddddd6f

idea 枚举快速

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值