Быстрое декодирование и кодирование пользовательских типов

#swift #firebase #google-cloud-firestore #codable

#swift #firebase #google-облако-firestore #кодируемый

Вопрос:

У меня возникли трудности с декодированием и кодированием одного из моих классов в Swift. Я попытался следовать документации по кодированию и декодированию пользовательских типов, но безуспешно.

Мой макет класса выглядит следующим образом:

 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»

Комментарии:

1. При запросе помощи с ошибками всегда, всегда указывайте текст ошибок. Мы не сможем помочь вам решить проблему, если мы не знаем, в чем конкретно она заключается.

2. поместите:Codable после имени вашего класса, чтобы оно соответствовало

3. @Caleb Извините за ошибку, я включил сообщение об ошибке в комментарий выше и вскоре отредактирую свой пост.

4. @gcharita Это Firebase / Firestore

5. MKPlacemark не соответствует Codable, поэтому вы не можете использовать его (напрямую) в своей структуре, поскольку все свойства кодируемого типа должны соответствовать Codable

Ответ №1:

MKPlacemark соответствует NSSecureCoding . Вы можете просто использовать NSKeyedArchiver и NSKeyedUnarchiver для его кодирования / декодирования. 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)
    }
}
  

Комментарии:

1. Спасибо, Лео! Это очень помогло

2. Извините, Лео, у меня быстрый последующий вопрос. Как мне использовать функцию encode для кодирования объекта MapLandmark? Спасибо

3. Неважно, я понял, что неправильно подхожу к этому, и использовал MapLandmark.encode()