Search code examples
iosjsonswiftnsjsonserialization

JSONSerialization parsing issue:


I am experiencing an error while parsing a json

"hoursOfOperation" : {
      "sat" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1020,
              "open" : 600
            }
          }
        ]
      },
      "fri" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1260,
              "open" : 660
            }
          }
        ]
      },
      "sun" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1020,
              "open" : 600
            }
          }
        ]
      },
      "mon" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1260,
              "open" : 960
            }
          }
        ]
      },
      "tue" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1260,
              "open" : 660
            }
          }
        ]
      },
      "wed" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1260,
              "open" : 660
            }
          }
        ]
      },
      "thu" : {
        "enabled" : true,
        "schedule" : [
          {
            "time" : {
              "close" : 1260,
              "open" : 660
            }
          }
        ]
      }
    }

This is JSON shared. I'm using JSONSerialization for parsing the same. Code is as below:

struct HoursOfOperation{

var sun : hoursOfOperationData?
var mon : hoursOfOperationData?
var tue : hoursOfOperationData?
var wed : hoursOfOperationData?
var thu : hoursOfOperationData?
var fri : hoursOfOperationData?
var sat : hoursOfOperationData?

init(_ info: AnyObject) {
    let s = String(describing: info)
    let data = s.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    do {
        let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]

        if let sun = json["sun"]{
            self.sun = hoursOfOperationData.init(sun)
        }
        if let sat = json["sat"]{
            self.sat = hoursOfOperationData.init(sat)
        }
        if let fri = json["fri"]{
            self.fri = hoursOfOperationData.init(fri)
        }
        if let thu = json["thu"] {
            self.thu = hoursOfOperationData.init(thu)
        }
        if let wed = json["wed"]{
            self.wed = hoursOfOperationData.init(wed)
        }
        if let tue = json["tue"]{
            self.tue = hoursOfOperationData.init(tue)
        }
        if let mon = json["mon"] {
            self.mon = hoursOfOperationData.init(mon)
        }
    } catch let error as NSError {
        print("Failed to load: \(error.localizedDescription)")
    }
}
}

//hoursOfOperationData

struct hoursOfOperationData{

var enabled : AnyObject?
var schedule : [scheduleData]?

init(_ info: AnyObject) {
    let s = String(describing: info)
    let data = s.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    do {
        let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
        if let enabled = json["enabled"]{
            self.enabled = enabled as AnyObject
        }
        if let schedule = json["schedule"] as? NSArray{

            for dic in schedule{
                schedule.adding(scheduleData.init(dic as AnyObject))
            }
            self.schedule = schedule as? [scheduleData]
        }
    } catch let error as NSError {
        print("Failed to load: \(error.localizedDescription)")
    }
}
}

//scheduleData

struct scheduleData{

var time : scheduleDataForLocation?

init(_ info: AnyObject) {
    let s = String(describing: info)
    let data = s.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    do {
        let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
        if let time = json["time"]{
            self.time = scheduleDataForLocation.init(time)
        }
    } catch let error as NSError {
        print("Failed to load: \(error.localizedDescription)")
    }
    }
}

//scheduleDataForLocation

struct scheduleDataForLocation{

var openTime : AnyObject?
var closeTime : AnyObject?

init(_ info: AnyObject) {
    let s = String(describing: info)
    let data = s.data(using: String.Encoding.utf8, allowLossyConversion: false)!
    do {
        let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String: AnyObject]
        if let open = json["open"]{
            self.openTime = open as AnyObject
        }
        if let close = json["close"]{
            self.closeTime = close as AnyObject
        }
    } catch let error as NSError {
        print("Failed to load: \(error.localizedDescription)")
    }
}
}

While Preparing this model Im unable to parse the json and getting error message

' Error Domain=NSCocoaErrorDomain Code=3840 "No string key for value in object around character 6." UserInfo={NSDebugDescription=No string key for value in object around character 6.} '

Please suggest a correct way to handle the same. I have visited many stack overflow questions and answers but none answers my question. Any help would be appreciable.


Solution

  • You can directly use below model class, reference : http://www.jsoncafe.com/

    class OperationModel : NSObject, NSCoding{
    
        var hoursOfOperation : HoursOfOperation!
    
    
        /**
         * Instantiate the instance using the passed dictionary values to set the properties values
         */
        init(fromDictionary dictionary: [String:Any]){
            if let hoursOfOperationData = dictionary["hoursOfOperation"] as? [String:Any]{
                hoursOfOperation = HoursOfOperation(fromDictionary: hoursOfOperationData)
            }
        }
    
        /**
         * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
         */
        func toDictionary() -> [String:Any]
        {
            var dictionary = [String:Any]()
            if hoursOfOperation != nil{
                dictionary["hoursOfOperation"] = hoursOfOperation.toDictionary()
            }
            return dictionary
        }
    
        /**
         * NSCoding required initializer.
         * Fills the data from the passed decoder
         */
        @objc required init(coder aDecoder: NSCoder)
        {
            hoursOfOperation = aDecoder.decodeObject(forKey: "hoursOfOperation") as? HoursOfOperation
        }
    
        /**
         * NSCoding required method.
         * Encodes mode properties into the decoder
         */
        @objc func encode(with aCoder: NSCoder)
        {
            if hoursOfOperation != nil{
                aCoder.encode(hoursOfOperation, forKey: "hoursOfOperation")
            }
        }
    }
    
    
    class Schedule : NSObject, NSCoding{
    
        var time : Time!
    
    
        /**
         * Instantiate the instance using the passed dictionary values to set the properties values
         */
        init(fromDictionary dictionary: [String:Any]){
            if let timeData = dictionary["time"] as? [String:Any]{
                time = Time(fromDictionary: timeData)
            }
        }
    
        /**
         * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
         */
        func toDictionary() -> [String:Any]
        {
            var dictionary = [String:Any]()
            if time != nil{
                dictionary["time"] = time.toDictionary()
            }
            return dictionary
        }
    
        /**
         * NSCoding required initializer.
         * Fills the data from the passed decoder
         */
        @objc required init(coder aDecoder: NSCoder)
        {
            time = aDecoder.decodeObject(forKey: "time") as? Time
        }
    
        /**
         * NSCoding required method.
         * Encodes mode properties into the decoder
         */
        @objc func encode(with aCoder: NSCoder)
        {
            if time != nil{
                aCoder.encode(time, forKey: "time")
            }
        }
    }
    
    
    
    class HoursOfOperation : NSObject, NSCoding{
    
        var fri : Day!
        var mon : Day!
        var sat : Day!
        var sun : Day!
        var thu : Day!
        var tue : Day!
        var wed : Day!
    
    
        /**
         * Instantiate the instance using the passed dictionary values to set the properties values
         */
        init(fromDictionary dictionary: [String:Any]){
            if let friData = dictionary["fri"] as? [String:Any]{
                fri = Day(fromDictionary: friData)
            }
            if let monData = dictionary["mon"] as? [String:Any]{
                mon = Day(fromDictionary: monData)
            }
            if let satData = dictionary["sat"] as? [String:Any]{
                sat = Day(fromDictionary: satData)
            }
            if let sunData = dictionary["sun"] as? [String:Any]{
                sun = Day(fromDictionary: sunData)
            }
            if let thuData = dictionary["thu"] as? [String:Any]{
                thu = Day(fromDictionary: thuData)
            }
            if let tueData = dictionary["tue"] as? [String:Any]{
                tue = Day(fromDictionary: tueData)
            }
            if let wedData = dictionary["wed"] as? [String:Any]{
                wed = Day(fromDictionary: wedData)
            }
        }
    
        /**
         * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
         */
        func toDictionary() -> [String:Any]
        {
            var dictionary = [String:Any]()
            if fri != nil{
                dictionary["fri"] = fri.toDictionary()
            }
            if mon != nil{
                dictionary["mon"] = mon.toDictionary()
            }
            if sat != nil{
                dictionary["sat"] = sat.toDictionary()
            }
            if sun != nil{
                dictionary["sun"] = sun.toDictionary()
            }
            if thu != nil{
                dictionary["thu"] = thu.toDictionary()
            }
            if tue != nil{
                dictionary["tue"] = tue.toDictionary()
            }
            if wed != nil{
                dictionary["wed"] = wed.toDictionary()
            }
            return dictionary
        }
    
        /**
         * NSCoding required initializer.
         * Fills the data from the passed decoder
         */
        @objc required init(coder aDecoder: NSCoder)
        {
            fri = aDecoder.decodeObject(forKey: "fri") as? Day
            mon = aDecoder.decodeObject(forKey: "mon") as? Day
            sat = aDecoder.decodeObject(forKey: "sat") as? Day
            sun = aDecoder.decodeObject(forKey: "sun") as? Day
            thu = aDecoder.decodeObject(forKey: "thu") as? Day
            tue = aDecoder.decodeObject(forKey: "tue") as? Day
            wed = aDecoder.decodeObject(forKey: "wed") as? Day
        }
    
        /**
         * NSCoding required method.
         * Encodes mode properties into the decoder
         */
        @objc func encode(with aCoder: NSCoder)
        {
            if fri != nil{
                aCoder.encode(fri, forKey: "fri")
            }
            if mon != nil{
                aCoder.encode(mon, forKey: "mon")
            }
            if sat != nil{
                aCoder.encode(sat, forKey: "sat")
            }
            if sun != nil{
                aCoder.encode(sun, forKey: "sun")
            }
            if thu != nil{
                aCoder.encode(thu, forKey: "thu")
            }
            if tue != nil{
                aCoder.encode(tue, forKey: "tue")
            }
            if wed != nil{
                aCoder.encode(wed, forKey: "wed")
            }
        }
    }
    
    
    class Time : NSObject, NSCoding{
    
        var close : Int!
        var open : Int!
    
    
        /**
         * Instantiate the instance using the passed dictionary values to set the properties values
         */
        init(fromDictionary dictionary: [String:Any]){
            close = dictionary["close"] as? Int
            open = dictionary["open"] as? Int
        }
    
        /**
         * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
         */
        func toDictionary() -> [String:Any]
        {
            var dictionary = [String:Any]()
            if close != nil{
                dictionary["close"] = close
            }
            if open != nil{
                dictionary["open"] = open
            }
            return dictionary
        }
    
        /**
         * NSCoding required initializer.
         * Fills the data from the passed decoder
         */
        @objc required init(coder aDecoder: NSCoder)
        {
            close = aDecoder.decodeObject(forKey: "close") as? Int
            open = aDecoder.decodeObject(forKey: "open") as? Int
        }
    
        /**
         * NSCoding required method.
         * Encodes mode properties into the decoder
         */
        @objc func encode(with aCoder: NSCoder)
        {
            if close != nil{
                aCoder.encode(close, forKey: "close")
            }
            if open != nil{
                aCoder.encode(open, forKey: "open")
            }
        }
    }
    
    
    class Day : NSObject, NSCoding{
    
        var enabled : Bool!
        var schedule : [Schedule]!
    
    
        /**
         * Instantiate the instance using the passed dictionary values to set the properties values
         */
        init(fromDictionary dictionary: [String:Any]){
            enabled = dictionary["enabled"] as? Bool
            schedule = [Schedule]()
            if let scheduleArray = dictionary["schedule"] as? [[String:Any]]{
                for dic in scheduleArray{
                    let value = Schedule(fromDictionary: dic)
                    schedule.append(value)
                }
            }
        }
    
        /**
         * Returns all the available property values in the form of [String:Any] object where the key is the approperiate json key and the value is the value of the corresponding property
         */
        func toDictionary() -> [String:Any]
        {
            var dictionary = [String:Any]()
            if enabled != nil{
                dictionary["enabled"] = enabled
            }
            if schedule != nil{
                var dictionaryElements = [[String:Any]]()
                for scheduleElement in schedule {
                    dictionaryElements.append(scheduleElement.toDictionary())
                }
                dictionary["schedule"] = dictionaryElements
            }
            return dictionary
        }
    
        /**
         * NSCoding required initializer.
         * Fills the data from the passed decoder
         */
        @objc required init(coder aDecoder: NSCoder)
        {
            enabled = aDecoder.decodeObject(forKey: "enabled") as? Bool
            schedule = aDecoder.decodeObject(forKey: "schedule") as? [Schedule]
        }
    
        /**
         * NSCoding required method.
         * Encodes mode properties into the decoder
         */
        @objc func encode(with aCoder: NSCoder)
        {
            if enabled != nil{
                aCoder.encode(enabled, forKey: "enabled")
            }
            if schedule != nil{
                aCoder.encode(schedule, forKey: "schedule")
            }
        }
    }
    

    Use :

    let jsonData = try Data(contentsOf: url)
    let json = try JSONSerialization.jsonObject(with: jsonData) as! [String : Any]
    let arrOper = OperationModel(fromDictionary: json)
    

    Output:

    enter image description here