1

I have an issue serialising core data managed object into JSON object. I am using Mantle to do this and this is related NSDate. I am getting this error.

'Invalid type in JSON write (__NSDate)'

This is where this exception is throwing. It is fine until code line 4 (NSDictionary *jDict ....)

        //NSManagedObject from Core Data
        Memo *newMemo = [self fetchMemo:memo.uuid];

        NSError *errorMantle;

        //MTLModel model
        BSMemo *memooo = [MTLManagedObjectAdapter modelOfClass:[BSMemo class] fromManagedObject:newMemo error:&errorMantle];

        NSDictionary *jDict = [MTLJSONAdapter JSONDictionaryFromModel:memooo];

        //Serialising using NSJSONSerialization
        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jDict options:NSJSONWritingPrettyPrinted error:&error];

This is how I am formatting the NSDate in MTLModel

+ (NSValueTransformer *)dateJSONTransformer {
    static dispatch_once_t onceToken;
    static NSDateFormatter *dateFormatter;

    dispatch_once(&onceToken, ^{
        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"YYYY-MM-dd'T'HH:mm:ssZZZ"];

    });

    return [MTLValueTransformer transformerWithBlock:^id(NSString *string) {
        return [dateFormatter dateFromString:string];
    }];
}

+ (NSValueTransformer *)createdJSONTransformer {
    return [self dateJSONTransformer];
}

JSON parsing fine and this is only happen when try to genarate JSON string from core data. I have tried with different date format. But no luck. Could you please help me how to overcome this?

Updated block

+ (NSValueTransformer *)dateJSONTransformer {
    __block dispatch_once_t onceToken;
    __block NSDateFormatter *dateFormatter;

    dispatch_once(&onceToken, ^{

        dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"YYYY-MM-dd'T'HH:mm:ssZZZ"];
    });

    return [MTLValueTransformer transformerWithBlock:^id(NSString *string) {
        return [dateFormatter dateFromString:string];
    }];
}

I am downloading some data from Rest JSON API and save into core data. Because my app has to be work offline. When try to push data back to the server, I need to convert core data in to JSON and attached with HTTP POST. So I am using Mantle to simplify this process.

Chinthaka
  • 966
  • 1
  • 13
  • 42
  • It seems like `BSMemo` has an `NSDate` property – borrrden Aug 04 '14 at 09:48
  • Wrong use of block? this is the issue you are having. – Retro Aug 04 '14 at 09:49
  • @borrrden Yes it is. Is that wrong ? – Chinthaka Aug 04 '14 at 09:49
  • @Retro, could you please explain me what is wrong with use of block ? – Chinthaka Aug 04 '14 at 09:50
  • dateFormatter used in block without __block prefix and its value wont be able to read outside the block, dont use the block make it simple – Retro Aug 04 '14 at 09:53
  • @Retro, I have changed and still no luck. – Chinthaka Aug 04 '14 at 09:58
  • share your updated code? let me ask you what you are trying to do is to get the JASON responce and insert object into Coredata or viseVersa? – Retro Aug 04 '14 at 10:01
  • 1
    Your original code was fine; you don't need `__block` with `static` variables (else all the singleton examples on this site would be wrong). – Droppy Aug 04 '14 at 10:13
  • Well when the error message says invalid type of NSDate, that seems pretty suspect don't you think? What are you doing to inform the serializer that the date transformer should be used to the NSDate property? – borrrden Aug 04 '14 at 10:13
  • @borrrden but how can I convert JSON date string into core data field without using NSDate. If you look at https://github.com/Mantle/Mantle you can see here, it uses NSDate. – Chinthaka Aug 04 '14 at 10:20
  • Also don't use YYYY always use yyyy unless you really want that oddball year format. – ahwulf May 04 '15 at 14:39

3 Answers3

5

I just thought to post above answer in a way we can use when Mantle is used. (hoping this will help others)

+ (NSValueTransformer *)dateJSONTransformer {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"YYYY-MM-dd'T'HH:mm:ssZZZ"];


    return [MTLValueTransformer reversibleTransformerWithForwardBlock:^(NSString *str) {
        NSDate *date = [dateFormatter dateFromString:str];
        return date;
    } reverseBlock:^(NSDate *date) {
        return [dateFormatter stringFromDate:date];
    }];
}

Then call whenever you need to use NSDate as follows

+ (NSValueTransformer *)createdJSONTransformer {
    return [self dateJSONTransformer];
}
Chinthaka
  • 966
  • 1
  • 13
  • 42
4

Try like this

+ (NSDate*)dateJSONTransformer:(NSString*)dateString {
        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
        [dateFormatter setDateFormat:@"YYYY-MM-dd'T'HH:mm:ssZZZ"];
        return [dateFormatter dateFromString:dateString];
}
Retro
  • 3,985
  • 2
  • 17
  • 41
  • 1
    Return type? `NSValueTransformer != NSDate`. – Droppy Aug 04 '14 at 10:10
  • @Retro I have updated your answer. Because there 'string' was unknown. – Chinthaka Aug 04 '14 at 10:27
  • 6
    It's a mystery how this answer has been accepted as correct. It breaks away from the `NSValueTransformer` model of the original code and merely shows how to convert an `NSDate` to an string, and there are a million examples of that on this site. – Droppy Aug 04 '14 at 10:35
  • Indeed - the issue was reverse transformation, from NSDate to NSString – David Snabel-Caunt Aug 04 '14 at 11:46
1

I know it's an old question, but here is my answer.

From de documentation page, we can found how to deal with NSDate in MTLModel :

GHIssue.h

@interface GHIssue : MTLModel <MTLJSONSerializing>

...
@property (nonatomic, copy, readonly) NSDate *updatedAt;
...

@end

GHIssue.m

@implementation GHIssue

+ (NSDateFormatter *)dateFormatter {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
    dateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'Z'";
    return dateFormatter;
}

+ (NSDictionary *)JSONKeyPathsByPropertyKey {
    return @{
        ...
        @"updatedAt": @"updated_at"
    };
}

+ (NSValueTransformer *)updatedAtJSONTransformer {
    return [MTLValueTransformer transformerUsingForwardBlock:^id(NSString *dateString, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter dateFromString:dateString];
    } reverseBlock:^id(NSDate *date, BOOL *success, NSError *__autoreleasing *error) {
        return [self.dateFormatter stringFromDate:date];
    }];
}

Documentation link : https://github.com/Mantle/Mantle#mtlmodel

youssman
  • 1,514
  • 1
  • 17
  • 21