I need help understanding the error below.
I have a BOOL in my NSObject defined as:
@property (nonatomic) BOOL isOpen;
In my reskit class I use:
[mapping addAttributeMappingsFromDictionary:@{......
@"isOpen": @"isOpen"
......}];
Has worked perfectly for weeks for all my tests using my iPhone4S and an original iPhone5. As a last test I tested on the simulator on a 64 bit device and I get the following error:
restkit.object_mapping:RKMappingOperation.m:440 Failed transformation of value at keyPath 'isOpen' to representation of type '__NSCFBoolean': Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3002 "Failed transformation of value '1' to __NSCFBoolean: none of the 2 value transformers consulted were successful." UserInfo=0x10cba1c00 {NSLocalizedDescription=Failed transformation of value '1' to __NSCFBoolean: none of the 2 value transformers consulted were successful., detailedErrors=(
"Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3002 \"The given value is not already an instance of '__NSCFBoolean'\" UserInfo=0x10cb86d30 {NSLocalizedDescription=The given value is not already an instance of '__NSCFBoolean'}",
"Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3000 \"Expected an `inputValue` of type `NSNull`, but got a `__NSCFNumber`.\" UserInfo=0x10cbeb400 {NSLocalizedDescription=Expected an `inputValue` of type `NSNull`, but got a `__NSCFNumber`.}"
)}
As Mikael says, there is some glitch in RestKit running on 64 bit platform preventing the default conversion from NSNumber to BOOL (and viceversa).
There is, though, a way to make this work thanks to RestKit Value Transformers modular architecture. So, you just create a dedicated transformer class and register it with RestKit default transformer.
This is how the transformer could look like:
@interface RKCustomBOOLTransformer : NSObject <RKValueTransforming>
+ (instancetype)defaultTransformer;
@end
@implementation RKCustomBOOLTransformer
+ (instancetype)defaultTransformer {
return [RKCustomBOOLTransformer new];
}
- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass {
return ([inputValueClass isSubclassOfClass:[NSNumber class]] &&
[outputValueClass isSubclassOfClass:[NSNumber class]]);
}
- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error {
RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ [NSNumber class] ]), error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ [NSNumber class] ]), error);
if (strcmp([inputValue objCType], @encode(BOOL)) == 0) {
*outputValue = inputValue?@(1):@(0);
} else if (strcmp([inputValue objCType], @encode(int)) == 0) {
*outputValue = ([inputValue intValue] == 0) ? @(NO) : @(YES);
}
return YES;
}
@end
You register it like this:
[[RKValueTransformer defaultValueTransformer]
insertValueTransformer:[RKCustomBOOLTransformer defaultTransformer] atIndex:0];
Take care of doing the registration before defining your mappings.
I had to do something along the same lines as sergio's answer, but in my case the JSON was formed similar to: "private":0
:
@implementation RPBooleanTransformer
+ (instancetype)defaultTransformer {
return [[RPBooleanTransformer alloc] init];
}
- (BOOL)validateTransformationFromClass:(Class)inputValueClass toClass:(Class)outputValueClass {
return ([inputValueClass isSubclassOfClass:NSClassFromString(@"__NSCFNumber")] &&
[outputValueClass isSubclassOfClass:NSClassFromString(@"__NSCFBoolean")]);
}
- (BOOL)transformValue:(id)inputValue toValue:(id *)outputValue ofClass:(Class)outputValueClass error:(NSError **)error {
RKValueTransformerTestInputValueIsKindOfClass(inputValue, (@[ NSClassFromString(@"__NSCFNumber") ]), error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, (@[ NSClassFromString(@"__NSCFBoolean") ]), error);
if ([inputValue isKindOfClass:NSClassFromString(@"__NSCFNumber")]) {
*outputValue = ([inputValue boolValue] == YES) ? @(YES) : @(NO);
} else if ([inputValue isKindOfClass:NSClassFromString(@"__NSCFBoolean")]) {
*outputValue = [inputValue isEqual:@(YES)] ? @1 : @0;
}
return YES;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With