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 .
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()
}
}
}

