2014-01-20 2 views
5

Der Arbeitscode ist für mich so etwas wie:Was ist die gängigste und korrekte Vorgehensweise, um einen CGFloat von einer NSNummer zu erhalten?

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

Es gibt auch

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

sein könnte Aber das riecht für mich noch hässlicher.

Es scheint mir, es sollte bessere API für eine solche gemeinsame Sache sein. Sind da irgendwelche?

Antwort

10

Dies wird das richtige Ergebnis in jedem Fall erhalten:

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

weil CGFloat entweder float oder double ist.


NSNumber keine CGFloatValue Methode haben.

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

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

oder mit Hilfe des C11-Funktion „Generic selection“, wo der Compiler wählt der geeignete Code je nach der Art der CGFloat:

Sie könnten ein mit der gebührenfreien Brücke CFNumberRef definieren
@implementation NSNumber (MyCGFloatValue) 
-(CGFloat)myCGFloatValue{ 
    CGFloat result; 
    result = _Generic(result, 
      double: [self doubleValue], 
      float: [self floatValue]); 
    return result; 
} 
@end 

Und dann

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

aber ich bezweifle, dass es sich lohnt.

+0

TIL über '_Generic'. Das sieht wirklich cool aus, danke! – rounak

+1

@rounak: Danke. Tatsächlich bietet es in diesem speziellen Fall keinen großen Vorteil gegenüber 'CGFloat cgf = [n doubleValue];', aber wenn Sie * einen CGFloat * scannen, dann hilft es, eine temporäre Variable zu vermeiden, vergleiche http://stackoverflow.com/questions/20731828/objecc-test-if-int-ist-lang-oder-nicht-cgfloat-ist-float-oder-double. –

3

Immer nur den doppelten Wert erhalten. Wenn CGFloat nur ein "Float" auf Ihrem Computer ist, wird das Double sofort abgeschnitten, also ist es Ihnen egal.

1

Die älteren Antworten sind beide korrekt. Nur für meine 2 ¢, hier ist meine Implementierung:

@implementation NSNumber (TypeConversion) 

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

@end 

Dies beruht auf der Definition von CGFLOAT_IS_DOUBLE in CGBase.h für Objective C oder CoreGraphics.h für 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 

Von CoreGraphics.h