I am using RestKit to talk to my JSON endpoints. The endpoint returns a UNIX timestamp in 'number of milliseconds'. But RestKit's default transformer assumes that it is 'number of seconds' and I get a wrong value in NSDate.
So I looked around, and found that I need to use a custom valueTransformer to tell RestKit how to transform my timestamp. Here's the code I have.
+ (RKBlockValueTransformer*) timeIntervalInMillisecondsSince1970TwoWayTransformer {
return [RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) {
// This transformer handles `NSNumber` <-> `NSDate` transformations
NSLog(@"checking new transformer");
return (([sourceClass isSubclassOfClass:[NSNumber class]] && [destinationClass isSubclassOfClass:[NSDate class]]) ||
([sourceClass isSubclassOfClass:[NSDate class]] && [destinationClass isSubclassOfClass:[NSNumber class]]));
} transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, __unsafe_unretained Class outputValueClass, NSError *__autoreleasing *error) {
NSLog(@"transforming");
RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSNumber class], [NSDate class] ]), error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSNumber class], [NSDate class] ]), error);
if ([outputValueClass isSubclassOfClass:[NSDate class]]) {
if ([inputValue isKindOfClass:[NSNumber class]]) {
*outputValue = [NSDate dateWithTimeIntervalSince1970:[inputValue doubleValue] / 1000];
}
} else if ([outputValueClass isSubclassOfClass:[NSNumber class]]) {
*outputValue = @((NSInteger)[inputValue timeIntervalSince1970] * 1000);
}
return YES;
}];
}
Then I am adding this transformer to RestKit's default transformer.
RKValueTransformer* transformer = [self timeIntervalInMillisecondsSince1970TwoWayTransformer];
[[RKValueTransformer defaultValueTransformer] addValueTransformer:transformer];
But, my transformer never gets called. The NSLog
statement I wrote in it never gets executed!
So then I tried this -- writing a transformer on the attributeMapping like this:
RKValueTransformer* transformer = [self timeIntervalInMillisecondsSince1970TwoWayTransformer];
RKAttributeMapping *tokenExpiryMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"access_token_expiration" toKeyPath:@"accessTokenExpirationDate"];
tokenExpiryMapping.valueTransformer = transformer;
[userMapping addPropertyMapping:tokenExpiryMapping];
But the code doesn't compile when I do this. It says "Property valueTransformer not found on object of type 'RKAttributeMapping *'". I don't understand this. All the examples I have seen on the internet, including the one with RestKit's documentation say the same thing. All examples set the valueTransformer
property of the AttributeMapping
object. Even the RestKit Class Reference says that I can set it. But then why doesn't it compile?
So I managed to finally figure out what the problem was.
My podfile was configured to use RestKit 0.20.3. And then I had added RKValueTransformers
as another Pod. However, RestKit 0.20.3 and earlier come with their own version of RKValueTransformer (.h and .m) files. And those older versions of RestKit doesn't support adding your own Transformers, because it doesn't make use of the newer RKValueTransformers
library.
When I upgraded my RestKit version to the newest version (actually anything above 0.21.0 would work), things started working fine. I didn't need to add the pod RKValueTransformers, because it gets added automatically as a dependency of RestKit.