I am very new to the site and iOS, JSON itself and ran into an error which I couldn't resolve. I was parsing a nested JSON string using structs and codable but gave, me a thread error but compiled just fine.
Below is the JSON string:
let jsonString = """
{
"status": "success",
"data": {
"deliveryBoyConfig": {
"id": "1079",
"fname": "Anish",
"lname": "mix",
"country_code": "+91",
"mobile": "9999043499",
"email": "abc@gmail.com",
"address": "delhi INDIA",
"userid": "9",
"imei_number": "357729053845270",
"last_update": null,
"post_id": null,
"capacity": null,
"geo_latitude": "29",
"geo_longitude": "77.1545846",
"geo_radius": "500",
"insert_datetime": "2018-02-03 08:01:26",
"update_datetime": null,
"orig_id": "1079",
"is_otp": "0",
"img_path": null,
"device_token": null,
"flag": null,
"osVersion": null,
"appVersion": null,
"latitude": "28.7039558",
"longitude": "77.1591989",
"timestamp": "1466845730469",
"duty_status": "1",
"battery": "0.49000000953674316",
"charging": "0",
"speed": "0",
"distance": "0",
"geofence_id": null,
"monthly_fix_earning": "0",
"daily_fix_earning": "0",
"reimbursement_per_km": "0",
"monthly_revenue_target": "0",
"monthly_task_target": "0",
"monthly_carrying_capacity": "0",
"emp_is_active": "1",
"emp_used_leaves": 365,
"emp_remaining_leaves": -365,
"emp_total_leaves": "0"
},
"userConfig":
{
"id": "9",
"companyname": "Roadcast",
"custom_logo": "https://test.roadcast.co.in/webserviceos_followme_api/userimages/1525348697_121x33-web.png",
"latitude": "28.7040795",
"longitude": "77.1591007",
"google_address": "RoadCast, Shaheed Udham Singh Marg, Shalimar Bagh, Delhi, India",
"timezone": "Asia/Kolkata",
"rc_users_id": "9",
"is_callback": "1",
"url_callback_base": "64456",
"url_callback_accept": "646546",
"url_callback_dispatch": "6567778",
"url_callback_complete": "7979897",
"url_callback_tracking": "987757b",
"url_callback_reject": "7567546758b",
"url_key_name": "usudfsdfsdf",
"url_key": "2323",
"notes": "7667",
"url_auth_key": "5666",
"sms_dispatch": "1",
"m_complete_popup": "ROADCAST",
"is_cash_inhand_auto_approve": "0",
"deliv_proof_compulsory": "1",
"cash_inhand_proof": "1",
"allow_cancel_from_app": "1",
"hide_pickup_amt": "0",
"auto_attendance": "0",
"auto_attendance_in": "IN",
"auto_attendance_out": "OUT",
"battery_optimization": "24",
"ttf_report": "1",
"ttf_for_dispatch": "1",
"ttf_time": "5",
"web_location": "1",
"kpi_attendance_in": "00:00:00",
"kpi_attendance_out": "00:00:00",
"kpi_duty_hours": "",
"kpi_distance_per_day": null,
"kpi_min_kms": null,
"kpi_max_idle_time": null,
"kpi_within_geofence": "0",
"kpi_outside_geofence": "0",
"kpi_min_orders": "10",
"kpi_max_orders": "10",
"kpi_def_deliv_time": null,
"kpi_delayed_orders": null,
"emp_limit": "5",
"shift_max_hours": "103",
"reset_shift_after": "2",
"shift_enable": "0",
"url_header_api_key_name": null,
"url_header_api_key": null,
"default_order_type": "D",
"extra_order_fields": "1",
"ord_fields_json": "[]",
"show_unique_fields": "1",
"show_stores": "0",
"currency": "INR",
"pod_upload_limit": "10",
"order_fields_names": "{\"pickupcheckbox\":0,\"deliverycheckbox\":0,\"additems\":\"ADD ITEMS\",\"delivery\":\"delivery\",\"pickup\":\"PICK-UP\",\"both\":\"Both\",\"additionalnotes\":\"Additional notes\",\"orderNumber\":\"Order No\",\"billAmount\":\"Bill amount\",\"orderType\":\"Order type\",\"custNameDeliv\":\"Customer name\",\"custMobileDeliv\":\"Customer Mobile\",\"custAddDeliv\":\"Customer address\",\"custAddDelivGgl\":\"Customer address Google\",\"paymentReceivedDeliv\":\"Payment received\",\"assignTo\":\"Assign order to\",\"custMobilePickup\":\"Customer Mobile\",\"custAddPickup\":\"Customer address\",\"custAddPickupGgl\":\"Customer address Google\",\"paymentReceivedPickup\":\"Payment received\",\"custNamePickup\":\"Customer name\",\"delivery_time\":\"Delivery time\",\"pickup_time\":\"Pick time\",\"deliver_by\":\"Deliver by\",\"pickup_by\":\"Pickup by\",\"assigned_at\":\"Assigned at\",\"dispatch_order_pickup\":\"Dispatch Order\",\"collect_payment_pickup\":\"Collect Payment\",\"incomplete_task_pickup\":\"Complete Delivery\",\"dispatch_order_delivery\":\"Dispatch Order\",\"collect_payment_delivery\":\"Collect Payment\",\"incomplete_task_delivery\":\"Complete Delivery\",\"order_progress_dispatch\":\"Dispatch\",\"order_progress_completed\":\"Completed\",\"order_progress_pickup_completed\":\"Completed\",\"order_progress_accepted\":\"Accepted\",\"select_customer\":\"Select Customer\",\"dispatch_completed_delivery\":\"Dispatch completed delivery\",\"dispatch_completed_pickup\":\"Dispatch completed pickup\",\"payment_completed_delivery\":\"Payment completed delivery\",\"payment_completed_pickup\":\"Dispatch completed pickup\",\"task_completed_delivery\":\"Task completed delivery\",\"task_completed_pickup\":\"Task completed delivery\",\"default_dispatch_pickup\":\"Default dispatch pickup\"}",
"page_access_settings": "[{\"id\":9,\"priv\":[0,1]},{\"id\":766,\"priv\":[0,1]}]",
"marker_input_field": "{\"name\":\"\",\"type\":\"dropdown\",\"options\":[{\"name\":\"sdf\",\"color\":\"#0F9595\"}]}",
"auto_gen_ord_no": "0",
"auto_gen_ord_prefix": "RC",
"is_payment_available": "1",
"show_create_order": "1",
"duty_config": "1",
"tracking_type": "0",
"interval_tracking_time": "10",
"sms_comp_name": "ssdf",
"sms_callcenter_no": "2323233232",
"uniqueCompanyName": "bbbbbbb",
"auto_complete_ord": "0",
"auto_complete_ord_val": "{\"time\":\"1\",\"accepted\":0,\"unassigned\":0,\"notaccepted\":0,\"all\":0}",
"auto_dispatch_ord": "0",
"auto_dispatch_time": "1",
"enable_idle_time": "0",
"idle_time_val": "1",
"show_sales_management": "1",
"expense_types": "[]",
"sales_task_prefix": "task1234",
"show_distance_module": "1",
"auto_complete_stask": "0",
"auto_complete_stask_val": "1",
"create_stask_backdate": "1",
"create_stask_backdate_val": "1",
"route_plan_visibility_val": "1",
"route_plan_visibility_type": "M",
"route_plan_is_freeze": "1",
"holiday_calendar_type": "",
"holiday_max_in_late_status": "0",
"holiday_max_in_late_value": "04:30",
"holiday_max_in_half_status": "0",
"holiday_max_in_half_value": "05:00",
"holiday_max_out_status": "0",
"holiday_max_out_value": "15:30",
"holiday_min_hours_status": "0",
"holiday_min_hours_value": "5",
"holiday_approval_date_limit_status": "0",
"holiday_approval_date_limit_value": "1",
"holiday_approval_required_status": "0",
"leave_types": "[\"Privilege leave\",\"Casual Leave\",\"Travel Leave\",\"medical leave\"]",
"enable_leave_types": "0",
"holiday_weekend": "[\"sunday\"]",
"emp_total_leaves": "0",
"late_equi_half_status": "0",
"late_equi_half_value": "2",
"transport_mode_input_field": "{\"name\":\"Transport Mode\",\"type\":\"text\"}",
"show_custom_form": "1",
"enable_receipt_sharing": "1",
"customer_types": "[\"Customer\",\"Buyer\",\"Seller\",\"seller2\",\"customer\",\"Test\",\"Retailer\"]"
}
},
"message": "OK"
}
"""
Below is the structs I am using:
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
struct Welcome: Codable {
let status: String
let data: DataClass
let message: String
}
struct DataClass: Codable {
let deliveryBoyConfig: DeliveryBoyConfig
let userConfig: [String: String?]
}
struct DeliveryBoyConfig: Codable {
let id, fname, lname, countryCode: String
let mobile, email, address, userid: String
let imeiNumber: String
let lastUpdate, postID, capacity: JSONNull?
let geoLatitude, geoLongitude, geoRadius, insertDatetime: String
let updateDatetime: JSONNull?
let origID, isOtp: String
let imgPath, deviceToken, flag, osVersion: JSONNull?
let appVersion: JSONNull?
let latitude, longitude, timestamp, dutyStatus: String
let battery, charging, speed, distance: String
let geofenceID: JSONNull?
let monthlyFixEarning, dailyFixEarning, reimbursementPerKM, monthlyRevenueTarget: String
let monthlyTaskTarget, monthlyCarryingCapacity, empIsActive: String
let empUsedLeaves, empRemainingLeaves: Int
let empTotalLeaves: String
enum CodingKeys: String, CodingKey {
case id, fname, lname
case countryCode = "country_code"
case mobile, email, address, userid
case imeiNumber = "imei_number"
case lastUpdate = "last_update"
case postID = "post_id"
case capacity
case geoLatitude = "geo_latitude"
case geoLongitude = "geo_longitude"
case geoRadius = "geo_radius"
case insertDatetime = "insert_datetime"
case updateDatetime = "update_datetime"
case origID = "orig_id"
case isOtp = "is_otp"
case imgPath = "img_path"
case deviceToken = "device_token"
case flag, osVersion, appVersion, latitude, longitude, timestamp
case dutyStatus = "duty_status"
case battery, charging, speed, distance
case geofenceID = "geofence_id"
case monthlyFixEarning = "monthly_fix_earning"
case dailyFixEarning = "daily_fix_earning"
case reimbursementPerKM = "reimbursement_per_km"
case monthlyRevenueTarget = "monthly_revenue_target"
case monthlyTaskTarget = "monthly_task_target"
case monthlyCarryingCapacity = "monthly_carrying_capacity"
case empIsActive = "emp_is_active"
case empUsedLeaves = "emp_used_leaves"
case empRemainingLeaves = "emp_remaining_leaves"
case empTotalLeaves = "emp_total_leaves"
}
}
and I parse it using the method below:
func jsonOne(){
do{
let jsonData = Data(jsonString.utf8)
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let encoder = JSONEncoder()
let habla = try! decoder.decode(Welcome.self, from : jsonData)
print(habla)
let x = habla.data.deliveryBoyConfig.address ; print(x)
let y = habla.data.userConfig ; print(y)
} catch{ print("bad json") }
}
You can use below code to parse your JSON with codable protocol.
How To Initialize It:
do{
let myCustomJSON = try MyCustomJSON(json)
}catch{
return
}
Model Classes:
class MyCustomJSON: Codable {
let status: String
let data: DataClass
let message: String
enum CodingKeys: String, CodingKey {
case status = "status"
case data = "data"
case message = "message"
}
init(status: String, data: DataClass, message: String) {
self.status = status
self.data = data
self.message = message
}
}
class DataClass: Codable {
let deliveryBoyConfig: DeliveryBoyConfig
let userConfig: [String: String?]
enum CodingKeys: String, CodingKey {
case deliveryBoyConfig = "deliveryBoyConfig"
case userConfig = "userConfig"
}
init(deliveryBoyConfig: DeliveryBoyConfig, userConfig: [String: String?]) {
self.deliveryBoyConfig = deliveryBoyConfig
self.userConfig = userConfig
}
}
class DeliveryBoyConfig: Codable {
let id: String
let fname: String
let lname: String
let countryCode: String
let mobile: String
let email: String
let address: String
let userid: String
let imeiNumber: String
let lastUpdate: JSONNull?
let postID: JSONNull?
let capacity: JSONNull?
let geoLatitude: String
let geoLongitude: String
let geoRadius: String
let insertDatetime: String
let updateDatetime: JSONNull?
let origID: String
let isOtp: String
let imgPath: JSONNull?
let deviceToken: JSONNull?
let flag: JSONNull?
let osVersion: JSONNull?
let appVersion: JSONNull?
let latitude: String
let longitude: String
let timestamp: String
let dutyStatus: String
let battery: String
let charging: String
let speed: String
let distance: String
let geofenceID: JSONNull?
let monthlyFixEarning: String
let dailyFixEarning: String
let reimbursementPerKM: String
let monthlyRevenueTarget: String
let monthlyTaskTarget: String
let monthlyCarryingCapacity: String
let empIsActive: String
let empUsedLeaves: Int
let empRemainingLeaves: Int
let empTotalLeaves: String
enum CodingKeys: String, CodingKey {
case id = "id"
case fname = "fname"
case lname = "lname"
case countryCode = "country_code"
case mobile = "mobile"
case email = "email"
case address = "address"
case userid = "userid"
case imeiNumber = "imei_number"
case lastUpdate = "last_update"
case postID = "post_id"
case capacity = "capacity"
case geoLatitude = "geo_latitude"
case geoLongitude = "geo_longitude"
case geoRadius = "geo_radius"
case insertDatetime = "insert_datetime"
case updateDatetime = "update_datetime"
case origID = "orig_id"
case isOtp = "is_otp"
case imgPath = "img_path"
case deviceToken = "device_token"
case flag = "flag"
case osVersion = "osVersion"
case appVersion = "appVersion"
case latitude = "latitude"
case longitude = "longitude"
case timestamp = "timestamp"
case dutyStatus = "duty_status"
case battery = "battery"
case charging = "charging"
case speed = "speed"
case distance = "distance"
case geofenceID = "geofence_id"
case monthlyFixEarning = "monthly_fix_earning"
case dailyFixEarning = "daily_fix_earning"
case reimbursementPerKM = "reimbursement_per_km"
case monthlyRevenueTarget = "monthly_revenue_target"
case monthlyTaskTarget = "monthly_task_target"
case monthlyCarryingCapacity = "monthly_carrying_capacity"
case empIsActive = "emp_is_active"
case empUsedLeaves = "emp_used_leaves"
case empRemainingLeaves = "emp_remaining_leaves"
case empTotalLeaves = "emp_total_leaves"
}
init(id: String, fname: String, lname: String, countryCode: String, mobile: String, email: String, address: String, userid: String, imeiNumber: String, lastUpdate: JSONNull?, postID: JSONNull?, capacity: JSONNull?, geoLatitude: String, geoLongitude: String, geoRadius: String, insertDatetime: String, updateDatetime: JSONNull?, origID: String, isOtp: String, imgPath: JSONNull?, deviceToken: JSONNull?, flag: JSONNull?, osVersion: JSONNull?, appVersion: JSONNull?, latitude: String, longitude: String, timestamp: String, dutyStatus: String, battery: String, charging: String, speed: String, distance: String, geofenceID: JSONNull?, monthlyFixEarning: String, dailyFixEarning: String, reimbursementPerKM: String, monthlyRevenueTarget: String, monthlyTaskTarget: String, monthlyCarryingCapacity: String, empIsActive: String, empUsedLeaves: Int, empRemainingLeaves: Int, empTotalLeaves: String) {
self.id = id
self.fname = fname
self.lname = lname
self.countryCode = countryCode
self.mobile = mobile
self.email = email
self.address = address
self.userid = userid
self.imeiNumber = imeiNumber
self.lastUpdate = lastUpdate
self.postID = postID
self.capacity = capacity
self.geoLatitude = geoLatitude
self.geoLongitude = geoLongitude
self.geoRadius = geoRadius
self.insertDatetime = insertDatetime
self.updateDatetime = updateDatetime
self.origID = origID
self.isOtp = isOtp
self.imgPath = imgPath
self.deviceToken = deviceToken
self.flag = flag
self.osVersion = osVersion
self.appVersion = appVersion
self.latitude = latitude
self.longitude = longitude
self.timestamp = timestamp
self.dutyStatus = dutyStatus
self.battery = battery
self.charging = charging
self.speed = speed
self.distance = distance
self.geofenceID = geofenceID
self.monthlyFixEarning = monthlyFixEarning
self.dailyFixEarning = dailyFixEarning
self.reimbursementPerKM = reimbursementPerKM
self.monthlyRevenueTarget = monthlyRevenueTarget
self.monthlyTaskTarget = monthlyTaskTarget
self.monthlyCarryingCapacity = monthlyCarryingCapacity
self.empIsActive = empIsActive
self.empUsedLeaves = empUsedLeaves
self.empRemainingLeaves = empRemainingLeaves
self.empTotalLeaves = empTotalLeaves
}
}
// MARK: Convenience initializers and mutators
extension MyCustomJSON {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(MyCustomJSON.self, from: data)
self.init(status: me.status, data: me.data, message: me.message)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
status: String? = nil,
data: DataClass? = nil,
message: String? = nil
) -> MyCustomJSON {
return MyCustomJSON(
status: status ?? self.status,
data: data ?? self.data,
message: message ?? self.message
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
extension DataClass {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(DataClass.self, from: data)
self.init(deliveryBoyConfig: me.deliveryBoyConfig, userConfig: me.userConfig)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
deliveryBoyConfig: DeliveryBoyConfig? = nil,
userConfig: [String: String?]? = nil
) -> DataClass {
return DataClass(
deliveryBoyConfig: deliveryBoyConfig ?? self.deliveryBoyConfig,
userConfig: userConfig ?? self.userConfig
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
extension DeliveryBoyConfig {
convenience init(data: Data) throws {
let me = try newJSONDecoder().decode(DeliveryBoyConfig.self, from: data)
self.init(id: me.id, fname: me.fname, lname: me.lname, countryCode: me.countryCode, mobile: me.mobile, email: me.email, address: me.address, userid: me.userid, imeiNumber: me.imeiNumber, lastUpdate: me.lastUpdate, postID: me.postID, capacity: me.capacity, geoLatitude: me.geoLatitude, geoLongitude: me.geoLongitude, geoRadius: me.geoRadius, insertDatetime: me.insertDatetime, updateDatetime: me.updateDatetime, origID: me.origID, isOtp: me.isOtp, imgPath: me.imgPath, deviceToken: me.deviceToken, flag: me.flag, osVersion: me.osVersion, appVersion: me.appVersion, latitude: me.latitude, longitude: me.longitude, timestamp: me.timestamp, dutyStatus: me.dutyStatus, battery: me.battery, charging: me.charging, speed: me.speed, distance: me.distance, geofenceID: me.geofenceID, monthlyFixEarning: me.monthlyFixEarning, dailyFixEarning: me.dailyFixEarning, reimbursementPerKM: me.reimbursementPerKM, monthlyRevenueTarget: me.monthlyRevenueTarget, monthlyTaskTarget: me.monthlyTaskTarget, monthlyCarryingCapacity: me.monthlyCarryingCapacity, empIsActive: me.empIsActive, empUsedLeaves: me.empUsedLeaves, empRemainingLeaves: me.empRemainingLeaves, empTotalLeaves: me.empTotalLeaves)
}
convenience init(_ json: String, using encoding: String.Encoding = .utf8) throws {
guard let data = json.data(using: encoding) else {
throw NSError(domain: "JSONDecoding", code: 0, userInfo: nil)
}
try self.init(data: data)
}
convenience init(fromURL url: URL) throws {
try self.init(data: try Data(contentsOf: url))
}
func with(
id: String? = nil,
fname: String? = nil,
lname: String? = nil,
countryCode: String? = nil,
mobile: String? = nil,
email: String? = nil,
address: String? = nil,
userid: String? = nil,
imeiNumber: String? = nil,
lastUpdate: JSONNull?? = nil,
postID: JSONNull?? = nil,
capacity: JSONNull?? = nil,
geoLatitude: String? = nil,
geoLongitude: String? = nil,
geoRadius: String? = nil,
insertDatetime: String? = nil,
updateDatetime: JSONNull?? = nil,
origID: String? = nil,
isOtp: String? = nil,
imgPath: JSONNull?? = nil,
deviceToken: JSONNull?? = nil,
flag: JSONNull?? = nil,
osVersion: JSONNull?? = nil,
appVersion: JSONNull?? = nil,
latitude: String? = nil,
longitude: String? = nil,
timestamp: String? = nil,
dutyStatus: String? = nil,
battery: String? = nil,
charging: String? = nil,
speed: String? = nil,
distance: String? = nil,
geofenceID: JSONNull?? = nil,
monthlyFixEarning: String? = nil,
dailyFixEarning: String? = nil,
reimbursementPerKM: String? = nil,
monthlyRevenueTarget: String? = nil,
monthlyTaskTarget: String? = nil,
monthlyCarryingCapacity: String? = nil,
empIsActive: String? = nil,
empUsedLeaves: Int? = nil,
empRemainingLeaves: Int? = nil,
empTotalLeaves: String? = nil
) -> DeliveryBoyConfig {
return DeliveryBoyConfig(
id: id ?? self.id,
fname: fname ?? self.fname,
lname: lname ?? self.lname,
countryCode: countryCode ?? self.countryCode,
mobile: mobile ?? self.mobile,
email: email ?? self.email,
address: address ?? self.address,
userid: userid ?? self.userid,
imeiNumber: imeiNumber ?? self.imeiNumber,
lastUpdate: lastUpdate ?? self.lastUpdate,
postID: postID ?? self.postID,
capacity: capacity ?? self.capacity,
geoLatitude: geoLatitude ?? self.geoLatitude,
geoLongitude: geoLongitude ?? self.geoLongitude,
geoRadius: geoRadius ?? self.geoRadius,
insertDatetime: insertDatetime ?? self.insertDatetime,
updateDatetime: updateDatetime ?? self.updateDatetime,
origID: origID ?? self.origID,
isOtp: isOtp ?? self.isOtp,
imgPath: imgPath ?? self.imgPath,
deviceToken: deviceToken ?? self.deviceToken,
flag: flag ?? self.flag,
osVersion: osVersion ?? self.osVersion,
appVersion: appVersion ?? self.appVersion,
latitude: latitude ?? self.latitude,
longitude: longitude ?? self.longitude,
timestamp: timestamp ?? self.timestamp,
dutyStatus: dutyStatus ?? self.dutyStatus,
battery: battery ?? self.battery,
charging: charging ?? self.charging,
speed: speed ?? self.speed,
distance: distance ?? self.distance,
geofenceID: geofenceID ?? self.geofenceID,
monthlyFixEarning: monthlyFixEarning ?? self.monthlyFixEarning,
dailyFixEarning: dailyFixEarning ?? self.dailyFixEarning,
reimbursementPerKM: reimbursementPerKM ?? self.reimbursementPerKM,
monthlyRevenueTarget: monthlyRevenueTarget ?? self.monthlyRevenueTarget,
monthlyTaskTarget: monthlyTaskTarget ?? self.monthlyTaskTarget,
monthlyCarryingCapacity: monthlyCarryingCapacity ?? self.monthlyCarryingCapacity,
empIsActive: empIsActive ?? self.empIsActive,
empUsedLeaves: empUsedLeaves ?? self.empUsedLeaves,
empRemainingLeaves: empRemainingLeaves ?? self.empRemainingLeaves,
empTotalLeaves: empTotalLeaves ?? self.empTotalLeaves
)
}
func jsonData() throws -> Data {
return try newJSONEncoder().encode(self)
}
func jsonString(encoding: String.Encoding = .utf8) throws -> String? {
return String(data: try self.jsonData(), encoding: encoding)
}
}
// MARK: Encode/decode helpers
class JSONNull: Codable, Hashable {
public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
return true
}
public var hashValue: Int {
return 0
}
public init() {}
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if !container.decodeNil() {
throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encodeNil()
}
}
func newJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
decoder.dateDecodingStrategy = .iso8601
}
return decoder
}
func newJSONEncoder() -> JSONEncoder {
let encoder = JSONEncoder()
if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
encoder.dateEncodingStrategy = .iso8601
}
return encoder
}