firebase-ios-sdk: Crash when trying to `updateData`/`setData` for individual fields.

[REQUIRED] Step 1: Describe your environment

  • Xcode version: 13.2.1 (13C100)
  • Firebase SDK version: 8.14.0
  • Installation method: Swift Package Manager
  • Firebase Component: Firestore
  • Target platform(s): iOS

[REQUIRED] Step 2: Describe the problem

Steps to reproduce:

The IOS Application crashes when trying im trying to use asynchronously (didn’t tested it synchronously) one of the following:

  1. ... .updateData([ "deviceModels": FieldValue.arrayRemove(oldDeviceModels) })

  2. ... .updateData([ "deviceModels": FieldValue.arrayUnion(newDeviceModels) })

  3. ... .updateData([ "deviceModels": newDeviceModels })

  4. ... .setData([ "deviceModels": newDeviceModels })

The only error im getting is Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT). But when going trough the stack trace I can see that it was caused by the function .updateData([]).

However FieldValue.delete() works just fine, as well as overwriting the hole document instead of just the field (via .setData(from: categoryModel).

I hope this is not an issue on my side, but if so im sorry to bother you. If you need more information don’t hesitate to ask. Thank you for your time!

Relevant Code:

Models
import Foundation
import FirebaseFirestoreSwift

struct CategoryModel: Identifiable, Codable {
    @DocumentID var id: String?
    
    let name: String
    var deviceModels: [DeviceModel]
}

struct DeviceModel: Identifiable, Codable {
    let id: String
    
    let name: String
    let imageURL: URL
    let model: String
    let brand: String
    let purchaseDate: Date
    let purchasePrice: Double
    let warrantyPeriod: Date
    let imageAssets: [URL]
    let pdfAssets: [URL]
    let repairModels: [RepairModel]
}

struct RepairModel: Identifiable, Codable {
    let id: String
    
    let name: String
    let repairDate: Date
    let repairPrice: Double
    let warrantyPeriod: Date
}
FirestoreViewModel
public func arrayRemove(document: String, field: String, array: [DeviceModel]) async {
    //self.actionState = .isLoading(action: .arrayRemove) - Not Important
    do {
        try await self.db.collection(self.collection).document(document).updateData([
            field: FieldValue.arrayRemove(array)
        ])
        //self.actionState = .none  - Not Important
    } catch {
        //self.actionState = .error(error: error)  - Not Important
    }
}
View (SwiftUI)
internal let categoryModel: CategoryModel
@EnvironmentObject private var firestoreViewModel: FirestoreViewModel



// - Some view
    .onDelete { offsets in
        let deviceModelsToDelete = offsets.map { self.categoryModel.deviceModels[$0] }
        Task.detached {
            await self.firestoreViewModel.arrayRemove(document: self.categoryModel.id!, field: "deviceModels", array: deviceModelsToDelete)
        }
    }

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 21 (11 by maintainers)

Most upvoted comments

@wu-hui I tested it and your workaround indeed works perfectly. Here is the valid swift code in case someone else is having the same issue:

FieldValue.arrayRemove(array.compactMap({ try? Firestore.Encoder().encode($0) }))

I hope this issue gets fixed soon, and please ask if you need further information, or something else from me 😃

Thanks Morgan, this is probably less a bug more a limitation, see below.

@lucaszischka The problem here is that Firestore’s Codable implementation does not support directly using codables as fields. They are only meant to be used as documents.

If you intend to use them as fields, they need to be wrapped around another codable, and this only works with setData.

To set an individual field using a codable however, you need to explicitly convert the codable to a Dictionary like this try Firestore.Encoder().encode(codeableInstance), then pass the returned dictionary to arrayRemove and similar.

OTOH, we will do below from our side:

  • Improve logging to tell users what we expect.
  • Look into whether we should support codables as fields.

You are right, I lost the context and closed it.