Shiv Jaiswal
Shiv Jaiswal

Reputation: 559

Write setter and getter method for variable while mapping swift?

I want to modify the value of roomTotal key while mapping. Please refer following code:

struct TransactionInfoModel: Codable {
   var currencyCode: String
   var total: Double
   var roomCurrencyCode: String
   var exchangeRate: Double

   var roomTotal: Double {
      get {
        let y = (self.roomTotal*100).rounded()/100
        return y
      }
   }
}

Initially, roomTotal key having the value from the server like "427.3000000002" but I want while mapping it stores value "427.3". Above code is not working.

Looking for some suggestions to resolve the issue.

Upvotes: 2

Views: 921

Answers (1)

Rob
Rob

Reputation: 437432

See this answer for example of how to round Double values and return a Decimal value that will preserve the rounding, without any of the artifacts that result when trying to represent decimal values in binary floating point representations. Then, you can get the rounded Decimal value like so:

let roomTotal = 427.3000000002
let value = roomTotal.roundedDecimal(to: 2)

And if you want to display it with a specified number of decimal places (as well as localize the string for the user's current locale), you can use a NumberFormatter:

let formatter = NumberFormatter()
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2

if let string = formatter.string(for: value) {
    print(string)
}

Now, if you want the JSONDecoder to do this conversion for you, you can, but I might be inclined to have the struct accurately represent what was returned, avoid any convoluted init(from:) implementation, but perhaps include a computed property to return the value in the format you want, e.g.:

struct TransactionInfoModel: Codable {
   var currencyCode: String
   var total: Double
   var roomCurrencyCode: String
   var exchangeRate: Double
   var roomTotal: Double

   var roundedRoomTotal: Decimal {
       return roomTotal.roundedDecimal(to: 2)
   }
}

If you need to round the roomTotal when you decode it, you can write an init(from:) to do that:

struct TransactionInfoModel: Codable {
    var currencyCode: String
    var total: Double
    var roomCurrencyCode: String
    var exchangeRate: Double
    var roomTotal: Decimal

    init(from decoder: Decoder) throws {
        let values       = try decoder.container(keyedBy: CodingKeys.self)
        currencyCode     = try values.decode(String.self, forKey: .currencyCode)
        total            = try values.decode(Double.self, forKey: .total)
        roomCurrencyCode = try values.decode(String.self, forKey: .roomCurrencyCode)
        exchangeRate     = try values.decode(Double.self, forKey: .exchangeRate)
        roomTotal        = try values.decode(Double.self, forKey: .roomTotal).roundedDecimal(to: 2)
    }
}

Alternatively, you could omit the init(from:), but manually round it after parsing:

struct TransactionInfoModel: Codable {
    var currencyCode: String
    var total: Double
    var roomCurrencyCode: String
    var exchangeRate: Double
    var roomTotal: Decimal
}

And:

var object = try! JSONDecoder().decode(TransactionInfoModel.self, from: data)
var rounded = Decimal()
NSDecimalRound(&rounded, &object.roomTotal, 2, .plain)
object.roomTotal = rounded

Upvotes: 1

Related Questions