Parsing JSON data from alamofire into Array with Dictionary

15,260

Solution 1

First of all you should create a class that is your model of Schedule like this

class Schedule: NSObject {
  var departureTime: String
  var destination: String
  var trainType: String

  init(jsonDic : NSDictionary) {
      self.departureTime = jsonDic["departureTime"] != nil ? jsonDic["departureTime"] as! String! : nil
      self.destination = jsonDic["destination"] != nil ? jsonDic["destination"] as! String! : nil
      self.trainType = jsonDic["trainType"] != nil ? jsonDic["trainType"] as! String : nil
  }
}

And in your view controller your going to need an array of the Schedule object and after you could parse your Json you do it like this:

class ScheduleController: UIViewController {

    // The two object use to show the spinner loading
    var loadingView: UIView = UIView()
    var spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)

    // Array of your objects
    var arrSchedule: [Schedule] = []


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.getInfoSchedule()
    }

    func getInfoSchedule() {
        showActivityIndicator()
        Alamofire.request("https://api.mynexttrainschedule.net/", method: .get, parameters: nil, encoding: URLEncoding.default, headers: nil).responseJSON {
            response in
            self.hideActivityIndicator()
            switch response.result {
            case .success:
                if let objJson = response.result.value as! NSArray? {
                    for element in objJson {
                        let data = element as! NSDictionary
                        if let arraySchedule = data["schedule"] as! NSArray? {
                            for objSchedule in arraySchedule {
                                self.arrSchedule.append(Schedule(jsonDic: objSchedule as! NSDictionary))  
                            }
                        }
                    }
                }
            case .failure(let error):
                print("Error: \(error)")
            }
        }
    }

    //Those two method serves to show a spinner when the request is in execution

    func showActivityIndicator() {
        DispatchQueue.main.async {
            self.loadingView = UIView()
            self.loadingView.frame = CGRect(x: 0.0, y: 0.0, width: self.view.frame.width, height: self.view.frame.height)
            self.loadingView.center = self.view.center
            self.loadingView.backgroundColor = UIColor(rgba: "#111111")
            self.loadingView.alpha = 0.9
            self.loadingView.clipsToBounds = true
            self.spinner = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
            self.spinner.frame = CGRect(x: 0.0, y: 0.0, width: 80.0, height: 80.0)
            self.spinner.center = CGPoint(x:self.loadingView.bounds.size.width / 2, y:self.loadingView.bounds.size.height / 2)
            self.loadingView.addSubview(self.spinner)
            self.view.addSubview(self.loadingView)
            self.spinner.startAnimating()
        }
    }

    func hideActivityIndicator() {
        DispatchQueue.main.async {
            self.spinner.stopAnimating()
            self.loadingView.removeFromSuperview()
        }
    }
}

Maybe is not the more efficient way to do it, but it worked for me. I'm using swift3 with xcode 8.1.

Hope it helps !

Solution 2

Basically what you have is an array of schedules. You can map it using ObjectMapper. Install its pod and just create a new Swift file. and Write this

import ObjectMapper

class TrainSchedules: Mappable {

var mySchedules: [Schedules]

required init?(_ map: Map) {
    mySchedules = []
}

func mapping(map: Map) {
    mySchedules             <- map["schedule"]
}
}


class Schedules: Mappable {

var departureTime: String
var destination: String
var trainType: String

required init?(_ map: Map) {

    departureTime = ""
    destination = ""
    trainType = ""
}

func mapping(map: Map) {

    departureTime           <- map["departureTime"]
    destination             <- map["destination"]
    trainType               <- map["trainType"]

}
}

Now you can use it like

 if let data = Mapper<TrainSchedules>().map(json){
     // now data is an array containt=g all the schedules
     // access departureTimelike below
     print(data[0].departureTime)
 }

I hope it helps, Letme know if you find any difficulty.

Share:
15,260
El Tomato
Author by

El Tomato

Updated on June 08, 2022

Comments

  • El Tomato
    El Tomato over 1 year

    I'm trying to parse JSON data from alamorefire as follows.

    import UIKit
    import Alamofire
    import SwiftyJSON
    
    class ViewController: UIViewController {
        override func viewDidLoad() {
            super.viewDidLoad()
    
            Alamofire.request(.GET, "https://api.mynexttrainschedule.net/")
                .responseJSON { response in
                    guard let object = response.result.value else {
                        print("Oh, no!!!")
                        return
                    }
                    let json = JSON(object);print(json)
                    let schedule = json[0]["schedule"]
            }
        }
    }
    

    If I print json, I have a data structure like the following (stated concisely).

    [
      {
        "schedule" : [
            {"departureTime" : "05:09", "destination" : "Boston", "trainType" : "Express"},
            {"departureTime" : "05:19", "destination" : "Portland", "trainType" : "Rapid"},
            {"departureTime" : "05:29", "destination" : "Boston", "trainType" : "Express""}
        ],
        "station" : "Grand Central",
        "direction" : "North"
      },
      {
        "schedule" : [
            {"departureTime" : "05:11","destination" : "Washington, "trainType" : "Express""},
            {"departureTime" : "05:23","destination" : "Baltimore, "trainType" : "Express""},
            {"departureTime" : "05:35","destination" : "Richmond, "trainType" : "Local""}
        ],
        "station" : "Grand Central",
        "direction" : "South"
      }
    ]
    

    Now, how can I save the schedule array with a dictionary (departureTime, destination...) through or not through SwiftyJSON?

    Thanks.

    UPDATE

    The following is my own solution.

    import Alamofire
    import SwiftyJSON
    
    class ViewController: UIViewController {
        var scheduleArray = [Dictionary<String,String>]()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            Alamofire.request(.GET, "https://api.mynexttrainschedule.net/")
                .responseJSON { response in
                    guard let object = response.result.value else {
                        print("Oh, no!!!")
                        return
                    }
                    let json = JSON(object)
                    if let jArray = json.array {
                        if let westHolidayArray = jArray[0]["schedule"].array {
                            for train in westHolidayArray {
                                if let time = train["departureTime"].string,
                                    let dest = train["destination"].string,
                                    let type = train["trainType"].string {
                                    let dict = ["time":time, "dest":dest, "type": type]
                                    self.scheduleArray.append(d)
                                }
                            }
                        }
                    }
            }
        }
    }
    
  • El Tomato
    El Tomato almost 7 years
    Thanks. I get an error on '.map' (above print). It says 'Cannot invoke 'map' with an argument list of type (JSON)
  • Umair Afzal
    Umair Afzal almost 7 years
    you basically have to pass your jsonObject (result of service) to the function
  • El Tomato
    El Tomato almost 7 years
    Thanks. Where does 'dir' as in self.arrSchedule.append(Schedule(jsonDic: dir as! NSDictionary)) come from?
  • Snoobie
    Snoobie almost 7 years
    I updated my answer it was objSchedule instead of dir sorry
  • El Tomato
    El Tomato almost 7 years
    The app crashes with the following message: nw_host_stats_add_src recv too small, received 24, expected 28 . I saw the same error a few days. I don't remember what it was for, but I think it made me switch to Swift 2.3 under Xcode 7.
  • Snoobie
    Snoobie almost 7 years
    Which version of xcode you were using ? Because the version 8.0 has lot of troubles. Maybe it could be the reason.
  • El Tomato
    El Tomato almost 7 years
    I get the error above under Xcode 8.1. I don't have trouble with alamofire 3.5.1 under Xcode 7.3.1.
  • Snoobie
    Snoobie almost 7 years
    Well normally the logic is the same, just you should change the prototype of the Alamofire.request. Let me know if you could not solve it, and I will try to adapt the code with the version of Xcode and Swift that you have.
  • El Tomato
    El Tomato almost 7 years
    arrSchedule returns an empty array.
  • Snoobie
    Snoobie almost 7 years
    Have you found a solution ? If it's not the case https://api.mynexttrainschedule.net/ is the API that give you that Json ?
  • El Tomato
    El Tomato almost 7 years
    I have come up with my solution above. No, that's not an actual URL.
  • El Tomato
    El Tomato over 6 years
    There's already a solution if you read the question carefully.
  • Varinder Singh  iPhone Dev
    Varinder Singh iPhone Dev over 3 years
    wahh.. nice Answer