Lvalue required as left operand of assignment - objective-c

I want to assign suitSize to scrollButton what I'm doing wrong?
UIView *scrollButton = [suitScrollView viewWithTag:1];
CGSize suitSize =CGSizeMake(10.0f,10.0f);
(UIButton *)scrollButton.frame.size=suitSize;

frame is a property, not a structure field. You can't assign to a subfield of it. Think of it as a function call; dot syntax for properties is convenience.
This:
scrollButton.frame.size = suitSize;
Is equivalent to:
[scrollButton frame].size = suitSize;
Which doesn't work; it doesn't make any sense to assign to a field of a function result.
Instead, do this:
CGFrame theFrame = [scrollButton frame];
theFrame.size = suitSize;
[scrollButton setFrame: theFrame];
Or, if you prefer:
CGFrame theFrame = scrollButton.frame;
theFrame.size = suitSize;
scrollButton.frame = theFrame;
Note that casting the scrollButton to a UIButton isn't necessary; UIViews have frames, too.

Don't mix the property accessors and struct field access on the left side of an assignment.
An lvalue is an expression that can appear on the left side of an assignment. When you mixstructs and properties, the resulting expression is not an lvalue, so you can't use it on the left side of an assignment.
(UIButton *)scrollButton.frame.size=suitSize;
The scrollButton.frame part is a property access. The .size part accesses a field of the frame structure. Steven Fisher's example above is the right way to break up the code to avoid the problem.

When dealing with properties that are structs you cannot directly set sub-structs in this manner...
(UIButton *)scrollButton.frame.size=suitSize;
The frame property of the UIButton is a CGRect struct. The compiler sees your .size access and tries to resolve it to a setter which does not exist. Instead of mixing struct member access with property accessors you need to deal with the CGRect struct type as a whole...
CGRect frame = (UIButton *)scrollButton.frame;
frame.size = CGSizeMake(100, 100);
(UIButton *)scrollButton.frame = frame;

Related

Cocos2d getChildByTag Not Returning Sprite

I am trying to change the text of a CCLabelTTF in cocos2d xcode (objective-c). I am setting the label like this:
CCLabelTTF *progressLBL = [CCLabelTTF labelWithString:#"connecting..." fontName:#"Marker Felt" fontSize:10];
progressLBL.position = ccp( width + 4, (s.height) - hight - 15);
CCMenu *menuHolder = [CCMenu menuWithItems:publishingLinesButton , nil];
[self addChild:progressLBL z:10 tag:cnt];
s is just the hight and width of the screen and cnt if an integer that goes up each time from 1 to 13. Then about 5 seconds after the label is created i get it like this:
CCLabelTTF *progressLBL = (CCLabelTTF *)[self getChildByTag:[dataInfo objectAtIndex:0]];
progressLBL.string = #"Updated";
dataInfo is an array and the object at index 0 is an integer. However when i run this code the labels are not changed. I have also tried:
CCLabelTTF *progressLBL = (CCLabelTTF *)[self getChildByTag:4];
But still the label is not changed.
Thanks, Sorry for wasting your time if this is something supper simple.
The fact is that an Objective-C array contains objects, it cannot contain primitive types. The tag argument is an integer, and you're passing an object instead (probably you got a compiler warning). I suppose that the object is a NSNumber, so you should take it's value calling the intValue accessor:
CCLabelTTF *progressLBL = (CCLabelTTF *)[self getChildByTag:[dataInfo objectAtIndex:0].intValue ];
Which with the newer compilers syntax can be translated like this:
CCLabelTTF *progressLBL = (CCLabelTTF *)[self getChildByTag: dataInfo[0].intValue ];

CGRectMake alternative

I have seen this alternative to using CGRectMake() in order to initialise a CGRect variable:
CGRect frame = (CGRect){0,0,10,10};
My question is, how does CGRect frame = (CGRect){0,0,10,10}; work? What's going on behind the scenes? It looks like a c-style array is being initialised ({x,y,w,h}) which is then being cast as a CGRect struct - is this correct? If so, how is it possible to cast a c style array as a struct?
N.B. I am not asking if it is appropriate to use the above alternative to CGRectMake(), I only wish to understand why/how it works.
It's a so-called compound literal. You can read more about them in this article by Mike Ash: Friday Q&A 2011-02-18: Compound Literals.
U can use like this:
CGRect rect = CGRectFromString(#"{{0, 0}, {612, 892}}"); // it contents { CGPoint origin;CGSize size;};
NSLog(#"rect : %#",NSStringFromCGRect(rect));
Check this:
CGPoint origin = {10, 20};
CGSize size = {100, 200};
CGRect rect = {origin, size};

How do I check if a CGPoint has been initialised?

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.

Nullable in objective c

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;

setting and using obj-c CGPoint, CGRect, and others

I have three questions surrounding what I think is the topic of structs in obj-c
1) Why is it that I often (or always) cannot take a member var that is a CGPoint or a CGRect and set the values one by one? I find I have to do:
CGPoint point;
point.x = someValue;
point.y = someOtherValue;
obj.myPoint = point;
instead of simply obj.myPoint.x = someValue etc.
2) Is this behavior that is consistent across all structs in obj-c?
3) Is there an easy way to add two CGPoints? It seems like there should already be, but I couldn't find one. I thought it'd be cumbersome if I'd have to use a temporary CGPoint to accumulate values between two CGPoints before setting the dest var to the temp var (because of not being able to just do pointA.x += pointB.x (same for y).
1) From #sb in an answer to Cocoa Objective-c Property C structure assign fails
That won't accomplish anything, because [t member] returns a struct, which is an "r-value", ie. a value that's only valid for use on the right-hand side of an assignment. It has a value, but it's meaningless to try to change that value.
Basically you just have to live with the fact that you can't set the fields of struct directly when returned from a function.
2) Yes
3) Unfortunately I don't think there is a built-in convenience method for adding two CGPoint. If you find your self doing this frequently you can make your own:
CGPoint CGPointAdd(CGPoint p1, CGPoint p2)
{
return CGPointMake(p1.x + p2.x, p1.y + p2.y);
}
and then use it like:
obj.pointA = CGPointAdd(obj.pointA, pointB);
not as elegant as obj.pointA.X += ... but sometimes life isn't fair.
This is perfectly normal. The 'obj' owns that var and has getters and setters, you can not modify parts of that variable.
The best thing to do is copy the struct and modify whatever you need.
Also note you can use the CGPointMake(x, y) function (and the same for all CG structs), which is much easier.
To update this is easiest:
CGPoint point = obj.myPoint;
point.x += 10.0f;
obj.myPoint = point;
Obj-C 2.0 hides the getters and setters which looks like this:
CGPoint point = [obj myPoint];
point.x += 10.0f;
[obj setMyPoint:point];