【问题标题】:Swift Decode and Encode Custom TypesSwift 解码和编码自定义类型
【发布时间】:2026-01-06 07:10:02
【问题描述】:

我在用 Swift 解码和编码我的一个类时遇到了困难。我曾尝试遵循Encoding and Decoding Custom Types 文档,但没有成功。

我的班级布局如下:

public struct MapLocation: Identifiable, Codable {
    @DocumentID public var id: String?
    let originLocation: [MapLandmark]
    let destinationLocation: [MapLandmark]
    enum CodingKeys: String, CodingKey {
        case originLocation
        case destinationLocation
    }
}

import Foundation
import MapKit    
struct MapLandmark: Codable {
    let placemark: MKPlacemark
    var id: UUID {
        return UUID()
    }
    var name: String {
        self.placemark.name ?? ""
    }
    var title: String {
        self.placemark.title ?? ""
    }
    var coordinate: CLLocationCoordinate2D {
        self.placemark.coordinate
    }
}

我已尝试从上述链接添加编码和解码类,但一直出错。实施解决方案的最佳方式是什么?

编辑: 我忘了提到我得到的错误是:

“类型'MapLandmark'不符合协议'Decodable'”

“类型'MapLandmark'不符合协议'Encodable”

【问题讨论】:

  • 在寻求错误帮助时,总是,总是包含错误的文本。如果我们不知道具体是什么问题,我们将无法帮助您解决问题。
  • 把 :Codable 放在你的类名之后以符合它
  • @Caleb 抱歉,错误我已在上述评论中包含错误消息,并将很快编辑我的帖子。
  • @gcharita 这是 Firebase / Firestore
  • MKPlacemark 不符合 Codable 因此您不能(直接)在结构中使用它,因为 Codable 类型的所有属性都需要符合 Codable

标签: swift firebase google-cloud-firestore codable


【解决方案1】:

MKPlacemark 符合 NSSecureCoding。您可以只使用NSKeyedArchiverNSKeyedUnarchiver 对其进行编码/解码。 UUID 已经符合 Codable。尝试如下:

import MapKit

extension NSSecureCoding {
    func archived() throws -> Data {
        try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false)
    }
}

extension Data {
    func unarchived<T: NSSecureCoding>() throws -> T? {
        try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(self) as? T
    }
}

struct MapLandmark: Codable {
    let placemark: MKPlacemark
    let id: UUID
    func encode(to encoder: Encoder) throws {
        var unkeyedContainer = encoder.unkeyedContainer()
        try unkeyedContainer.encode(placemark.archived())
        try unkeyedContainer.encode(id)
    }
    public init(from decoder: Decoder) throws {
        var container = try decoder.unkeyedContainer()
        placemark = try container.decode(Data.self).unarchived()!
        id = try container.decode(UUID.self)
    }
}

【讨论】:

  • 谢谢利奥!这很有帮助
  • 抱歉,Leo,我有一个快速跟进的问题。如何使用 encode 函数对 MapLandmark 对象进行编码?谢谢
  • 没关系,我意识到我接近错误并使用了 MapLandmark.encode()