InvalidFirebaseData Swift 3 Can only store objects of type NSNumber, NSString, NSDictionary, and NSArray.'

I am trying to integrate Firebase to my app and want to store data in the below format.

"chits": {
"Chit-1": {
  "Bidders": [
    {
      "bankAccNumber": "5555566966",
      "bankIFSC": "GFHJJHHJ",
      "bankName": "55666",
      "bidderEmail": "desi@venkat.co.in",
      "bidderId": "Bidder-1",
      "bidderName": "Venkat Desi",
      "bidderPhone": "9999999999",
      "checked": false,
      "paymentType": 66555
    },
    {
      "bankAccNumber": "5555566966",
      "bankIFSC": "GFHJJHHJ",
      "bankName": "55666",
      "bidderEmail": "desi@venkat.co.in",
      "bidderId": "Bidder-2",
      "bidderName": "Venkat Desi",
      "bidderPhone": "9999999999",
      "checked": false,
      "paymentType": 66555
    },
    {
      "bankAccNumber": "5555566966",
      "bankIFSC": "GFHJJHHJ",
      "bankName": "55666",
      "bidderEmail": "desi@venkat.co.in",
      "bidderId": "Bidder-3",
      "bidderName": "Venkat Desi",
      "bidderPhone": "9999999999",
      "checked": false,
      "paymentType": 66555
    }
  ],
  "chitId": "Chit-1",
  "chitName": "ABC1",
  "chitTotalValue": 240000,
  "endDate": "11/10/2018",
  "monthlyShare": 1000,
  "startDate": "11/10/2017",
  "totalMonths": 12
},
"Chit-2": {
  "bidderIds": [
    {
      "bidderId": "0",
      "bidderName": "Rajesh Challuri",
      "bidderPhone": "3333333333",
      "checked": true,
      "paymentType": 0
    },
    {
      "bidderId": "0",
      "bidderName": "Govinda Bhonsle",
      "bidderPhone": "9999999999",
      "checked": true,
      "paymentType": 0
    }
  ],
  "chitId": "Chit-2",
  "chitName": "ABC2",
  "chitTotalValue": 100000,
  "endDate": "12/10/2018",
  "monthlyShare": 8000,
  "startDate": "12/10/2017",
  "totalMonths": 12
},
"Chit-3": {
  "bidderIds": [
    {
      "bidderId": "0",
      "bidderName": "Rajesh Challuri",
      "bidderPhone": "3333333333",
      "checked": true,
      "paymentType": 0
    },
    {
      "bidderId": "0",
      "bidderName": "Govinda Bhonsle",
      "bidderPhone": "9999999999",
      "checked": true,
      "paymentType": 0
    }
  ],
  "chitId": "Chit-3",
  "chitName": "ABC3",
  "chitTotalValue": 200000,
  "endDate": "13/10/2018",
  "monthlyShare": 2000,
  "startDate": "13/10/2017",
  "totalMonths": 12
}}}

I am successfully able to store Bidder data which is name,email,phone, account details etc. However, i also need to store Chit data as well. Below is the code for both the classes.

Bidder.swift

class Bidder {

let bidderId: Int
let bidderName: String
let bidderEmail: String
let bidderPhone : String
let modeOfPayment: Int
let bidderBankName: String
let bidderBankAcno: String
let bidderIfscCode: String
let paymentArray :  [[String:String]]?
let chitrefArray : [String]?
let ref: FIRDatabaseReference?

init(bidderId: Int, bidderName: String,bidderEmail: String, bidderPhone: String, modeOfPayment: Int, bidderBankName: String, bidderBankAcno: String, bidderIfscCode: String,paymentArray:  [[String:String]], chitrefArray: [String]) {
    self.bidderId = bidderId
    self.bidderName = bidderName
    self.bidderEmail = bidderEmail
    self.bidderPhone = bidderPhone
    self.modeOfPayment = modeOfPayment
    self.bidderBankName = bidderBankName
    self.bidderBankAcno = bidderBankAcno
    self.bidderIfscCode = bidderIfscCode
    self.paymentArray = paymentArray
    self.chitrefArray = chitrefArray
    self.ref = nil
}

init(snapshot: FIRDataSnapshot) {
    let snapshotValue = snapshot.value as! [String: AnyObject]
    bidderId = snapshotValue["bidderId"] as! Int
    bidderName = snapshotValue["bidderName"] as! String
    bidderEmail = snapshotValue["bidderEmail"] as! String
    bidderPhone = snapshotValue["bidderPhone"] as! String
    modeOfPayment = snapshotValue["modeOfPayment"] as! Int
    bidderBankName = snapshotValue["bidderBankName"] as! String
    bidderBankAcno = snapshotValue["bidderBankAcno"] as! String
    bidderIfscCode = snapshotValue["bidderIfscCode"] as! String
    paymentArray = snapshotValue["paymentArray"] as? [[String:String]]
    chitrefArray = snapshotValue["chitrefArray"] as? [String]
    ref = snapshot.ref
}

func toAnyObject() -> Any {
    return [
        "bidderId" : bidderId,
        "bidderName" : bidderName,
        "bidderEmail": bidderEmail,
        "bidderPhone": bidderPhone,
        "modeOfPayment": modeOfPayment,
        "bidderBankName":bidderBankName,
        "bidderBankAcno": bidderBankAcno,
        "bidderIfscCode":bidderIfscCode,
        "paymentArray": paymentArray!,
        "chitrefArray" : chitrefArray!
    ]
}}

Chit.swift

struct ChitObject {

var chitId : Int
var chitName: String
var startDate: String
var endDate : String
var chitTotalAmt: Int
var chitTotalMonths: Int
var bidders: [Bidder]
var ref: FIRDatabaseReference?

init(chitId: Int,chitName: String, startDate: String, endDate: String, chitTotalAmt: Int, chitTotalMonths: Int, bidders: [Bidder]) {
    self.chitId = chitId
    self.chitName = chitName
    self.startDate = startDate
    self.endDate = endDate
    self.chitTotalAmt = chitTotalAmt
    self.chitTotalMonths = chitTotalMonths
    self.bidders = bidders 
    self.ref = nil
}

init(snapshot: FIRDataSnapshot) {
    let snapshotValue = snapshot.value as! [String: Any]
    chitId = snapshotValue["chitId"] as! Int
    chitName = snapshotValue["chitName"] as! String
    startDate = snapshotValue["startDate"] as! String
    endDate = snapshotValue["endDate"] as! String
    chitTotalAmt = snapshotValue["chitTotalAmt"] as! Int
    chitTotalMonths = snapshotValue["chitTotalMonths"] as! Int
    bidders = snapshotValue["bidders"] as! [Bidder]
    ref = snapshot.ref
}

func toAnyObject() -> Dictionary<String, Any>
{
    return [
        "chitId" : chitId,
        "chitName": chitName,
        "startDate": startDate,
        "endDate": endDate,
        "chitTotalAmt":chitTotalAmt,
        "chitTotalMonths": chitTotalMonths,
        "bidders":bidders
    ] 
}}

ViewController.swift

let chitItem = ChitObject(chitId: self.chitId, chitName: chitName.text!, startDate: startDate.text!, endDate: endDate.text!, chitTotalAmt: Int(totalAmount.text!)!, chitTotalMonths:
            Int(totalMonths.text!)!, bidders: biddersArray)
        let chitItemRef = ChitUtils.chitRef.child((chitName.text?.lowercased())!) // Crashes here at this point. 
        chitItemRef.setValue(chitItem.toAnyObject(), withCompletionBlock: { erorr , dataRef in
            if erorr != nil
            {
                let _ = self.navigationController?.popViewController(animated: true)
            }
        })
        chitItemRef.setValue(chitItem.toAnyObject())

Output : *** Terminating app due to uncaught exception 'InvalidFirebaseData', reason: '(setValue:withCompletionBlock:) Cannot store object of type _SwiftValue at bidders.0. Can only store objects of type NSNumber, NSString, NSDictionary, and NSArray.'

1 answer

  • answered 2017-10-11 10:04 Mike Atkins-Spelling

    You are trying to set an array of Bidder objects in firebase:

    In your ChitObject:

    var bidders: [Bidder]
    

    toAnyObject() method:

    "bidders":bidders
    

    Firebase will not know what this is and is expecting NSNumber, NSString, NSDictionary, or NSArray. as per the error message. (It is an Array of your own custom objects).

    Try mapping your array of bidders into an array of bidders.toAnyClass() so that they all use the Firebase primitive types.