Explorar o código

Support NSDecimalNumber setters

Tanner Bennett %!s(int64=6) %!d(string=hai) anos
pai
achega
f9e42aed74

+ 21 - 15
Classes/Editing/ArgumentInputViews/FLEXArgumentInputNumberView.m

@@ -17,6 +17,7 @@
         self.inputTextView.keyboardType = UIKeyboardTypeNumbersAndPunctuation;
         self.targetSize = FLEXArgumentInputViewSizeSmall;
     }
+    
     return self;
 }
 
@@ -33,24 +34,29 @@
 + (BOOL)supportsObjCType:(const char *)type withCurrentValue:(id)value {
     NSParameterAssert(type);
     
-    static NSArray<NSString *> *primitiveTypes = nil;
+    static NSArray<NSString *> *supportedTypes = nil;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
-        primitiveTypes = @[@(@encode(char)),
-                           @(@encode(int)),
-                           @(@encode(short)),
-                           @(@encode(long)),
-                           @(@encode(long long)),
-                           @(@encode(unsigned char)),
-                           @(@encode(unsigned int)),
-                           @(@encode(unsigned short)),
-                           @(@encode(unsigned long)),
-                           @(@encode(unsigned long long)),
-                           @(@encode(float)),
-                           @(@encode(double)),
-                           @(@encode(long double))];
+        supportedTypes = @[
+            @FLEXEncodeClass(NSNumber),
+            @FLEXEncodeClass(NSDecimalNumber),
+            @(@encode(char)),
+            @(@encode(int)),
+            @(@encode(short)),
+            @(@encode(long)),
+            @(@encode(long long)),
+            @(@encode(unsigned char)),
+            @(@encode(unsigned int)),
+            @(@encode(unsigned short)),
+            @(@encode(unsigned long)),
+            @(@encode(unsigned long long)),
+            @(@encode(float)),
+            @(@encode(double)),
+            @(@encode(long double))
+        ];
     });
-    return type && [primitiveTypes containsObject:@(type)];
+    
+    return type && [supportedTypes containsObject:@(type)];
 }
 
 @end

+ 4 - 4
Classes/Editing/FLEXFieldEditorViewController.m

@@ -63,7 +63,7 @@
         action:@selector(getterButtonPressed:)
     ];
     self.toolbarItems = @[
-        UIBarButtonItem.flex_flexibleSpace, self.getterButton, self.setterButton
+        UIBarButtonItem.flex_flexibleSpace, self.getterButton, self.actionButton
     ];
 
     // Configure input view
@@ -75,11 +75,11 @@
 
     // Don't show a "set" button for switches; we mutate when the switch is flipped
     if ([inputView isKindOfClass:[FLEXArgumentInputSwitchView class]]) {
-        self.setterButton.enabled = NO;
-        self.setterButton.title = @"Flip the switch to call the setter";
+        self.actionButton.enabled = NO;
+        self.actionButton.title = @"Flip the switch to call the setter";
         // Put getter button before setter button 
         self.toolbarItems = @[
-            UIBarButtonItem.flex_flexibleSpace, self.setterButton, self.getterButton
+            UIBarButtonItem.flex_flexibleSpace, self.actionButton, self.getterButton
         ];
     }
 }

+ 1 - 1
Classes/Editing/FLEXMethodCallingViewController.m

@@ -41,7 +41,7 @@
 - (void)viewDidLoad {
     [super viewDidLoad];
 
-    self.setterButton.title = @"Call";
+    self.actionButton.title = @"Call";
 
     // Configure field editor view
     self.fieldEditorView.argumentInputViews = [self argumentInputViews];

+ 1 - 1
Classes/Editing/FLEXVariableEditorViewController.h

@@ -24,7 +24,7 @@
 @property (nonatomic, readonly) id target;
 @property (nonatomic, readonly) FLEXFieldEditorView *fieldEditorView;
 /// Subclasses can change the button title via the button's \c title property
-@property (nonatomic, readonly) UIBarButtonItem *setterButton;
+@property (nonatomic, readonly) UIBarButtonItem *actionButton;
 
 - (void)actionButtonPressed:(id)sender;
 

+ 2 - 2
Classes/Editing/FLEXVariableEditorViewController.m

@@ -93,7 +93,7 @@
     self.fieldEditorView.targetDescription = [NSString stringWithFormat:@"%@ %p", [self.target class], self.target];
     [self.scrollView addSubview:self.fieldEditorView];
     
-    _setterButton = [[UIBarButtonItem alloc]
+    _actionButton = [[UIBarButtonItem alloc]
         initWithTitle:@"Set"
         style:UIBarButtonItemStyleDone
         target:self
@@ -101,7 +101,7 @@
     ];
     
     self.navigationController.toolbarHidden = NO;
-    self.toolbarItems = @[UIBarButtonItem.flex_flexibleSpace, self.setterButton];
+    self.toolbarItems = @[UIBarButtonItem.flex_flexibleSpace, self.actionButton];
 }
 
 - (void)viewWillLayoutSubviews {

+ 61 - 48
Classes/Utility/Runtime/FLEXRuntimeUtility.m

@@ -519,51 +519,61 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
     NSNumberFormatter *formatter = [NSNumberFormatter new];
     [formatter setNumberStyle:NSNumberFormatterDecimalStyle];
     NSNumber *number = [formatter numberFromString:inputString];
-
-    // Make sure we box the number with the correct type encoding so it can be properly unboxed later via getValue:
-    NSValue *value = nil;
-    if (strcmp(typeEncoding, @encode(char)) == 0) {
-        char primitiveValue = [number charValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(int)) == 0) {
-        int primitiveValue = [number intValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(short)) == 0) {
-        short primitiveValue = [number shortValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(long)) == 0) {
-        long primitiveValue = [number longValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(long long)) == 0) {
-        long long primitiveValue = [number longLongValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(unsigned char)) == 0) {
-        unsigned char primitiveValue = [number unsignedCharValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(unsigned int)) == 0) {
-        unsigned int primitiveValue = [number unsignedIntValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(unsigned short)) == 0) {
-        unsigned short primitiveValue = [number unsignedShortValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(unsigned long)) == 0) {
-        unsigned long primitiveValue = [number unsignedLongValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(unsigned long long)) == 0) {
-        unsigned long long primitiveValue = [number unsignedLongValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(float)) == 0) {
-        float primitiveValue = [number floatValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(double)) == 0) {
-        double primitiveValue = [number doubleValue];
-        value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
-    } else if (strcmp(typeEncoding, @encode(long double)) == 0) {
-      long double primitiveValue = [number doubleValue];
-      value = [NSValue value:&primitiveValue withObjCType:typeEncoding];
+    
+    // Is the type encoding longer than one character?
+    if (strlen(typeEncoding) > 1) {
+        NSString *type = @(typeEncoding);
+        
+        // Is it NSDecimalNumber or NSNumber?
+        if ([type isEqualToString:@FLEXEncodeClass(NSDecimalNumber)]) {
+            return [NSDecimalNumber decimalNumberWithString:inputString];
+        } else if ([type isEqualToString:@FLEXEncodeClass(NSNumber)]) {
+            return number;
+        }
+        
+        return nil;
     }
-
-    return value;
+    
+    // Type encoding is one character, switch on the type
+    FLEXTypeEncoding type = typeEncoding[0];
+    uint8_t value[32];
+    void *bufferStart = &value[0];
+    
+    // Make sure we box the number with the correct type encoding
+    // so it can be properly unboxed later via getValue:
+    switch (type) {
+        case FLEXTypeEncodingChar:
+            *(char *)bufferStart = number.charValue; break;
+        case FLEXTypeEncodingInt:
+            *(int *)bufferStart = number.intValue; break;
+        case FLEXTypeEncodingShort:
+            *(short *)bufferStart = number.shortValue; break;
+        case FLEXTypeEncodingLong:
+            *(long *)bufferStart = number.longValue; break;
+        case FLEXTypeEncodingLongLong:
+            *(long long *)bufferStart = number.longLongValue; break;
+        case FLEXTypeEncodingUnsignedChar:
+            *(unsigned char *)bufferStart = number.unsignedCharValue; break;
+        case FLEXTypeEncodingUnsignedInt:
+            *(unsigned int *)bufferStart = number.unsignedIntValue; break;
+        case FLEXTypeEncodingUnsignedShort:
+            *(unsigned short *)bufferStart = number.unsignedShortValue; break;
+        case FLEXTypeEncodingUnsignedLong:
+            *(unsigned long *)bufferStart = number.unsignedLongValue; break;
+        case FLEXTypeEncodingUnsignedLongLong:
+            *(unsigned long long *)bufferStart = number.unsignedLongLongValue; break;
+        case FLEXTypeEncodingFloat:
+            *(float *)bufferStart = number.floatValue; break;
+        case FLEXTypeEncodingDouble:
+            *(double *)bufferStart = number.doubleValue; break;
+            
+        case FLEXTypeEncodingLongDouble:
+            // NSNumber does not support long double
+        default:
+            return nil;
+    }
+    
+    return [NSValue value:value withObjCType:typeEncoding];
 }
 
 + (void)enumerateTypesInStructEncoding:(const char *)structEncoding
@@ -826,10 +836,13 @@ const unsigned int kFLEXNumberOfImplicitArgs = 2;
 #undef CASE
 
     NSValue *value = nil;
-    @try {
-        value = [NSValue valueWithBytes:pointer objCType:type];
-    } @catch (NSException *exception) {
-        // Certain type encodings are not supported by valueWithBytes:objCType:. Just fail silently if an exception is thrown.
+    if (FLEXGetSizeAndAlignment(type, nil, nil)) {
+        @try {
+            value = [NSValue valueWithBytes:pointer objCType:type];
+        } @catch (NSException *exception) {
+            // Certain type encodings are not supported by valueWithBytes:objCType:.
+            // Just fail silently if an exception is thrown.
+        }
     }
 
     return value;

+ 2 - 0
Example/UICatalog/Person.h

@@ -17,4 +17,6 @@
 @property (nonatomic, readonly) CGFloat height;
 @property (nonatomic, readonly) NSNumber *numberOfKids;
 
+@property (nonatomic) NSDecimalNumber *netWorth;
+
 @end

+ 9 - 2
Example/UICatalog/Person.m

@@ -16,6 +16,7 @@
     bob->_age = 50;
     bob->_height = 5.8;
     bob->_numberOfKids = @3;
+    bob->_netWorth = [NSDecimalNumber decimalNumberWithString:@"12345.67"];
     return bob;
 }
 
@@ -24,18 +25,24 @@
     [coder encodeInteger:self.age forKey:@"age"];
     [coder encodeDouble:self.height forKey:@"height"];
     [coder encodeObject:self.numberOfKids forKey:@"numberOfKids"];
+    [coder encodeObject:self.netWorth forKey:@"netWorth"];
 }
 
 - (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder {
     self->_name = [coder decodeObjectForKey:@"name"];
     self->_age = [coder decodeIntegerForKey:@"age"];
     self->_height = [coder decodeDoubleForKey:@"height"];
-    self->_numberOfKids= [coder decodeObjectForKey:@"numberOfKids"];
+    self->_numberOfKids = [coder decodeObjectForKey:@"numberOfKids"];
+    self->_netWorth = [coder decodeObjectForKey:@"netWorth"];
     return self;
 }
 
+- (void)setNetWorth:(NSDecimalNumber *)netWorth {
+    _netWorth = netWorth;
+}
+
 - (NSUInteger)hash {
-    return self.name.hash ^ @(self.age).hash ^ self.numberOfKids.hash;
+    return self.name.hash ^ @(self.age).hash ^ self.numberOfKids.hash ^ self.netWorth.hash;
 }
 
 - (BOOL)isEqual:(id)object {