-3

I am running low on energy and time complete this project now, I have done everything I can to learn and understand and implement a solution with no success, I would really like some help with this. Anyone got any ideas for implementing a solution?

I am really struggling to parse a json file into my iOS app in Swift. I have a JSON output from an SQL db. I think the formatting is wrong and the data headers are a bit ambiguous but my developer who I hired to create the process is happy with the output. Link below.

So in the last 3 days I have read all of the Apple Developer materials on parsing JSON, also watched numerous tutorials which all cover pretty much the same data, and I don't know how much I have read and converted into actual projects which have all failed. I am really needing some guidance here. I have even in a desperate attempt to understand my problem from a different perspective I have looked at how it is done in other languages. This is the latest iteration:

import UIKit import Foundation

struct ScheduleList: Codable {
let data: [Datum]

enum CodingKeys: String, CodingKey {
    case data = "data"
  }
}

struct Datum: Codable {
let date: String
let message: String
let notice: String

enum CodingKeys: String, CodingKey {
    case date = "date"
    case message = "message"
    case notice = "notice"
  }
}

class VCMainViewController: UIViewController {

@IBOutlet weak var flightTable: UITableView!

@IBOutlet weak var date: UILabel!

@IBOutlet weak var route: UILabel!

@IBOutlet weak var std: UILabel!

@IBOutlet weak var sta: UILabel!

@IBOutlet weak var pax: UILabel!


let flight = [Datum]()

func parse() {
    let jsonUrlString = "http://35.237.114.234/api/index.php?uid=Bx7faf08A9fYJ7bZCNMUX9EzxYN2"

    guard let url = URL(string: jsonUrlString) else { return }

    let task = URLSession.shared.scheduleListTask(with: url) { (scheduleList, response, error) in

        guard let scheduleList = scheduleList, error == nil, response != nil else {
            print("Something Wrong")
            return
        }
        print("downlaoded")

        do {
            let decoder = JSONDecoder()
//Error Here: Cannot convert value of type 'ScheduleList' to expected argument type 'Data'
            let downloadedFlights = try decoder.decode([scheduleList], from: scheduleList)
            self.flight = downloadedFlights.date
        } catch {
            print("Something wrong after loading")
        }

    }
//I find I can print data / scheduleList here and it still returns correct data. So something above I guess is the problem.
    task.resume()

    /*
        if scheduleList != nil {
                 print(scheduleList!)
        } else {
            print(error)
        }
     }
    */

}


override func viewDidLoad() {
    super.viewDidLoad()

    parse()

}

}

**Added full JSON file now due to issue with original post.

I think the structure is the problem. Any advice where I am going wrong? I can't cast that as Data, the dataTask data is called scheduleList so I don't know why this won't accept it.

Thanks

James
  • 19
  • 1
  • 7
  • 1
    So what actually happens when you run this code? Update your question (don't post comments) with details about any messages, errors, etc. – rmaddy Jul 03 '18 at 20:22
  • feel free to see my post maybe it will help. https://stackoverflow.com/questions/50420124/swift-json-deserialization-is-wrong also check out http://www.json4swift.com/ – owen gerig Jul 03 '18 at 20:23
  • 2
    Just google for "JSON on-line viewer validator".. You'll notice that your JSON *ISN'T* formatted correctly - and the viewer should help show you where, and what you can do to fix it. For example: [JSON formatter and validator](https://jsonformatter.curiousconcept.com/) – paulsm4 Jul 03 '18 at 20:23
  • sorry I dropped the last section of the scrape as it isn't relevant data but all on one result page. its in the link if you'd like to take a full look. – James Jul 03 '18 at 20:27
  • Remove the last comma and put a `}` instead and it should be valid. I think user cropped the JSON. Also, what's wrong with your current code? What's your question? Is it "is this JSON bad in term of use/architecture"? I can't decode it? – Larme Jul 03 '18 at 20:28
  • 1
    `for person in data` should be `for person in memebers`. The error is indicating you're trying to use a variable you haven't defined. – beyowulf Jul 03 '18 at 20:44

2 Answers2

2

Just change your last two characters from ], to ]}, and you'll have valid JSON.

It might even work :)

If it doesn't, please post back the exact error message, and the line it's failing on.

And again, having a JSON formatter/browser/validator handy is Good. I generally use a Notepad++ plugin. Here's a good on-line browser:

JSON formatter and validator

See also:

Stack Overflow: How to create a Minimal, Complete, and Verifiable example

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • please view full JSON at url. I trimmed the data as Is not relevant. Will change that last line to close. Also see last code block as error is here currently. – James Jul 03 '18 at 20:32
  • I checked the file to being with and Is valid as JSON and converts well in a converter. But cannot make it work in Swift. – James Jul 03 '18 at 20:34
1

The new way to handle JSON in Swift 4.1 is to use the Codable protocol (or its subvariants Encodable and Decodable). To go from a JSON string to actual objects, you should use Decodable.

//: Playground - noun: a place where people can play

import UIKit
import Foundation

struct Message: Decodable {
    let date: String
    let message: String
    let notice: String
}

struct Flight: Decodable {
    let flight: String
    let aircraft: String
    let operating: String
    let type: String
    let route: String
    let std: String
    let sta: String
    let pax: String
    let prm: String
    let check: String
}

struct Response: Decodable {
    let data: [Message]
    let flights: [Flight]
    let state: String

    private enum CodingKeys: String, CodingKey {
        case data, state
        case flights = "flight" // Parses "flight" from the response to the flights property
    }
}


// Get a String from your JSON and convert it to Data
let jsonString = "..."
let jsonData = jsonString.data(using .utf8)!

// Initialize the decoder
let decoder = JSONDecoder()

// Try to convert your JSON to objects
do {
    let response = try decoder.decode(Response.self, from: jsonData)
    print("Decoded successfully: \(response)")

    // Access values as usual with a struct... well, this IS a Swift struct already
    print("State: \(response.state)")
    // etc...
} catch {
    print("Error decoding: \(error)")
}

Check out Apple documentation here:

1) Encoding and Decoding Custom Types

2) JSONDecoder

Alejandro Iván
  • 3,969
  • 1
  • 21
  • 30
  • ok I see. But with this being out of context I do not understand where to implement this.... Run in Playgrounds and produces an error: "Error decoding: dataCorrupted(Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data was not valid JSON.", underlyingError: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set." UserInfo={NSDebugDescription=JSON text did not start with array or object and option to allow fragments not set.})))" – James Jul 03 '18 at 21:37
  • Run it on an actual project with your actual JSON. – Alejandro Iván Jul 03 '18 at 21:45
  • Hi so I spent over an hour building this and could not get it to work. The code I tried to post of my build was rejected so can not show. Any other suggestions for implementation to make this work? – James Jul 04 '18 at 01:28
  • `NSCocoaErrorDomain Code=3840` is the one specific error you've posted so far in this thread. Your JSON *MUST* have a top-level container: https://stackoverflow.com/questions/14171111/cocoa-error-3840-using-json-ios – paulsm4 Jul 04 '18 at 17:18