8

The working code for me is something like:

NSNumber *n = @42.42;
CGFloat cgf = 0; 
CFNumberRef cfn = CFBridgingRetain(n);
CFNumberGetValue(cfn, kCFNumberCGFloatType, &cgf);
CFRelease(cfn);

There could be also

CGFloat cgf = (CGFLOAT_IS_DOUBLE) ? [n doubleValue] : [n floatValue];

But this smells even uglier for me.

It seems to me there should be better API for doing such a common thing. Are there any?

mderk
  • 796
  • 4
  • 13

3 Answers3

16

This will get the correct result in any case:

 NSNumber *n = @42.42;
 CGFloat cgf = [n doubleValue];

because CGFloat is either float or double.


NSNumber does not have a CGFloatValue method. You could define one using the toll-free bridge to CFNumberRef:

@interface NSNumber (MyCGFloatValue)
-(CGFloat)myCGFloatValue;
@end

@implementation NSNumber (MyCGFloatValue)
-(CGFloat)myCGFloatValue{
    CGFloat result;
    CFNumberGetValue((__bridge CFNumberRef)(self), kCFNumberCGFloatType, &result);
    return result;
}
@end

or using the C11 feature "Generic selection", where the compiler chooses the appropriate code depending on the type of CGFloat:

@implementation NSNumber (MyCGFloatValue)
-(CGFloat)myCGFloatValue{
    CGFloat result;
    result = _Generic(result,
            double: [self doubleValue],
            float: [self floatValue]);
    return result;
}
@end

And then

NSNumber *n = @42.24;
CGFloat f = [n myCGFloatValue];

but I doubt that it is worth the hassle.

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • 1
    @rounak: Thanks. Actually in this particular case it does not offer much advantage over `CGFloat cgf = [n doubleValue];`, but when you *scan* a CGFloat then it helps to avoid a temporary variable, compare http://stackoverflow.com/questions/20731828/objectivec-test-if-int-is-long-or-not-cgfloat-is-float-or-double. – Martin R Jun 18 '15 at 10:34
4

Just always get the double value. If CGFloat is only a ‘float’ on your machine the double will be instantly truncated, so you don’t care.

Wil Shipley
  • 9,343
  • 35
  • 59
1

The older answers are both correct. Just for my 2¢, here's my implementation:

@implementation NSNumber (TypeConversion)

- (CGFloat)cgFloatValue
{
#if CGFLOAT_IS_DOUBLE
    return self.doubleValue;
#else
    return self.floatValue;
#endif
}

@end

This relies on the definition of CGFLOAT_IS_DOUBLE in CGBase.h for Objective C, or CoreGraphics.h for Swift:

// Don't write this code; it's already included in Foundation :)

#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
# define CGFLOAT_IS_DOUBLE 1
# define CGFLOAT_MIN DBL_MIN
# define CGFLOAT_MAX DBL_MAX
#else
# define CGFLOAT_TYPE float
# define CGFLOAT_IS_DOUBLE 0
# define CGFLOAT_MIN FLT_MIN
# define CGFLOAT_MAX FLT_MAX
#endif

typedef CGFLOAT_TYPE CGFloat;
#define CGFLOAT_DEFINED 1

From CoreGraphics.h

Ky -
  • 30,724
  • 51
  • 192
  • 308