9

I'm using ObjectMapper to cast json into objects. My problem is that the NSDate property is not being mapped correctly. Here is the json:

{
   "Id":4775,
   "Cor":{
      "Id":2,
      "Nome":"Amarelo",
      "HTMLCode":"FFFB00"
   },
   "Data":"2016-07-25T09:35:00",
   "Texto":"test test test",
   "Kilometro":547.0
}

And here is my mappable class

class RoadWarning : Mappable {

    var id: Int?
    var color: RoadWarningColor?
    var date: NSDate?
    var text: String?
    var kilometer: Float?

    required init?(_ map: Map){

    }

    func mapping(map: Map) {
        id <- map["Id"]
        color <- map["Cor"]
        text <- map["Texto"]
        kilometer <- map["Kilometro"]
        date    <- (map["Data"], DateTransform())
    }
}

The problem is that the date property is always 1970-01-01. I can't see yet what I am missing. Can you see what is wrong in this mapping?

Thanks

André Luiz
  • 6,642
  • 9
  • 55
  • 105

4 Answers4

14

ObjectMapper not convert from String to NSDate properly you have to make a workaround like this to specify the type of NSDate format it need to convert from the String :

func mapping(map: Map) {
    id <- map["Id"]
    color <- map["Cor"]
    text <- map["Texto"]
    kilometer <- map["Kilometro"]

    let dateFormatter = NSDateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"

    if let dateString = map["Data"].currentValue as? String, let _date = dateFormatter.dateFromString(dateString) {
        date = _date
    } 
}

I hope this help you.

Victor Sigler
  • 23,243
  • 14
  • 88
  • 105
  • 1
    Thanks! It did. I just had to change this line dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" – André Luiz Jul 29 '16 at 22:58
  • This is not a good approach, the Transforms are the correct way to set the data correctly. The built-in DateTransform uses timeIntervalSince1970 so won't work with a formatted date. The best approach is to create your own DateTransform as Rodolfo has done below. – Leon Feb 28 '17 at 09:13
  • @Leon First of all, let me be clear what you mentioned about `DateTransform` uses `timeIntervalSince1970`. The protocol `TransformType` is a protocol to create transformations, how you implement the `transformToJSON(_:)` and the `transformFromJSON(_:)` it's up to you completely. If you see closely the code below it's exactly the same as I did above for the purpose of convert from JSON to `Date` and that was the goal of the question. So please be careful before down vote a question without argument, if was you of course. – Victor Sigler Feb 28 '17 at 14:39
  • If you need to parse to `Date` from several places you can use it the transformation, but again it doesn't mean that you can not encapsulate the behaviour in a function and use it. Everything depends on what context you're using it because you have to implement `transformToJSON` for the transformation every time even if your return `nil` and maybe you never create a `JSON` in your app. I don't downvote solutions because I think another solution have a better approach that another, I don't care your downvote, SO need to start tracking it to dispute vs whoever did it like you wth purpose. – Victor Sigler Feb 28 '17 at 17:55
  • I downvoted your answer because I believe it's not a good approach, that's the entire point of the voting system. You don't need to take it personally. – Leon Mar 01 '17 at 09:18
  • how to use the custom transform when i use like this Mapper().mapArray(JSONString: str) i wanted to use custom transform at this place – Deepakraj Murugesan Jun 20 '18 at 10:41
9

You could just create a TransformType class allowing a dateFormat as parameter:

//  DateFormatTransform.swift

    import Foundation
    import ObjectMapper
    public class DateFormatTransform: TransformType {
        public typealias Object = NSDate
        public typealias JSON = String


    var dateFormat = NSDateFormatter(dateFormat: "yyyy-MM-dd HH:mm:ss")

    convenience init(dateFormat: String) {
        self.init()
        self.dateFormat = NSDateFormatter(dateFormat: dateFormat)
    }

    public func transformFromJSON(value: AnyObject?) -> Object? {
        if let dateString = value as? String {
            return self.dateFormat.dateFromString(dateString)
        }
        return nil
    }
    public func transformToJSON(value: NSDate?) -> JSON? {
        if let date = value {
            return self.dateFormat.stringFromDate(date)
        }
        return nil
    }
}

And use it like this:

func mapping(map: Map) {
    id <- map["Id"]
    color <- map["Cor"]
    text <- map["Texto"]
    kilometer <- map["Kilometro"]
    date    <- (map["Data"], DateFormatTransform(dateFormat: "yyyy-MM-dd"))
}
RodolfoAntonici
  • 1,555
  • 21
  • 34
  • By the way, I've made a gist [DateFormatTransform.swift](https://gist.github.com/RodolfoAntonici/2c446d829ddefc19afe0635ce2977d2d) – RodolfoAntonici Nov 29 '16 at 12:09
  • Can you update your code for newest Swift version? Thanks! – Tà Truhoada Jan 19 '18 at 06:58
  • how to use the custom transform when i use like this Mapper().mapArray(JSONString: str) i wanted to use custom transform at this place – Deepakraj Murugesan Jun 20 '18 at 10:42
  • 1
    @TàTruhoada in Swift 4 you have Codable protocol, way easier to do so. – RodolfoAntonici Jun 20 '18 at 12:38
  • @DeepakrajMurugesan please create an stack overflow question with more context. – RodolfoAntonici Jun 20 '18 at 12:39
  • Hi all does any one worked with object mapper in swift ?? I just wanted to know how to add transformer while you map an array from JsonString !!! I wanted to know how to add custom transformer in this (for example: let a = Mapper().mapArray(JsonString: sample) ) I knew the method in which we add custom transformer at the time of func mapping !! (For example: object <— (map[“object”], customTransformer)) @RodolfoAntonici – Deepakraj Murugesan Jun 21 '18 at 07:34
3

RodolfoAntonici answer rewrited to Swift 4 with usage of SwiftDate library

import SwiftDate
import Foundation
import ObjectMapper
public class DateFormatTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = String


    public func transformFromJSON(_ value: Any?) -> Object? {
        if let dateString = value as? String {
            return dateString.toDate()?.date
        }
        return nil
    }
    public func transformToJSON(_ value: Date?) -> JSON? {
        if let date = value {
            return date.toString()
        }
        return nil
    }
}
Michal Gumny
  • 1,770
  • 1
  • 16
  • 24
1
import Foundation
import ObjectMapper

public class DateFormatTransform: TransformType {
    public typealias Object = Date
    public typealias JSON = Double

    var dateFormat = DateFormatter()

    convenience init(_ format: String) {
        self.init()
        self.dateFormat.dateFormat = format
    }

    open func transformFromJSON(_ value: Any?) -> Date? {
        if let timeInt = value as? Double {
            return Date(timeIntervalSince1970: TimeInterval(timeInt))
        }

        if let timeStr = value as? String {
            return self.dateFormat.date(from: timeStr)
        }

        return nil
    }

    open func transformToJSON(_ value: Date?) -> Double? {
        if let date = value {
            return Double(date.timeIntervalSince1970)
        }
        return nil
    }
}
anhhtbk
  • 89
  • 2
  • 12