Search code examples
jsonswiftrestalamofireswifty-json

Unable to parse Json properly with SwiftyJson


I have the folllowing Json response:

 `       [Body]:
    {"id":"cmpl-6Z45N6vfd2312vdfqyYPb8aDRVe9Nft7vfnpoEsL","object":"text_completion","created":16738vfv15205,"model":"text-davinci-003","choices":[{"text":"\n1. Full Stack Developer\n2. Project Engineering Intern\n3. AI Programmer\n4. Systems Trade Studies Engineer\n5. BLE Technology Developer\n6. macOS Menu Bar App Developer\n7. Mobile App Developer\n8. Research Engineer\n9. Writing and Design Lab Researcher","index":0,"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":726,"completion_tokens":60,"total_tokens":786}}`

And I'm using SwiftyJson and Alamofire to parse the Json using the following code:

`     AF.request(...).responseJSON { response in
                
                print("response: \(response)")
                
                
                switch response.result {
                case .success(_):
                    if let JSON = response.value as! [[String : Any]]?{
                               print("JSON: \(JSON)")
                        let dic = JSON[0] as [String:AnyObject]?
                               print("TitularEmail : ",dic?["choices"])
                           }
                       break

                   case .failure(_):
                       print("There is an error")
                       break
               }
        }`

But it keeps breaking and I keep getting the error 'Thread 1: signal SIGABRT' at 'if let JSON = response.value as! [[String : Any]]?{'

Does anyone know what could've gone wrong? I've read through quite some threads but I can't seem to figure this out. Any info shall be appreciated.


Solution

  • Using the built-in Decodable would be a much better alternative. At the risk of slightly wandering from the original SwiftyJSON question, I highly recommend using Decodable to parse JSON (see also Encodable for writing and Codable for the combination of both). Here's an example of a very basic use of Decodable. Supposed you want to parse the following:

    {
    "name": "New York City",
    "mayor": "Eric Adams",
    "population": 8468000
    }
    

    You can parse it super easily with Decodable:

    struct City: Decodable {
        let name:String
        let mayor:String
        let population:Int
    }
    

    You can create an instance of City in this example by taking the JSON– assume it is stored in a variable called jsonData– and simply doing the following:

    let NYC = try JSONDecoder().decode(City.self, from: jsonData)
    

    You should highly consider this route because it can get a lot done with very little work.

    You can also use JSONSerialization if you don't want to use the aforementioned ways of parsing it. Here is a simple tutorial on how to do that.

    In your case, you can implement Decodable to solve your problem like this:

    var json = try! Data(contentsOf: URL(fileURLWithPath: "PATH TO FILE WITH EXAMPLE JSON TEXT"))
    
    
    struct FirstStruct:Decodable {
        let id:String
        let object:String
        let created:String //I'm calling this a string because, despite the lack of quotes, it has letters in it and cannot be an Int. You could also do something like Int? so it can fail safely if there are letters. I am adding quotes to the example text make it work.
        let model:String
        let choices:[SecondStruct]
        let usage:ThirdStruct
        
    }
    
    struct SecondStruct:Decodable {
        let text:String
        let index:Int
        let logprobs:String? //idk what type this is supposed to be from the text given
        let finish_reason:String
    }
    
    struct ThirdStruct:Decodable {
        let prompt_tokens:Int
        let completion_tokens:Int
        let total_tokens:Int
    }
    
    var test = try! JSONDecoder().decode(FirstStruct.self, from: json)
    
    print(test.id) 
    print(test.usage.total_tokens) //these two examples show it clearly works here
    

    Obviously, have a bit more care with error handling, try! was just easier for the example.