Home > OS >  The data couldn’t be read in Swift
The data couldn’t be read in Swift

Time:02-04

I am new to swift . I am trying to retrieve the data form api. The data in json format. Here is the data in json format.

    {
        "photos": [
            {
                "id": 424926,
                "sol": 1000,
                "camera": {
                    "id": 22,
                    "name": "MAST",
                    "rover_id": 5,
                    "full_name": "Mast Camera"
                },
                "img_src": "http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631200305217E01_DXXX.jpg",
                "earth_date": "2015-05-30",
                "rover": {
                    "id": 5,
                    "name": "Curiosity",
                    "landing_date": "2012-08-06",
                    "launch_date": "2011-11-26",
                    "status": "active"
                }
            }
    ]

}

Here is the online Json viewer .

Screenshot

NetworkMnager code .


    class NetworkManager{
        
        
        func fetchData(completion: @escaping ([Rover]) -> Void) {
           
            
            if let url = URL(string: "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=1000&api_key=Mykey") {
                
                URLSession.shared.dataTask(with: url) { data, urlResponse, error in
                    
                    if let data = data {
                        
                        do {
                            let result = try JSONDecoder().decode([Rover].self, from: data)
                            completion(result)
                        } catch let error {
                            print(error.localizedDescription)
                        }
                        
                        
                    }
                    
                }
                .resume()
            }
            
            
        }
    }
    

I am trying to display the data id and status from rover (struct ) into simulator when i try to run the data , I am getting following error into console window of the xcode.The data couldn’t be read because it isn’t in the correct format. I am sure there is somethings wrong with the struct. Here is the struct code .

        import Foundation

// MARK: - Welcome
struct Welcome: Codable {
    let photos: [Photo]
}

// MARK: - Photo
struct Photo: Codable {
    let id, sol: Int
    let camera: Camera
    let imgSrc: String
    let earthDate: String
    let rover: Rover

    enum CodingKeys: String, CodingKey {
        case id, sol, camera
        case imgSrc = "img_src"
        case earthDate = "earth_date"
        case rover
    }
}

// MARK: - Camera
struct Camera: Codable {
    let id: Int
    let name: String
    let roverID: Int
    let fullName: String

    enum CodingKeys: String, CodingKey {
        case id, name
        case roverID = "rover_id"
        case fullName = "full_name"
    }
}

// MARK: - Rover
struct Rover: Codable {
    let id: Int
    let name, landingDate, launchDate, status: String

    enum CodingKeys: String, CodingKey {
        case id, name
        case landingDate = "landing_date"
        case launchDate = "launch_date"
        case status
    }
}

Table view controller code .

class ViewController: UIViewController {
    
    @IBOutlet weak var tableView: UITableView!
    private var posts = [Rover]()
    private let networkManager = NetworkManager()
    private var rowSelected = 0
  
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        setUpUI ()
        fetchData()
    }
    
   /* override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showDetail" {
            let destination = segue.destination as? SecondViewController
            destination?.posts = posts
            destination?.rowSelected = rowSelected
        }
    }*/
    
    private func setUpUI () {
        tableView.dataSource = self
        tableView.delegate = self
    }
    
    private func fetchData() {
        networkManager.fetchData { [weak self] array in
            self?.posts = array
            
            DispatchQueue.main.async {
                self?.tableView.reloadData()
            }
            
        }
    }
}
extension ViewController: UITableViewDelegate {
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        rowSelected = indexPath.row
        performSegue(withIdentifier: "cell", sender: nil)
    }
}

extension ViewController: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let row = indexPath.row
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let post = posts[row]
        cell.textLabel?.text = String(post.id)
        cell.detailTextLabel?.text = post.status
        return cell
        
    }
    
}

CodePudding user response:

try using this example code to decode your json data: (note I do not have a api_key, so I cannot test this).

EDIT-1:

here is the code I used for testing (sorry it is using SwiftUI), from this you should be able to get your data decoded. Works for me.

class NetworkManager {
    
    func fetchData(completion: @escaping ([Photo]) -> Void) { // <-- here
        if let url = URL(string: "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=1000&api_key=DEMO_KEY") {
            URLSession.shared.dataTask(with: url) { data, urlResponse, error in
                if let data = data {
                    do {
                        let result = try JSONDecoder().decode(NASAResponse.self, from: data) // <-- here
                        completion(result.photos)
                    } catch let error {
                        print(error.localizedDescription)
                    }
                }
            }
            .resume()
        }
    }
}

struct ContentView: View {
    let networkManager = NetworkManager()
    
    @State var photos: [Photo] = []
    
    var body: some View {
        List (photos) { photo in
          HStack {
            Text(String(photo.rover.id))
            Text(photo.rover.status.rawValue)
          }
        }
        .onAppear {
            networkManager.fetchData { thePhotos in
                photos = thePhotos
            }
        }
    }
    
}


struct NASAResponse: Codable {
    let photos: [Photo]
}

// MARK: - Photo
struct Photo: Identifiable, Codable {
    let sol, id: Int
    let earthDate: String
    let camera: Camera
    let imgSrc: String
    let rover: Rover

    enum CodingKeys: String, CodingKey {
        case sol, id
        case earthDate = "earth_date"
        case camera
        case imgSrc = "img_src"
        case rover
    }
}

// MARK: - Camera
struct Camera: Identifiable, Codable {
    let id, roverID: Int
    let fullName: FullName
    let name: CameraName

    enum CodingKeys: String, CodingKey {
        case id
        case roverID = "rover_id"
        case fullName = "full_name"
        case name
    }
}

enum FullName: String, Codable {
    case chemistryAndCameraComplex = "Chemistry and Camera Complex"
    case frontHazardAvoidanceCamera = "Front Hazard Avoidance Camera"
    case mastCamera = "Mast Camera"
    case navigationCamera = "Navigation Camera"
    case rearHazardAvoidanceCamera = "Rear Hazard Avoidance Camera"
}

enum CameraName: String, Codable {
    case chemcam = "CHEMCAM"
    case fhaz = "FHAZ"
    case mast = "MAST"
    case navcam = "NAVCAM"
    case rhaz = "RHAZ"
}

// MARK: - Rover
struct Rover: Identifiable, Codable {
    let status: Status
    let id: Int
    let landingDate, launchDate: String
    let name: RoverName

    enum CodingKeys: String, CodingKey {
        case status, id
        case landingDate = "landing_date"
        case launchDate = "launch_date"
        case name
    }
}

enum RoverName: String, Codable {
    case curiosity = "Curiosity"
}

enum Status: String, Codable {
    case active = "active"
}

EDIT-2:

To get all the "rover" into the post var, in your class ViewController: UIViewController, do this for your tableView :

 private func fetchData() {
        networkManager.fetchData { thePhotos in
            self.posts = thePhotos.map { $0.rover }
            DispatchQueue.main.async {
                self?.tableView.reloadData()
            }
        }
    }
   
  •  Tags:  
  • Related