skip to Main Content

I’m trying to make a stocks app for college related work and ive done almost everything i need to do except getting the actual data of the stocks into my app, I’ve been trying this and researching for the past couple days but still cannot get it to work as i get the error message :

typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

any help is appreciated as this is the first ever thing i’ve made with swift/xcode

the code in my viewController:

import UIKit

class ViewController: UIViewController { 
    
    override func viewDidLoad() {
        super.viewDidLoad()
        fetchPostData { (posts) in
            for post in posts {
                print(post.datetime!)
            }
        }                
    }
    
    func fetchPostData(completionHandler: @escaping ([Post]) -> Void) {
        
        let url = URL(string: "https://api.twelvedata.com/time_series?symbol=AAPL&interval=1min&apikey=<api-key>")!
        
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            
            guard let data = data else { return }
            
            do {
                let postsData = try JSONDecoder().decode([Post].self, from: data)
                
                completionHandler(postsData)
                
            }
            catch {
                let error = error
                print(error)
            }                                                        
        }.resume()        
    }        
} 

and the other file with the variables:


struct Post: Codable {
    var datetime: Int!
    var open: Int!
    var high: String!
    var low: String!
    var close: String!
    var volume: String!
}

link to the json file: https://api.twelvedata.com/time_series?symbol=AAPL&interval=1min&apikey=0561a81a9baf4ae4bc65c7af9196f929

2

Answers


  1. The error is speaking for itself; you are trying to decode an array but the JSON is a dictionary. You need to change your decode:

    JSONDecoder().decode(Post.self, from: data)
    

    Edit after Joakim Danielson hint for completeness of the answer:

    You have also to modify your struct in order to accomodate the JSON in your response

    struct Post: Decodable {
        let meta: Meta
    }
    
    struct Meta: Decodable {
        let symbol: String
        let interval: String
        let currency: String
        let values: [Values]
        // more data here
    }
    
    struct Values: Decodable {
        // more data here
    }
    
    Login or Signup to reply.
  2. First of all, all values in Post are String, please note the double quotes in the JSON

    struct Post: Decodable {
        let datetime, open, high, low, close, volume: String
    }
    

    But the main issue is – as mentioned in the comments and Alastar’s answer and indirectly stated by the error – you are ignoring the root object. You have to decode JSON always from the top. Add this struct

    struct Root: Decodable {
        let status: String
        let values: [Post]
    }
    

    and decode

    let postsData = try JSONDecoder().decode(Root.self, from: data)
    completionHandler(postsData.values)
                
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search