如何定义 Codable 类型的变量?

5
我想创建一个类型为Codable的变量,并在JSONEncoder类中使用它。我认为下面的代码应该可以正常工作,但是它给了我一个错误:

无法调用类型为(Codable)的参数列表的encode

如何声明可编码变量,以便JSONEncoder不会出错?
struct Me: Codable {
    let id: Int
    let name: String
}

var codable: Codable? // It must be generic type, but not Me.

codable = Me(id: 1, name: "Kobra")

let data = try? JSONEncoder().encode(codable!)

这里有一个类似的问题,关于如何使用函数传递Codable。但是我正在寻找如何使用变量(类变量)设置Codable。


@LeoDabus 另一个问题是如何将它传递给JSONEncoder? - Ramis
1
使用 Me 有什么问题吗? - Leo Dabus
@LeoDabus 我已经添加了注释说明这不是重复的。我想避免传递Me结构体。 - Ramis
1
我仍然认为这是一个重复的问题。重新打开可能不会有什么区别。这是参考链接:https://dev59.com/FlcO5IYBdhLWcg3w7lrq - Leo Dabus
2
@Ramis 这是不可能的 - JSONEncoderJSONDecoder 需要具体类型,而 Codable 不是具体类型(类型为 Codable? 的变量被称为 _存在类型_)。你能在这里展示一下你的使用案例吗?这个变量还可以放入什么内容? - Itai Ferber
显示剩余6条评论
3个回答

7

您的代码没问题,我们需要关注的是 Codable

Codable 是一个 typealias,不会给你泛型类型。

JSONEncoder().encode(符合 Encodable 协议的泛型)。

所以,我修改了下面的代码,希望能对您有所帮助。

protocol Codability: Codable {}

extension Codability {
    typealias T = Self
    func encode() -> Data? {
        return try? JSONEncoder().encode(self)
    }

    static func decode(data: Data) -> T? {
        return try? JSONDecoder().decode(T.self, from: data)
    }
}

struct Me: Codability
{
    let id: Int
    let name: String
}

struct You: Codability
{
    let id: Int
    let name: String
}

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        var codable: Codability
        codable = Me(id: 1, name: "Kobra")
        let data1 = codable.encode()

    codable = You(id: 2, name: "Kobra")
    let data2 = codable.encode()
}
}

你的解决方案救了我! - AlexBerd

5

我创建了与你相同的场景:

struct Me: Codable
{
    let id: Int
    let name: String
}

struct You: Codable
{
    let id: Int
    let name: String
}

class ViewController: UIViewController
{
    override func viewDidLoad()
    {
        var codable: Codable?

        codable = Me(id: 1, name: "Kobra")
        let data1 = try? JSONEncoder().encode(codable)

        codable = You(id: 2, name: "Kobra")
        let data2 = try? JSONEncoder().encode(codable)
    }
}

上面的代码没有给我任何错误。我改变的唯一事情是:
let data = try? JSONEncoder().encode(codable!)

我没有解包codable,但它仍然运行良好。


1
编译没有提供任何错误,但在执行时出现错误:致命错误:Optional<Decodable & Encodable>不符合Encodable,因为Encodable不符合自身。您必须使用具体类型来进行编码或解码。 - Ramis
4
明白了。您需要使用具体类型。 - PGDev

1
我曾经使用过这种方法,也许它对你的情况有帮助。
public protocol AbstractMessage: Codable {
  var id: Int { get } // you might add {set} as well
  var name: Int { get }
}

然后创建了一个方法:
public func sendMessage<T>(message: T) where T: AbstractMessage {
  let json = try! String(data: JSONEncoder().encode(message), encoding: .utf8)!
  ...
}

我创建了一个通用协议,并将其作为泛型类型传递给我的函数。


你确定吗?那个可行吗?我写了同样的方法,但是出现了一个错误,说“无法使用类型为'(Codable)'的参数列表调用'encode'”。 - Sanju
@Sanju,这是我目前正在开发的项目中使用的。 - guness

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接