21

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;

}

Alan
  • 4,325
  • 3
  • 21
  • 25

6 Answers6

31

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:

  1. 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.
  2. 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;
    
mipadi
  • 398,885
  • 90
  • 523
  • 479
  • 4
    I like this answer much more, because **{0.0, 0.0}** is a really existing and valid coordinate. Using that as a null-point might break your program logic. – Stas May 19 '12 at 16:20
  • 1
    Setting the CGPoint to -1,-1 seems less hackish to me than the other suggestions. Adding a separate boolean variable seems like a Single Point of Truth violation -- it will give an incorrect result if it's not updated whenever the variable's state is changed. – arlomedia Jan 09 '14 at 00:16
  • Probably horrible programming, but if you're desperate you could always pass {NAN,NAN} as coordinates to your CGPoint. –  Oct 27 '15 at 21:36
22

An easier way would be to initialize _graphOrigin to CGRectZero and change your if statement for this:

if (!CGPointEqualToPoint(_graphOrigin, CGPointZero)) {  

}
François Marceau
  • 592
  • 1
  • 4
  • 10
11

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))

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
5

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]; 
Zigglzworth
  • 6,645
  • 9
  • 68
  • 107
  • This solution is very useful for an IF statement checking if the 'point' struct exists. You can check if pointVal is nil (... if (pointVal)...), which you cannot do with point (... if (point)... gives you an 'invalid operand' error). – GlennRay Jun 16 '17 at 21:21
1
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
Sergey Demchenko
  • 2,924
  • 1
  • 24
  • 26
0

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.

Tony
  • 31
  • 7