I'm assigning a CGFloat animatedDistance and I'm getting this error.
Here I'm assigning value to animatedDistance
static const CGFloat KEYBOARD_ANIMATION_DURATION = 0.3;
static const CGFloat LANDSCAPE_KEYBOARD_HEIGHT = 140;
heightFraction is CGFloat as well.
if (orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown)
{
animatedDistance = floor(PORTRAIT_KEYBOARD_HEIGHT * heightFraction);
}
else
{
animatedDistance = floor(LANDSCAPE_KEYBOARD_HEIGHT * heightFraction);
}
What type should be animatedDistace? Can someone help me?
floor returns a double. On some platforms, CGFloat is a float. animatedDistance should be typed as a double (you can cast it to a CGFloat if needed).
Use this to get a vector... CGpoint vector = ccpSub(cgpoint 1, cgpoint 2);
And if you want double/float values then do this:
CGpoint.location
for whatever you are trying to find the coordinates of, then assign a float to CGPoint.location.y and another float to CGPoint.location.x
You need cocos2d for this by the way. I think.
Sounds to me like you declared animatedDistance as holding some kind of pointer, such as NSNumber *, or a structure, such as CGSize. Either way, you can't assign a CGFloat there.
If animatedDistance holds an NSNumber object, create one around the value. Back when you asked this question, the way to do this was [NSNumber numberWithDouble:floor(…)]. Now, you can just use #(floor(…)).
If animatedDistance holds a CGSize or other structure, you're going to have to decide for yourself how to meaningfully convert from the single number you have to the kind of structure you want.
Related
I would like to initially set a CGPoint property to a particular point (middle of screen). Other methods may subsequently wish to change this property. My thoughts were to initialise it if empty in the getter, but I get the message invalid argument type 'struct CGPoint' to unary expression. I also tried using if property == nil or 0 but no joy.
Any thoughts?
-(CGPoint)graphOrigin
{
// initialise to centre of screen if has not been set
if(!_graphOrigin) // this expression is causing the problem
{
CGPoint origin = CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2, self.bounds.origin.y + self.bounds.size.height / 2);
_graphOrigin = origin;
}
return _graphOrigin;
}
A CGPoint is a struct, so you can't set it to nil or NULL (it's not a pointer). In a sense, there's really no "uninitialized" state. Perhaps you could use {0.0, 0.0} to designate an unset CGPoint, but that's also a valid coordinate. Or you could use negative x and y values to flag an "uninitialized" point, since negative values can't be valid drawing points, but that's a bit of a hack, too.
Probably your best bet is to do one of two things:
Store the property as a pointer to a CGPoint. This value can be set to NULL when uninitialized. Of course, you have to worry about mallocing and freeing the value.
Store the CGPoint alongside a BOOL called pointInitialized or somesuch, initially set to NO, but set to YES once the point has been initialized. You can even wrap that up in a struct:
struct {
CGPoint point;
BOOL initialized;
} pointData;
An easier way would be to initialize _graphOrigin to CGRectZero and change your if statement for this:
if (!CGPointEqualToPoint(_graphOrigin, CGPointZero)) {
}
CGPoint does not have an uninitialized state. However, if you consider the point (0, 0) as uninitialized, you could use
if (_graphOrigin.x == 0 && _graphOrigin.y == 0)
{
...
This works because when an Objective-C instance is initialized, all its ivar are cleared to bits of zero, which in the CGFloat representation is 0.0.
(Note: The == is fine here even if the operands are CGFloat because we want to compare with the an exact bit pattern (ignoring the issue of -0))
Since CGPointZero (0,0) and any other value you give a point may exist in your context
you may want to initialize an NSValue with your point using:
NSValue *pointVal = [NSValue valueWithCGPoint:point];
You could do this based on some condition and then later test the NSValue for nil.
NSValue can also be added to an array which would allow you to have an array of points should you need.
To get the point later simply use:
CGPoint point = [pointVal CGPointValue];
static CGPoint kInvalidPoint = {.x = NSIntegerMax, .y = NSIntegerMax};
#implementation MyClass
- init()
{
self = [super init];
if (self) {
_oldPoint = kInvalidPoint;
}
return self;
}
- (void)foo
{
if (CGPointEqualToPoint(self.oldPoint, kInvalidPoint)) {
// Invalid point.
return;
}
}
#end
Create two CGPoint properties, that way they are both "uninitialized". Set one of them and use the second one to check whether or not they are equal.
#interface ClassName ()
#property (nonatomic) CGPoint point1;
#property (nonatomic) CGPoint point2;
#end
#implementation ClassName
self.point1 = CGPointMake(69.0f, 180.0f); //arbitrary numbers
//if not equal, then if statement proceeds
if (!CGPointEqualToPoint(self.point1, self.point2) {
//your code here
}
#end
Idk if you'd consider this way hackish though. And I know your question was already answered, but I had kinda the same dilemma till I thought of this.
Is there a way to make nullable struct in objective C like in C# you can use Nullable<T>?
I need a CGPoint to be null when there is no applicable value. I cannot allocate a random invalid value for this like (-5000, -5000) because all values are valid for this.
What if you define a CGPoint using CGPointMake(NAN, NAN) similar to CGRectNull? Surely with NAN's for coordinates, it's not still a valid point.
CGPoint is a struct and that has some different rules in objective-c than you might think. You should consider reading about structs in objective-c.
The way this is done most of the time is to wrap the struct in an object because that object can be set to null. NSValue will wrap a CGPoint.
NSValue * v = [NSValue valueWithPoint:CGPointMake(1,9)];
NSVAlue * vNull = [NSValue valueWithPointer:nil];
if([v objCType] == #encode(CGPoint)) printf("v is an CGPoint");
CGPoint is a enum, not an object. You can use CGPointZero, or you can wrap all of your points inside of NSValue, which are objects and can be nil.
There is also nothing stopping you creating your own struct based on CGPoint, similar to how C# 2 works.
struct NilableCGPoint { bool isNil; CGPoint point; }
Examples of use:
// No value (nil)
NilableCGPoint myNilablePoint.point = CGPointZero;
myPoint.isNil = YES;
// Value of (0,0)
NilableCGPoint myNilablePoint.point = CGPointZero;
myPoint.isNil = NO;
// Value of (100, 50)
NilableCGPoint myNilablePoint.point = CGPointMake(100, 50);
myPoint.isNil = NO;
I want to make an method which takes an CGFloat by reference.
Could I do something like this?
- (void)doStuff:(CGFloat*)floatPointer
I guess this must look different than other object pointers which have two of those stars. Also I'm not sure if I must do something like:
- (void)doStuff:(const CGFloat*)floatPointer
And of course, no idea how to assign an CGFloat value to that floatPointer. Maybe &floatPointer = 5.0f; ?
Could someone give some examples and explain these? Would be great!
objective-c is still c, so
-(void) doStuff (CGFloat *) f
{
*f = 1.2;
}
call with
CGFloat f = 1.0;
[self doStuff:&f];
If you are passing a CGFloat by reference, then accessing it is simple:
- (void)doStuff:(CGFloat*)floatPointer {
*floatPointer = 5.0f;
}
Explanation: as you are getting a reference, you need to de-reference the pointer (with the *) to get or set the value.
if you (hate pointers and ;-) prefer objective-c++ pass by reference, the following is an alternative:
-(void) doStuffPlusPlus:(CGFloat &) f
{
f = 1.3;
}
call by
CGFloat abc = 1.0;
[self doStuffPlusPlus:abc];
and, you need to rename the source filename from ???.m to ???.mm
I'm attempting to define an extremely simple utility method that will save me from having to use a calculator to define RGB values as percentages. When I look into Apple's sample code called "QuartzCache", in the DrawView.m file, line 96, I see this:
float whiteColor[4] = {1, 1, 1, 1};
However, when I attempt to created a method like the following, the compiler hates me. A half-hour of intensive Googling has not produced any help.
+(float[])percentagesRGBArray:(float[])rgbArray{
float red = rgbArray[0];
float green = rgbArray[1];
float blue = rgbArray[2];
float alpha = rgbArray[3];
red = red/255;
green = green/255;
blue = blue/255;
alpha = alpha;
float percentagesRGBArray[4] = {red, green, blue, alpha};
return percentagesRGBArray;
}
What is the proper way to define such a method? What am I doing wrong here?
Define a struct that contains all of the components, or wrap up each individual component in an NSNumber. Alternatively, use an NSColor instance to contain your colour components.
struct way:
typedef struct
{
float red;
float green;
float blue;
float alpha;
} MyColor;
- (MyColor) percentagesRGBArray:(MyColor) incoming
{
MyColor result;
result.red = incoming.red / 255;
result.green = incoming.green / 255;
result.blue = incoming.blue / 255;
result.alpha = incoming.alpha;
return result;
}
NSNumber way:
- (NSArray *) percentagesRGBArray:(float[]) rgbArray
{
NSNumber *red = [NSNumber numberWithFloat:rgbArray[0] / 255];
NSNumber *green = [NSNumber numberWithFloat:rgbArray[1] / 255];
NSNumber *blue = [NSNumber numberWithFloat:rgbArray[2] / 255];
NSNumber *alpha = [NSNumber numberWithFloat:rgbArray[3]];
return [NSArray arrayWithObjects:red, green, blue, alpha, nil];
}
NSColor way:
- (NSColor *) percentagesRGBArray:(float[]) rgbArray
{
CGFloat red = rgbArray[0] / 255;
CGFloat green = rgbArray[1] / 255;
CGFloat blue = rgbArray[2] / 255;
CGFloat alpha = rgbArray[3];
return [NSColor colorWithDeviceRed:red
green:green
blue:blue
alpha:alpha];
}
Normally, you would use Cocoa's NSColor class to handle this sort of thing, but it looks like you are doing something a little more low-level.
In that case, I would do the following:
typedef struct
{
float red;
float green;
float blue;
float alpha;
}
RGBAData;
RGBAData ConvertRGBAToPercentages(const RGBAData source)
{
RGBAData percentages;
percentages.red = source.red/255;
percentages.green = source.green/255;
percentages.blue = source.blue/255;
percentages.alpha = source.alpha/255;
return percentages;
}
To be used as follows:
RGBAData original = { 0xFF, 0xFF, 0x00, 0x80 }; // 50% transparent yellow
RGBAData percents = ConvertRGBAToPercentages(original);
Both e.James and dreamlax's answers give good approaches for doing this. But to answer what was wrong with your original code:
Basically, it has to do with how C arrays work. An array is essentially equivalent to a pointer to its first element. In fact, when you pass an array to a function, it decays into a pointer. You're still allowed to name the argument float myArray[4] (you have to declare the number of elements) just to make it clear that the pointer is supposed to be to an array of 4 elements — but you're still getting a pointer. Now consider the return value. What are you returning? We already established that you can't return an array by value, because it decays into a pointer. But even if you change the return type to be a pointer, it still won't work, because the array will have gone out of scope once the function returns. In order to return an array, you have to malloc the memory, and then you're responsible for freeing it later.
This is why you should avoid working with C arrays when at all possible. They're really low-level and fiddly. Even when you do use them, it's usually a good idea to hide them behind an API that takes care of the low-level details for you.
I think i'm late) but i have just found this thread.
the C way to do this is to create an array before invoking a function;
+(void) percentagesRGBArray:(float[])inArray toArray:(float*)outArray {
...
}
float array1[4];
float array2[4];
[MyClass percentagesRGBArray:array1 toArray:array2];
In CABasicAnimation.fromValue I want to convert a CGPoint to a "class" so I used NSValue valueWithPoint but in device mode or simulator one is not working...
need to use NSMakePoint or CGPointMake if in device or simulator.
There is a UIKit addition to NSValue that defines a function
+ (NSValue *)valueWithCGPoint:(CGPoint)point
See iPhone doc
#ashcatch 's answer is very helpful, but consider that those methods from addition copy values, when native NSValue methods store pointers! Here is my code checking it:
CGPoint point = CGPointMake(2, 4);
NSValue *val = [NSValue valueWithCGPoint:point];
point.x = 10;
CGPoint newPoint = [val CGPointValue];
here newPoint.x = 2; point.x = 10
CGPoint point = CGPointMake(2, 4);
NSValue *val = [NSValue valueWithPointer:&point];
point.x = 10;
CGPoint *newPoint = [val pointerValue];
here newPoint.x = 10; point.x = 10
In Swift, you can change a value like this:
var pointValueare = CGPointMake(30,30)
NSValue(CGPoint: pointValueare)
&(cgpoint) -> get a reference (address) to cgpoint
(NSPoint *)&(cgpoint) -> casts that reference to an NSPoint pointer
*(NSPoint )(cgpoint) -> dereferences that NSPoint pointer to return an NSPoint to make the return type happy
In Swift the static method is change to an initialiser method:
var pointValue = CGPointMake(10,10)
NSValue(CGPoint: pointValue)
If you are using a recent-ish version of Xcode (post 2015), you can adopt the modern Objective-C syntax for this. You just need to wrap your CGPoint in #():
CGPoint primitivePoint = CGPointMake(4, 6);
NSValue *wrappedPoint = #(primitivePoint);
Under the hood the compiler will call +[NSValue valueWithCGPoint:] for you.
https://developer.apple.com/library/archive/releasenotes/ObjectiveC/ModernizationObjC/AdoptingModernObjective-C/AdoptingModernObjective-C.html
Don't think of it as "converting" your point-- NSValue is a wrapper class that holds primitive structs like NSPoint. Anyway, here's the function you need. It's part of Cocoa, but not Cocoa Touch. You can add the entire function to your project, or just do the same conversion wherever you need it.
NSPoint NSPointFromCGPoint(CGPoint cgpoint) {
return (*(NSPoint *)&(cgpoint));
}