M1X
M1X

Reputation: 5354

Decodable DocumentReference in Swift

I have a custom model in swift and it has a property of type DocumentReference I'm getting some data from a cloud function and then I'm trying to decode it back to my model.

DocumentReference doesn't conform to Decodable by itself so I'm trying to write an extension for it.

I can not make it work since I keep getting this error:

Initializer requirement 'init(from:)' can only be satisfied by a 'required' initializer in the definition of non-final class 'DocumentReference'

Any idea how to make this work?

My extension:

import Firebase

extension DocumentReference: Decodable {
    public convenience init(from decoder: Decoder) throws {
        //
    }
}

Existing model:

struct Notification: Identifiable, CollectionProtocol, DocumentProtocol {
    var id = UUID()

    var documentReference: DocumentReference
    var receiverID: String
    var type: String
    var createdAt: Date
    var requestReference: DocumentReference?
    var request: Request?

    init(document: DocumentSnapshot) {
        self.documentReference = document.reference
        self.requestReference = document["requestReference"] as? DocumentReference ?? Firestore.firestore().document("")
        self.receiverID = document["receiverID"] as? String ?? ""
        self.type = document["type"] as? String ?? ""
        self.createdAt = (document["createdAt"] as? Timestamp)?.dateValue() ?? Date()
    }
}

Upvotes: 2

Views: 1270

Answers (2)

Joakim Danielson
Joakim Danielson

Reputation: 51891

The class DocumentReference is not final which means that it could possibly be sub-classed but without the sub class conforming to Codable. So this would leave to an unknown state if init(from decoder: Decoder) in your extension was called.

One workaround could be to create a wrapper struct with its own init(from decoder: Decoder) and then do your decoding of DocumentReference there.

Example:

struct Wrapped: Decodable {
    let docRef: DocumentReference

    public init(from decoder: Decoder) throws {
        let container = try decoder....

        // add the decoding code here for DocumentReference
    }
}

Upvotes: 1

slushy
slushy

Reputation: 12385

NS_SWIFT_NAME(DocumentReference)
@interface FIRDocumentReference : NSObject

/** :nodoc: */
- (instancetype)init
    __attribute__((unavailable("FIRDocumentReference cannot be created directly.")));

DocumentReference (FIRDocumentReference) cannot be instantiated directly; it has no available initializers. To implement the required init, you'd have to do that in the declaration of the class itself.

If you want to conveniently instantiate custom objects from Firestore data, consider a failable initializer that takes a [String: Any] argument. If you just want to encode/decode the reference itself, consider encoding/decoding the String value of the location itself (the collection and document names) and then using that to reconstruct the DocumentReference.

Upvotes: 1

Related Questions