Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestKit does not map BOOL in 64 bit simulator

Tags:

ios

restkit

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`.}"
 )}
like image 246
Mika Avatar asked Mar 21 '23 08:03

Mika


2 Answers

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.

like image 88
sergio Avatar answered Mar 29 '23 13:03

sergio


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;
}
like image 44
iwasrobbed Avatar answered Mar 29 '23 13:03

iwasrobbed