evermeer / AlamofireJsonToObjects

An Alamofire extension which converts JSON response data into swift objects using EVReflection
Other
161 stars 28 forks source link

NSArray element failed to match the Swift Array Element type #24

Closed jamesbar2 closed 8 years ago

jamesbar2 commented 8 years ago

I'm having an issue when trying to get an array of objects inside an an object to deserialize. The output is saying fatal error: NSArray element failed to match the Swift Array Element type and then the debugger breaks on line 560 of EVReflection.swift mi = Mirror(reflecting: theValue) with the error: Thread 1: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0).

It's been able to deserialize nested objects when its not in an array, so not sure what the issue might be here. I'll paste some code below though so you can see my process.

Alamofire Request, the error happens when I ask it to print the debugDescription

Alamofire.request(.GET, "http://server.com/api/get/all", headers: getAuthenticationHeaders()).
validate().
responseArray { (response: Result<[MyPrimaryObject], NSError>) in
       if(response.isSuccess){
           print(response.debugDescription)
           success(response.value)
       }
       if(response.isFailure){
           let error : NSError = response.error!
           NSLog("API failure: \(error.debugDescription)")
           failure(error)
       }
   }

Models:

public class MyPrimaryObject : EVObject{

    public var myPrimaryObjectId : NSUUID?
    public var name : String = ""
    public var myObjectDescription: String?

    public var numberOfOccurrences : Int = 0
    public var positiveResponsePercentage : Float = 0

    public var secondaryObjects : [MySecondaryObject]?

    override public func propertyMapping() -> [(String?, String?)] {
        return [("myObjectDescription","Description")]

    }
}

public class MySecondaryObject : EVObject {
    public var mySecondaryObjectId : Int = 0
    public var dateRecorded : NSDate?
    public var rating : Int = 0
    public var userRemarks : String?
}

It also should be noted that MyPrimaryObject is parsed perfectly when the secondaryObjects are null from the API response.

I've obviously simplified, I'm happy to share the actual code with you privately. Any help would be greatly appreciated! Thanks so much!

evermeer commented 8 years ago

Hi,

It looks like this is actually an issue with the EVReflection library and not AlamofireJsonToObjects.

I have copied your 2 classes and created a unit test. See the code below. That code works.

It could be that there is a difference between the json an the model. Could you send me a sample of the json? It's OK to remove and/or alter the data.

    func testIssue24() {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyyMMdd"
        EVReflection.setDateFormatter(dateFormatter)

        let json = "{ \"positiveResponsePercentage\" : 80, \"Description\" : \"The description\", \"myPrimaryObjectId\" : \"ADSF13\", \"numberOfOccurrences\" : 2, \"name\" : \"The name\", \"secondaryObjects\" : [ { \"rating\" : 9, \"dateRecorded\" : \"20160620\", \"mySecondaryObjectId\" : 1, \"userRemarks\" : \"The remarks\" }, { \"rating\" : 8, \"dateRecorded\" : \"20160515\", \"mySecondaryObjectId\" : 2, \"userRemarks\" : \"More remarks\" }]}"
        let x = MyPrimaryObject(json: json)
        let json2 = x.toJsonString()
        print(json2)
    }
evermeer commented 8 years ago

O, I see you have an array of MyPrimaryObject objects. Then the test will be:

    func testIssue24() {
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "yyyyMMdd"
        EVReflection.setDateFormatter(dateFormatter)

        let json = "[{ \"positiveResponsePercentage\" : 80, \"Description\" : \"The description\", \"myPrimaryObjectId\" : \"ADSF13\", \"numberOfOccurrences\" : 2, \"name\" : \"The name\", \"secondaryObjects\" : [ { \"rating\" : 9, \"dateRecorded\" : \"20160620\", \"mySecondaryObjectId\" : 1, \"userRemarks\" : \"The remarks\" }, { \"rating\" : 8, \"dateRecorded\" : \"20160515\", \"mySecondaryObjectId\" : 2, \"userRemarks\" : \"More remarks\" }]}]"
        let x = [MyPrimaryObject](json: json)
        let json2 = x.toJsonString()
        print(json2)
    }
jamesbar2 commented 8 years ago

Thanks for your quick reply, here is a modified output from the server to match the example I gave you.

https://gist.github.com/jamesbar2/7695af3cc37d7f5f80edf34303a2054a

jamesbar2 commented 8 years ago

I've been testing it, I can parse the primary and secondary object separately, just not when the secondary is nested in the primary.

I've uploaded my relevant code here, with actual output from the server, you should be able to paste this in your test environment and go. https://gist.github.com/jamesbar2/c226d7b20455940c1454bc079300f58e

Here's an interesting bit as well from the debugger, so long as I'm not trying to access the vodkaHistory array, it has a dictionary where it's displaying things just fine. It's when I try to ask it to debugDescription or access any of the fields that it freaks out. image

evermeer commented 8 years ago

It took me a while, but I have found (and solved) the bug.

The issue was that when you have a sub object array the pascal casing conversion did not work for getting the correct type. because of this the dictionary was put in the array and you would get the error that you got.

The fix has been published in EVReflection 2.38.3