Я пытаюсь сохранить модель firebase по умолчанию, но кодирование/декодирование поля id не выполняется.
struct DeviceModel: Identifiable, Codable, Hashable {
@DocumentID var id: String?
var fcmToken: String
var userId: String
@ServerTimestamp var expiresOn: Timestamp?
enum CodingKeys: String, CodingKey {
case id
case fcmToken = "token"
case expiresOn = "expires_on"
case userId = "user_id"
}
init(id: String? = nil,
fcmToken: String,
userId: String,
expiresOn: Timestamp? = Timestamp()) {
self.id = id
self.fcmToken = fcmToken
self.userId = userId
self.expiresOn = expiresOn
}
}
Расширение UserDefault
extension UserDefaults {
func decode<T: Decodable>(_ type: T.Type, forKey defaultName: String) throws -> T {
// try! JSONDecoder().decode(T.self, from: data(forKey: defaultName) ?? .init())
try! Firestore.Decoder().decode(T.self, from: data(forKey: defaultName) ?? .init())
}
func encode<T: Encodable>(_ value: T, forKey defaultName: String) throws {
// try! set(JSONEncoder().encode(value), forKey: defaultName)
try! set(Firestore.Encoder().encode(value), forKey: defaultName)
}
}
Сначала я попытался использовать JSONEncoder и получил сообщение об ошибке, говорящее о том, что @DocumentID должен быть закодирован/декодирован с использованием кодировщика/декодера firestore.
Fatal error: 'try!' expression unexpectedly raised an error:
FirebaseFirestoreSwift.FirestoreEncodingError.encodingIsNotSupported("DocumentID values can only be encoded with Firestore.Encoder")
После этого я использую их, как указано выше, но теперь я получаю
2023-04-18 10:52:19.298750+0300 Voxic[49960:1461668] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attempt to insert non-property list object {
"expires_on" = "<FIRTimestamp: seconds=1685555885 nanoseconds=220984000>";
token = "<token>";
"user_id" = 41giBVERER34QNPFZmlB3;
} for key localDeviceKey'
Одна вещь, которую я нахожу странной, заключается в том, что user_id
не печатается в виде строки в приведенной выше ошибке. Хотя, возможно, это просто проблема с печатью.
Есть предположения? Спасибо
@ Джатин, спасибо, но это не тот сценарий. Я уже использую DocumentID в своем проекте. и кодирование/декодирование в/из firebase работает.
Попробуйте использовать пользовательскую функцию кодирования и пользовательскую функцию инициализации (от :)
struct DeviceModel: Identifiable, Codable, Hashable {
@DocumentID var id: String?
var fcmToken: String
var userId: String
@ServerTimestamp var expiresOn: Timestamp?
enum CodingKeys: String, CodingKey {
case id
case fcmToken = "token"
case expiresOn = "expires_on"
case userId = "user_id"
}
init(id: String? = nil,
fcmToken: String,
userId: String,
expiresOn: Timestamp? = Timestamp()) {
self.id = id
self.fcmToken = fcmToken
self.userId = userId
self.expiresOn = expiresOn
}
// Custom init(from:) function that decodes the id property using the Firestore.Decoder
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
fcmToken = try container.decode(String.self, forKey: .fcmToken)
userId = try container.decode(String.self, forKey: .userId)
expiresOn = try container.decode(Timestamp?.self, forKey: .expiresOn)
// Decode the DocumentID property using the Firestore.Decoder
if let idContainer = try? decoder.container(keyedBy: CodingKeys.self),
let id = try? idContainer.decode(String.self, forKey: .id) {
self.id = id
}
}
// Custom encode function that encodes the DocumentID property using the Firestore.Encoder
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(fcmToken, forKey: .fcmToken)
try container.encode(userId, forKey: .userId)
try container.encode(expiresOn, forKey: .expiresOn)
// Encode the DocumentID property using the Firestore.Encoder
if let id = id {
let firestoreEncoder = Firestore.Encoder()
let something = try firestoreEncoder.encode(["id":id])
if let mapId = something["id"] as? String {
try container.encode(mapId, forKey: .id)
}
}
}
}
я нашел похожий вопрос, пожалуйста, проверьте решение здесь: stackoverflow.com/a/61432255/16322682