0

I am new to iOS development and wanting some help here. I have a JSON output from a webservice and I want to display the details in a custom table view cell. Actually, I am following a tutorial here: https://www.youtube.com/watch?v=ea6_a_zbQrY

In that tutorial, the JSON output is as follows:-

{
  "actors": [
    {
      "name": "Brad Pitt",
      "description": "William Bradley 'Brad' Pitt is an American actor and film producer. He has received a Golden Globe Award, a Screen Actors Guild Award, and three Academy Award nominations in acting categories",
      "dob": "December 18, 1963",
      "country": "United States",
      "height": "1.80 m",
      "spouse": "Jennifer Aniston",
      "children": "Shiloh Nouvel Jolie-Pitt, Maddox Chivan Jolie-Pitt",
      "image": "http://microblogging.wingnity.com/JSONParsingTutorial/brad.jpg"
    },
    {
      "name": "Tom Cruise",
      "description": "Tom Cruise, is an American film actor and producer. He has been nominated for three Academy Awards and has won three Golden Globe Awards. He started his career at age 19 in the 1981 film Endless Love.",
      "dob": "July 3, 1962",
      "country": "United States",
      "height": "1.70 m",
      "spouse": "Katie Holmes",
      "children": "Suri Cruise, Isabella Jane Cruise, Connor Cruise",
      "image": "http://microblogging.wingnity.com/JSONParsingTutorial/cruise.jpg"
    },
    {
      "name": "Johnny Depp",
      "description": "John Christopher 'Johnny' Depp II is an American actor, film producer, and musician. He has won the Golden Globe Award and Screen Actors Guild award for Best Actor.",
      "dob": "June 9, 1963",
      "country": "United States",
      "height": "1.78 m",
      "spouse": "Lori Anne Allison",
      "children": "Lily-Rose Melody Depp, John 'Jack' Christopher Depp III",
      "image": "http://microblogging.wingnity.com/JSONParsingTutorial/johnny.jpg"
    },

My own JSON output are as follows:

[{"ID":"5662","Subject":"EXAM [JUNE 17 SEMESTER]","Course":"UNITAR","Lecturer":"EXAM OFFICER","CTime":"9:00AM-5:30PM","Venue":"10.03","TDate":"2017-09-04"},{"ID":"10314","Subject":"FAB","Course":"CAT","Lecturer":"DR CHONG","CTime":"9:00AM-12:00PM","Venue":"THEATRE ROOM 1 [LV 9]","TDate":"2017-09-04"},{"ID":"10317","Subject":"FMA","Course":"CAT","Lecturer":"GS ONG","CTime":"9:00AM-12:00PM","Venue":"9.09","TDate":"2017-09-04"},{"ID":"10318","Subject":"FFA","Course":"CAT","Lecturer":"MARGARET","CTime":"1:00PM-4:00PM","Venue":"THEATRE ROOM 1 [LV 9]","TDate":"2017-09-04"},{"ID":"10319","Subject":"MA1","Course":"CAT","Lecturer":"GS ONG","CTime":"1:00PM-4:00PM","Venue":"9.09","TDate":"2017-09-04"},{"ID":"10320","Subject":"P5","Course":"ACCA","Lecturer":"SPENCER","CTime":"6:15PM-9:45PM","Venue":"THEATRE ROOM 1 [LV 9]","TDate":"2017-09-04"},{"ID":"10324","Subject":"F8","Course":"ACCA","Lecturer":"MIKE KEE","CTime":"6:15PM-9:45PM","Venue":"9.02","TDate":"2017-09-04"},{"ID":"10325","Subject":"F2","Course":"ACCA","Lecturer":"GS ONG","CTime":"6:15PM-9:45PM","Venue":"9.09","TDate":"2017-09-04"},{"ID":"10326","Subject":"F4","Course":"ACCA","Lecturer":"HEMA","CTime":"6:15PM-9:45PM","Venue":"9.13","TDate":"2017-09-04"},{"ID":"11413","Subject":"M4","Course":"TG","Lecturer":"LAI WS","CTime":"7:00PM-10:00PM","Venue":"9.01","TDate":"2017-09-04"}]

Here is the code from the tutorial to parse the JSON values from the tutorial:

func downloadJsonWithURL() {
    let url = NSURL(string: urlString)
    URLSession.shared.dataTask(with: (url as? URL)!, completionHandler: {(data, response, error) -> Void in
        if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
            print(jsonObj!.value(forKey: "actors"))

            if let actorArray = jsonObj!.value(forKey: "actors") as? NSArray {
                for actor in actorArray{
                    if let actorDict = actor as? NSDictionary {
                        if let name = actorDict.value(forKey: "name") {
                            self.nameArray.append(name as! String)
                        }
                        if let name = actorDict.value(forKey: "dob") {
                            self.dobArray.append(name as! String)
                        }
                        if let name = actorDict.value(forKey: "image") {
                            self.imgURLArray.append(name as! String)
                        }
                    }
                }
            }

            OperationQueue.main.addOperation({
                self.tableView.reloadData()
            })
        }
    }).resume()
}

How do I modify this code as I don't have "actors" key in my JSON. Can someone guide me how to change this part?

5
  • you just have [[String:Any]]. So just use a for loop and access each object,and values with key. Commented Sep 4, 2017 at 4:31
  • 2
    FYI - Do not use NSArray or NSDictionary with Swift. Use native Swift collections. If you are using a tutorial that uses NSArray or NSDictionary then you need to find a better tutorial. And do not use NSURL, use URL. Commented Sep 4, 2017 at 4:39
  • 1
    Look for a better tutorial, this is a very bad code. Commented Sep 4, 2017 at 4:40
  • @vadian It really is. Almost every single line has a problem. Commented Sep 4, 2017 at 4:45
  • Thank you all. Yes, i find it not so appropriate. Still looking for other better way... Commented Sep 4, 2017 at 4:58

4 Answers 4

2

This is one of the worst codes I've ever seen. Almost everything is wrong or a very bad programming habit.

The biggest mistakes are:

  • No error handling at all.
  • The usage of Foundation (NSArray / NSDictionary) rather than native collection types.
  • The usage of multiple string arrays rather than one custom struct / class as data model.
  • The forced unwrapping of the values rather than handling the optionals safely.
  • The usage of valueForKey rather than dedicated objectForKey or key subscription.

First of all create a struct as data model and one array as data source

struct Schedule {
    let id, subject, course, lecturer, cTime, venue, tDate : String
}

var schedules = [Schedule]()

Assuming all values won't be changed the struct members are declared as constants (let). You get the memberwise initializer for free.

Reading JSON is very easy. There are only two collection types, array ([]) and dictionary ({}).

This JSON is an array of dictionaries ([{ .. }, { ...}]) . All keys and values are strings. The appropriate (native) Swift type is [[String:String]]. The code parses the JSON and assigns an empty string in case one of the keys does not exist.

func downloadJson(with urlString : String) {
    guard let url = URL(string: urlString) else { print("bad URL"); return }
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let connectionError = error {
            print(connectionError)
            return
        }
        do {
            if let scheduleArray = try JSONSerialization.jsonObject(with: data!) as? [[String:String]] {
                for item in scheduleArray {
                    self.schedules.append(Schedule(id: item["ID"] ?? "",
                                      subject: item["Subject"] ?? "",
                                      course: item["Course"] ?? "",
                                      lecturer: item["Lecturer"] ?? "",
                                      cTime: item["CTime"] ?? "",
                                      venue: item["Venue"] ?? "",
                                      tDate: item["TDate"] ?? ""))                
                }

                DispatchQueue.main.async {
                    self.tableView.reloadData()
                }
            }
        } catch {
            print(error)
        }
    }
    task.resume()
}

In the table view in cellForRow you can simply write

 let schedule = schedules[indexPath.row]
 aLabel.text = schedule.id
 anotherLabel.text = schedule.subject
 ...
Sign up to request clarification or add additional context in comments.

Comments

0

First ignore the JSON contents, and instead, think of it as an array of objects called as course.

[
    {
        "ID": "",
        "Subject": "",
        "Course": "",
        "Lecturer": "",
        "CTime": "",
        "Venue": "",
        "TDate": ""
    },

    ...
]

So first you need to parse your JSON as an array. Let's call it as coursesArray.

if let coursesArray = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSArray
{
    for course in CoursesArray
    {
        // course is a json object. So get it into a dictionary so that
        // we can access the values in the course.

        if let courseDict = course as? NSDictionary
        {
            // Now we can print the remaining properties of the course
            let id = courseDict.value(forKey: "ID")
            let subject = courseDict.value(forKey: "Subject")
            let courseName = courseDict.value(forKey: "Course")
            let lecturer = courseDict.value(forKey: "Lecturer")
            let cTime = courseDict.value(forKey: "CTime")
            let venue = courseDict.value(forKey: "Venue")
            let tDate = courseDict.value(forKey: "TDate")

            // Print them, or use them in any way you like now.
        }
    }
}

That should do about the extraction of the data. To be able to use these, you'll need to append them to other arrays, and reload the table. I'm leaving it to you.

Hope this helps.

3 Comments

Do not use NSArray or NSDictionary in Swift. This code needs to be rewritten properly.
@rmaddy Could you edit the answer? I'm a newbie to Swift. I used them as I previously used Objective C.
Thanks @Sri , i will give it a try. Appreciate it.
0

Try using following code , take json object as [[String:Any]] and loop through all the present dictionaries in It to get all values you require

//Two arrays to store your data and use it as result

    var IDs = [String]()
    var Subjects = [String]()


//Your function

func downloadJsonWithURL() {

        let url = URL(string: urlString)

        URLSession.shared.dataTask(with: (url as? URL)!, completionHandler: {(data, response, error) -> Void in

        if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as?  [[String:Any]] {
            print(jsonObj)

//Loop through all the keys present in the dictionaries inside 
               for key in jsonObj{

//Need to provide required key to check and loop in it  
                let ID = key["ID"]
                let Subject = key["Subject"]

//Append values in Arrays declared above 
                self.IDs.append(ID as! String)

            self.Subjects.append(Subject as! String)


        }


            OperationQueue.main.addOperation({
                self.tableView.reloadData()
            })
        }
    }).resume()
}

5 Comments

This code still needs some more cleanup. Don't use NSURL. Eliminate all of the bad uses of !.
Ah sorry, I just added my for loop in His question . I did not cleaned up his code
@rmaddy I edited my code For Url and please let me know user1734225 if result is still not found
@ios Geek you still have (as! String) in code. In future if value changed to Int from server side you can get a crash.So you can use guard statement and handle forced casting.
I will be happy if you edit my answer for this @TusharSharma
0

In the tutorial the author's data format is dictionary of arrays and each array is of type dictionary so, in the code first author converted json data into NSDictionary then accessed array with actor keyword.

But all this steps are not necessary in your case, because your data is directly in an array of dictionaries. So first convert your data as NSArray and then convert each record of it as NSDictionary as shown in below code snippet.

func downloadJsonWithURL() {
     let url = URL(string: urlString)

    URLSession.shared.dataTask(with: (url as? URL)!, completionHandler: {(data, response, error) -> Void in

    if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as?  [[String:String]] {
        print(jsonObj)

                for student in jsonObj{
                    if let studentDict = student as? [String:String] {
                        if let id = studentDict["ID"] ?? "" {
                            self.idArray.append(id)
                        }
                        if let subject = actorDict["Subject"] ?? "" {
                            self.subArray.append(subject)
                        }
                    }
                }
            OperationQueue.main.addOperation({
                self.tableView.reloadData()
            })
        }
    }).resume()
}

7 Comments

Please don't post code with no explanation. Describe what was wrong in the original code and explain how your answer solves the problem.
Besides providing no explanation, the code in this answer is all wrong. Almost every line needs to be rewritten properly.
@rmaddy thank u for your suggestions, i had modified my answer accordingly.
You still have NSURL. You still have lots of bad uses of !. You are still using value(forKey:). Still lots of code needs fixing.
Thanks @KrishnarjunBanoth, i will give it a try.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.