Fatal Error: Nsarray Element Failed to Match the Swift Array Element Type

getting fatal error: NSArray element failed to match the Swift Array Element type when trying to read values from an array of class objects

OK, This was a beginner problem that might help others.

The scenario: I have a complex JSON: root is object, for each key in the object there is a numeric value (deferent key but the value has the same structure) and the value is the Category Object!
For each category there are many key/Value pairs and one of them is the the Books KEY and the value is array or objects, each one is a book.

The problem: when i deserialised the JSON, i parsed the categories with an array of books, but the books as mentioned in the comments weren't really book instances more array of NSDictionary objects.

So after deserialising the Category i have to add an init method in The Book class to get an NSDictionary and parse it into a Book Object.

After that for each category i have to go over the the NSArray of books and for each one to create an Object go Book and return an Array of Books.

That did the trick and now every thing is working:

API:

// Getting NSArray of NSDictionary that represnets books and convert it into Books array
static func getBooksFromArr(booksArr: NSArray) -> [Book] {
var books = [Book]()

for book in booksArr {
let thisBook = Book(bookDict: book as! NSDictionary)
books.append(thisBook)
print(book)
}

return books
}

// Parsing the category object
private static func CategoryFromJSONObject(json: [String: AnyObject]) -> Category? {
guard let
id = json["Id"] as? Int,
name = json["Name"] as? String,
booksArr = json["Books"] as? NSArray else {
return nil
}

let books = getBooksFromArr(booksArr)

return Category(name: name, id: id, books: books)
}

Book Class:

init(bookDict: NSDictionary){
self.name = (bookDict["Name"] ?? "") as! String
self.id = (bookDict["Id"] ?? -1) as! Int
self.categoryId = (bookDict["CategoryId"] ?? -1) as! Int
self.bookAuthor = (bookDict["BookAuthor"] ?? "") as! String
self.level1Name = (bookDict["Level1Name"] ?? "") as! String
self.level2Name = (bookDict["Level2Name"] ?? "") as! String
self.level3Name = (bookDict["Level3Name"] ?? "") as! String
self.level4Name = (bookDict["Level4Name"] ?? "") as! String
self.levels = (bookDict["Levels"] ?? -1) as! Int
self.orderKey = (bookDict["OrderKey"] ?? -1) as! Int
self.viewCount = (bookDict["ViewCount"] ?? -1) as! Int
self.viewLevel = (bookDict["ViewLevel"] ?? -1) as! Int
self.chapters = (bookDict["Chapters"] ?? []) as! [AnyObject]
}

Now i will have to do the same for the chapters if i want to compose books to hold the chapters.

I didn't write the REST API so don't ask me why they did it as so, but now every thing is working and that is the point of it.

How to Solve NSArray element failed to match the Swift Array Element type in GooglePlaces API findAutocompletePredictions?

So I have solved this problem, but I did not fix anything, since it is from the GooglePlaces framework.

In order to solve this, simply make results as results:[Any]? at the callback.

Then, at guard let, safely convert it to [GMSAutocompletePrediction].

Here is the complete code

func getGoogleWayPoint(text: String) -> Promise<[GoogleWayPoint]> {
return Promise<[GoogleWayPoint]> { resolver in
if text.isEmpty {
resolver.fulfill([])
return
}
placesClient.findAutocompletePredictions(fromQuery: text, filter: filter, sessionToken: sessionToken) { (results: [Any]?, error) in
if let error = error {
dprint(error.localizedDescription)
resolver.fulfill([])
return
}

guard let finalResults = results as? [GMSAutocompletePrediction] else {
dprint("can't found results")
resolver.fulfill([])
return
}
let searchResultsWayPoints = finalResults.map {
GoogleWayPoint(id: $0.placeID, address: $0.attributedFullText.string)
}
resolver.fulfill(searchResultsWayPoints)
}
}
}

Fatal error NSArray element failed to match the Swift Array Element type after xcode10.1 update

The error message tells you that items was bridged from an NSArray (which does not enforce typing of its elements) but when Swift tried to retrieve an element, it did not find an instance of mainPageJobObj, which is what you said they array contained.

From the debug screen shot you can see that the items array actually contains instances of NSMutableDictionary.

A quick fix is to use the appropriate declaration of items:

var items:[String:Any] = slider.mainPageObj.items!
let oneItem = items[index]
let name = oneItem["name"]

A much better fix is to use Swift types from the start; If the data from your server is being returned in JSON format then use Codable to create Swift Struct or Class instances.

NSArray element failed to match the Swift Array Element type Expected JSONPaymentCard but found __NSDictionaryI

In the README file of JSONModel, there is a note saying:

@interface OrderModel : JSONModel
@property (nonatomic) NSInteger orderId;
@property (nonatomic) float totalPrice;
@property (nonatomic) NSArray <ProductModel> *products;
@end

Note: the angle brackets after NSArray contain a protocol. This is not the same as the Objective-C generics system. They are not mutually exclusive, but for JSONModel to work, the protocol must be in place.

JSONModel uses the type in the <> to determine the specific type of array to deserialise, and it is specifically noted that you can't replace this with Objective-C generics system ("not the same"!), so if you did:

@property (strong, nonatomic) NSArray<JSONPaymentCard *> *userCards;

You are not telling JSONModel what model type the array should contain, so it just dumbly deserialises NSDictionarys. You can do both Objective-C generics, and tell JSONModel the type of the array, as demonstrated by the next code snippet in the README.

@property (strong, nonatomic) NSArray<JSONPaymentCard *> <JSONPaymentCard> *userCards;

NSArray element failed to match the Swift Array Element type Expected NSMutableArray but found __NSDictionaryI:

The solution i found is when i pass the array i convert it to NSData so the swift can read it using the following code:

NSData *data1 = [NSKeyedArchiver archivedDataWithRootObject:self.mSelectedBills];

and then in the swift ViewController i use this code to read it:

@objc func setSelectedBillsData(selectedBillsData: NSData) {
self.mData = selectedBillsData
do {
if let loadedStrings = try NSKeyedUnarchiver.unarchiveObject(with: selectedBillsData as Data) as? [[String:AnyObject]] {
print(loadedStrings)
}
} catch {
print("erreur.")
}
}

Thread 1: Fatal error: NSArray element failed to match the Swift Array Element type

Okay, I've found the reason of this error.
My messages array was being appended in another block of code with SBDUserMessages, and I wasn't cast them as exact type of message (as! SBDUserMessage).

The debugging really helped a lot. At some point I decided to call before the self.messages.append(newMessage) (where the crash actually occured), the messaged.removeAll(), and after that I've found out that everything works fine.

Firebase iOS Swift fatal error: NSArray element failed to match the Swift Array Element type

The issue is in your ChitObject class, specifially here:

bidders = snapshotValue["bidders"] as! [Bidder]

You would need to create an array of Bidders and assign that into bidders variable. Loop through the array you get from snapshotValue["bidders"] and create Bidders object for every value and assign that into a Swift array.

I have not workded with Firebase but something like this may work:

init(snapshot: FIRDataSnapshot) {
let snapshotValue = snapshot.value as! [String: AnyObject]
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
if let biddersArray = snapshotValue["bidders"] as? [[String:Any]] {
bidders = biddersArray.flatMap{Bidder(dict:$0)}
}
ref = snapshot.ref
}

EDITED:

class Bidder {

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

convenience init?(dict:[String:Any]) {
guard let bidderId = dict["bidderId"] as? Int, let bidderName = dict["bidderName"] as? String, let bidderEmail = dict["bidderEmail"] as? String, let bidderPhone = dict["bidderPhone"] as? String, let modeOfPayment = dict["paymentType"] as? Int, let bidderBankName = dict["bankName"] as? String, let bidderBankAcno = dict["bankAccNumber"] as? String, let bidderIfscCode = dict["bankIFSC"] as? String else {
return nil
}
self.init(bidderId: bidderId, bidderName: bidderName, bidderEmail: bidderEmail, bidderPhone: bidderPhone, modeOfPayment: modeOfPayment, bidderBankName: bidderBankName, bidderBankAcno: bidderBankAcno, bidderIfscCode: bidderIfscCode, paymentArray: [[]], chitrefArray: [])
}

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 as Any,
"chitrefArray" : chitrefArray as Any
]
}

}


Related Topics



Leave a reply



Submit