我正在使用 Codable
对于我的 WebRequest 响应,它返回一些预定义的字符串或数字。所以,我正在使用枚举。但是当一些意外的值到达 Response 时,我的 Codable 无法解码。
这里有一些代码以便更好地理解。
class WebUser: Codable, Equatable {
static func == (lhs: WebUser, rhs: WebUser) -> Bool {
return lhs.id == rhs.id
}
...
var mobileNumberPrivacy: CommonPrivacyOption?
var emailPrivacy: CommonPrivacyOption?
var dobPrivacy: CommonPrivacyOption?
...
}
enum CommonPrivacyOption: Int, CaseIterable, Codable {
case privacyOnlyMe = 1, privacyPublic, privacyFriends, privacyFriendsOfFriends
//Does not help this optional init function
/*init?(rawValue: Int) {
switch rawValue {
case 1: self = .privacyOnlyMe
case 2: self = .privacyPublic
case 3: self = .privacyFriends
case 4: self = .privacyFriendsOfFriends
default: return nil
}
}*/
}
但有时我从 WebServer 得到,0 表示 dobPrivacy
那时我得到 DecodingError.dataCorrupted
上下文异常 Cannot initialize CommonPrivacyOption from invalid Int value 0
当我获得其他值时,我希望 dobPrivacy 为零,然后是 1/2/3/4。编辑:
let dict1 = [
"id": 2,
"mobileNumberPrivacy": 3,
"emailPrivacy": 4,
"dobPrivacy": 0 // Works perfectly with 1
]
do {
let data1 = try JSONSerialization.data(withJSONObject: dict1, options: .prettyPrinted)
let user1 = try JSONDecoder().decode(WebUser.self, from: data1)
print("User1 created")
}
catch DecodingError.dataCorrupted(let context) {
print(context.codingPath)
print(context.debugDescription)
}
catch {
print(error.localizedDescription)
}
我将这个相同的 Codable WebUser 对象用于配置文件详细信息、搜索用户等。因此,有时 WebRequest 的响应中可能不会再出现一个键。
最佳答案
我建议编写一个属性包装器来为您处理这个问题。
具体来说,让我们编写一个名为 NilOnDecodingError
的属性包装器。变成任何 DecodingError
进入 nil
.
这是NilOnDecodingError
的声明:
@propertyWrapper
public struct NilOnDecodingError<Wrapped> {
public init(wrappedValue: Wrapped?) {
self.wrappedValue = wrappedValue
}
public var wrappedValue: Wrapped?
}
我们已将其定义为包装任何类型,并存储 Optional
.现在我们可以符合
Decodable
当Wrapped
类型是 Decodable
:extension NilOnDecodingError: Decodable where Wrapped: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
do {
wrappedValue = .some(try container.decode(Wrapped.self))
} catch is DecodingError {
wrappedValue = nil
}
}
}
我们可能还希望它是 Encodable
当Wrapped
类型是 Encodable
:extension NilOnDecodingError: Encodable where Wrapped: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
if let value = wrappedValue {
try container.encode(value)
} else {
try container.encodeNil()
}
}
}
现在我们可以包装 WebUser
的适当字段:class WebUser: Codable {
let id: String
@NilOnDecodingError
var mobileNumberPrivacy: CommonPrivacyOption?
@NilOnDecodingError
var emailPrivacy: CommonPrivacyOption?
@NilOnDecodingError
var dobPrivacy: CommonPrivacyOption?
}
为了测试,我们要打印解码用户的字段:extension WebUser: CustomStringConvertible {
var description: String {
return """
WebUser(
id: \(id),
mobileNumberPrivacy: \(mobileNumberPrivacy.map { "\($0)" } ?? "nil"),
emailPrivacy: \(emailPrivacy.map { "\($0)" } ?? "nil")),
dobPrivacy: \(dobPrivacy.map { "\($0)" } ?? "nil")))
"""
}
}
现在我们可以试一试:let json = """
{
"id": "mrugesh",
"mobileNumberPrivacy": 1,
"emailPrivacy": 2,
"dobPrivacy": 1000
}
"""
let user = try! JSONDecoder().decode(WebUser.self, from: json.data(using: .utf8)!)
print(user)
输出:WebUser(
id: mrugesh,
mobileNumberPrivacy: privacyOnlyMe,
emailPrivacy: privacyPublic),
dobPrivacy: nil))
关于swift - 在 swift iOS 中出现意外值时,如何将 nil 设置为可编码枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68021019/