首页 > 解决方案 > ios meta:我如何摆脱丑陋的雏菊

问题描述

public protocol NodeProtocol
{
    var identifier: String? { get }
    ...
}

var node: (NodeProtocol)?

required public init(from decoder: Decoder) throws
{
    let values = try decoder.container(keyedBy: CodingKeys.self)
    do {
        node = try values.decode(Operation.self, forKey: .node)
    } catch {
        do {
            node = try values.decode(Deposit.self, forKey: .node)
        } catch {
            do {
                node = try values.decode(Loan.self, forKey: .node)
            }
            catch {
                    print ("failure \(error) decoding node")
            }
        }
    }
}

我怎么能把这种丑陋折叠成一个循环,将 Foo.self 转储到一个数组中?

public class BVOperation: Codable { ...
public struct Loan: Codable { ...
public struct Deposit: Codable { ...

如果你尝试这样的事情:

让 types = [Operation.self, Loan.self, Deposit.self] 为 [Any]

let values = try decoder.container(keyedBy: CodingKeys.self)
for type in types {
    do {
        node = try values.decode(type as! (NodeProtocol)?.Type, forKey: .node)
        break
    } catch {
        continue
    }
}

你会得到臭名昭著的协议类型“NodeProtocol”的值不能符合“Decodable”; 只有结构/枚举/类类型可以符合协议

标签: iosswift

解决方案


最好的方法是在您的序列化数据中使用类型键,但如果这不可能,您可以通过执行以下操作来获得一些更好看的代码:

    let types = [Operation.self, Loan.self, Deposit.self]

    let values = try decoder.container(keyedBy: CodingKeys.self)
    for type in types {
        do {
            node = try values.decode(type, forKey: .node)
            break
        } catch {
            continue
        }
    }

此外,do ... catch如果您不喜欢它们,则不需要使用它们。您可以改用可选绑定:

    let types = [Operation.self, Loan.self, Deposit.self]

    let values = try decoder.container(keyedBy: CodingKeys.self)
    for type in types {
        guard let decoded = try? values.decode(type, forKey: .node) else { continue }
        node = decoded
        break
    }

他们也会这样做,但这是一个偏好问题。


推荐阅读