What Is Most Common and Correct Practice to Get a Cgfloat from an Nsnumber

What is most common and correct practice to get a CGFloat from an NSNumber?

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.

Conversion between CGFloat and NSNumber without unnecessary promotion to Double

Update: One can cast a CGFloat value to NSNumber and back:

let c1 = CGFloat(12.3)
let num = c1 as NSNumber
let c2 = num as CGFloat

This preserves the precision of CGFloat and works with Swift 2
and Swift 3.


(Previous answer – far too complicated): There are two solutions that I found. The first uses the toll-free bridging
between NSNumber and CFNumber (as in What is most common and correct practice to get a CGFloat from an NSNumber?
for Objective-C). It uses the fact that CFNumber has a dedicated
conversion mode for CGFloat values:

extension NSNumber {

// CGFloat -> NSNumber
class func numberWithCGFloat(var value: CGFloat) -> NSNumber {
return CFNumberCreate(nil , .CGFloatType, &value)
}

// NSNumber -> CGFloat
var cgFloatValue : CGFloat {
var value : CGFloat = 0
CFNumberGetValue(self, .CGFloatType, &value)
return value
}
}

That is simple and nice. The only drawback: I could not figure out
how to make the constructor an init method instead of a class method.

The second possible solution is a bit longer:

extension NSNumber {

// CGFloat -> NSNumber
private convenience init(doubleOrFloat d : Double) {
self.init(double : d)
}
private convenience init(doubleOrFloat f : Float) {
self.init(float : f)
}
convenience init(cgFloat : CGFloat) {
self.init(doubleOrFloat: cgFloat.native)
}

// NSNumber -> CGFloat
private func doubleOrFloatValue() -> Double {
return self.doubleValue
}
private func doubleOrFloatValue() -> Float {
return self.floatValue
}
var cgFloatValue : CGFloat {
return CGFloat(floatLiteral: doubleOrFloatValue())
}
}

There are two private "helper" init methods with the same external
parameter name doubleOrFloat but different parameter types. From the actual
type of cgFloat.native the compiler determines which one to call
in

    convenience init(cgFloat : CGFloat) {
self.init(doubleOrFloat: cgFloat.native)
}

Same idea in the accessor method. From the type of self.native
the compiler determines which of the two doubleOrFloatValue()
methods to call in

    var cgFloatValue : CGFloat {
return CGFloat(floatLiteral: doubleOrFloatValue())
}

ObjectiveC test if int is long or not / CGFloat is float or double

C11 has introduced a new feature "Generic selection" that can be used to
let the compiler choose the right method, depending on the type of CGFloat.

Written as a NSScanner category method:

@implementation NSScanner (MyCategory)

-(BOOL) myScanCGFloat:(CGFloat *)cgFloatValue
{
return _Generic(*cgFloatValue,
double: [self scanDouble:(double *)cgFloatValue],
float: [self scanFloat:(float *)cgFloatValue]);
}

@end

Remarks:

  • The _Generic keyword is described in "6.5.1.1 Generic selection" of the C11 standard (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf). Another description is here:
    http://www.robertgamble.net/2012/01/c11-generic-selections.html.
  • Selecting the matching code is done by the compiler, not at runtime.
  • The selection checks if CGFloat is compatible to float or double,
    not if the current target architecture is 32-bit or 64-bit.
  • This solution does not depend on any preprocessor macros.
  • As of Xcode 5.0.2, Clang supports the _Generic keyword, even in the default GNU99 mode. I have not tested earlier Xcode/Clang versions.

Previous answer: One possible solution would be do mimic the definition of CGFloat
and let the preprocessor choose the correct version:

CGFloat f;

#if __LP64__
[scanner scanDouble:&f];
#else
[scanner scanFloat:&f];
#endif

Or you define a custom macro:

#if __LP64__
#define scanCGFloat scanDouble
#else
#define scanCGFloat scanFloat
#endif

// ...
CFFloat f;
[scanner scanCGFloat:&f];

Alternatively, use a temporary variable:

double tmp;
[scanner scanDouble:&tmp];
f = tmp;

What's the difference between NSNumber and NSInteger?

The existing answers are useful; adding to them:

Yes, NSUInteger gives twice the range among positive integers as NSInteger, but I think another critical reason to choose between the two is simply to distinguish among cases where negative values simply do not make sense.

Example: the return value of NSArray's count method is an NSUInteger, which makes sense since we cannot have an array with a negative number of elements. When the coder knows it's unsigned, he/she has more freedom to perform operations that might be unreliable in the signed case, including bitwise operations such as shifting. This blog post talks more about signed vs unsigned.

My guess about CGFloat vs NSFloat (which doesn't exist): It might be the case that the designers of the NeXTStep-named code elements simply didn't need to specify too many float values, outside of time intervals. So they gave NSTimeInterval, which is a floating-point type, but that is clearly intended for use with time intervals. And, frankly, it's great to have that type because you know it's always meant to be in seconds without having to deal with a struct. When you move into the graphics world (where Core Graphics lives), suddenly floats are all around you, hovering in the air (haha). So it makes sense to introduce a CGFloat there. This paragraph is all "educated speculation."

Also, just to be clear about why you might use NSInteger etc instead of primitive types: Because this way it's easier to write portable code that takes full advantage of the machine architecture. For example, a CGFloat uses 32 bits on some machines and 64 bits on others, depending largely on how much of an efficiency gap there is on those machines for those sizes. In some cases, there's no real speedup for using 32 bits vs 64 bits, so you might as well use 64 bits. If you've declared things as CGFloat's, you suddenly get that extra precision "for free" when you recompile.

And, as iKenndac has pointed out, NSNumber is a wrapper class for all of these (and other primitive or quasi-primitive types like the BOOL) which enables you to include it in your NSArrays and NSDictionarys, archive them more easily, and do other things that NSObjects can do.

What is the equivalent of NSNotFound for floats

You could use not a number (NaN).

See nan(), nanf() and isnan().

However for these issues, where there is no clearly defined non-value (it's worse with integers), then I prefer to use the following method semantics:

- (BOOL)parseString:(NSString *)string
toFloat:(CGFloat *)value
{
// parse string here
if (parsed_string_ok) {
if (value)
*value = parsedValue;
return YES;
}
return NO;
}

Creating An Array of CGFloat for Gradient Locations

NSGradient's documentation states that locations parameter should be of type const CGFloat*, so you can't use NSArray*. The following should work:

// Allocate a C-array with the same length of colorArray2
CGFloat* pArray = (CGFloat*)malloc(colorArray2.count * sizeof(CGFloat));

for (NSInteger i2 = 0; i2 < colorArray2.count; i2++) {
// Extract location
NSString* p = [[colorArray2 objectAtIndex:i2] objectForKey:key2e];
pArray[i2] = [p doubleValue];
}

// Do whaterver with pArray

...

// Remember to free it

free(pArray);

Swift Double is Not Convertible to CGFloat

Convert the values that need to be CGFloat to a CGFloat.

path.addArcWithCenter(center, radius: CGFloat(radius), startAngle: CGFloat(0.0), endAngle: CGFloat(M_PI) * 2.0, clockwise: true)

startAngle probably shouldn't need to be converted though if you're just passing a literal. Also note that this isn't a C style cast, but actually converting between different Swift Types.

Edit: Looking at your whole function, this works.

func drawCircle() {
// Drawing code
var bounds:CGRect = self.view.bounds
var center = CGPoint()
center.x = bounds.origin.x + bounds.size.width / 2.0
center.y = bounds.origin.y + bounds.size.height / 2.0
var radius = (min(bounds.size.width, bounds.size.height) / 2.0)
var path:UIBezierPath = UIBezierPath()
path.addArcWithCenter(center, radius: CGFloat(radius), startAngle: CGFloat(0.0), endAngle: CGFloat(Float(M_PI) * 2.0), clockwise: true)
path.stroke()
}

What's the difference between using CGFloat and float?

As @weichsel stated, CGFloat is just a typedef for either float or double. You can see for yourself by Command-double-clicking on "CGFloat" in Xcode — it will jump to the CGBase.h header where the typedef is defined. The same approach is used for NSInteger and NSUInteger as well.

These types were introduced to make it easier to write code that works on both 32-bit and 64-bit without modification. However, if all you need is float precision within your own code, you can still use float if you like — it will reduce your memory footprint somewhat. Same goes for integer values.

I suggest you invest the modest time required to make your app 64-bit clean and try running it as such, since most Macs now have 64-bit CPUs and Snow Leopard is fully 64-bit, including the kernel and user applications. Apple's 64-bit Transition Guide for Cocoa is a useful resource.

How to round CGFloat

There are already standard functions with behaviors you might need in <math.h> such as: floorf, ceilf,
roundf, rintf and nearbyintf (lasf 'f' means "float" version, versions without it are "double" versions).

It is better to use standard methods not only because they are standard, but because they work better in edge cases.

2013 Update (jessedc)

iOS is no longer only 32 bit. There are a number of other answers to this question that are now more relevant.

Most answers mention importing tgmath.h

  • https://stackoverflow.com/a/5352779/184130
  • https://stackoverflow.com/a/7695011/184130

Casting CGFloat to Float in Swift

You can use the Float() initializer:

let cgFloat: CGFloat = 3.14159
let someFloat = Float(cgFloat)


Related Topics



Leave a reply



Submit