Passing new struct as parameter - objective-c

I have a function like so:
- (void)addBalloon:(COLOR)color:(VELOCITY)velocity:(LOCATION)location
Where COLOR is an enum, and VELOCITY and LOCATION are structs defined in a constants header file..
VELOCITY and LOCATION both store two ints, x and y.
When calling this method, I would call it like so:
VELOCITY vel;
LOCATION loc;
vel.x = 100.0;
vel.y = 0.0;
loc.x = 10.0;
loc.y = 10.0;
[self addBalloon:Red:vel:loc];
But to me, this seems disorganized. I would like to call the function directly in one line while creating the struct on the line..
Here is my question: I'm not sure if this can be done using #define.. but if it can't.. is the only other viable option creating a function that returns VELOCITY or LOCATION and takes inputs x, and y?
I would like to do something like the following:
[self addBalloon:Red:VELOCITY(100.0, 0.0):LOCATION(10.0, 10.0)];

You can use the C99 syntax for designated initialisers:
[self addBalloon:Red:(VELOCITY){100.0, 0.0}:(LOCATION){10.0, 10.0}];
or
[self addBalloon:Red:(VELOCITY){.x=100.0, .y=0.0}:(LOCATION){.x=10.0, .y=10.0}];

Related

What is "CG_INLINE CGRect" definition in Objective C called?

What is the following structure called in Objective C,
CG_INLINE CGRect
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
CGRect rect;
rect.origin.x = x; rect.origin.y = y;
rect.size.width = width; rect.size.height = height;
return rect;
}
I want to create my own definition for making an object that would hold multiple parameters that I pass. Currently I am using a static method within a class that would take multiple parameters and return an object. But this syntax of CGRectMake is a perfect solution i could use. What is the structure actually called in Objective C syntax?
CGRectMake() is a function. Functions are a C language feature, not unique to Objective-C. Therefore, they don't have a special name in Objective-C. They're called C functions.
If you're asking about this seemingly cryptic syntax:
CG_INLINE CGRect
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
CG_INLINE is a special token that does nothing more than declare a function as inline. You can find a description of CG_INLINE in this question:
What does CG_INLINE do?
CGRect is the return type. The line break that follows is mere whitespace; it's a somewhat common code-formatting convention in C to break a line after the return type in a function definition.
CGRectMake is the function name.
The rest that follows is its argument list and function body.
If you want to create a function, you can place its definition in your .m file, with a corresponding forward declaration in the .h file.

List two Objective-C dot operators in an NSLog statement?

If I want to print two values using an Objective-C dot operator with the NSLog statement, I would do it like so:
NSLog(#"The height is %i and the width is %i", myRect.height, myRect.width);
But is there any way in which I can list the height and width only metioning myRect once? After all, they're from the the same object and class. Is there some sort of shorthand like so?
NSLog(#"The height is %i and the width is %i", myRect.height, width);
PS. I know that the above code doesn't work, but am I missing something that would work similar to the code above?
You could write your own helper routine:
void ReportDimensions(rectangle_t myRect) {
NSLog(#"The height is %i and the width is %i", myRect.height, myRect.width);
return;
}
Then you can use it in your code like this:
rectangle_t r = /* rectangle from somewhere */
ReportDimensions(r);
This saves you from re-typing the string and object name over and over again. You could even add this as a method of a rectangle class if you wanted to write this instead:
r.ReportDimensions();
Assuming myRect is of type CGSize (since that's the only built-in type that has immediate height and width members), then YES there is:
NSLog(#"myRect: %#", NSStringFromCGSize(myRect));
There's also NSStringFromCGSize, NSStringFromCGPoint, etc. These are built-in functions that do the member extraction for you.
No, there's no shorthand.
Unspoken convention when accessing many fields from one object could be using really short names for the local variable of the object, so you only get eg r.width, r.height.

Pass struct to performSelector:withObject:afterDelay:

I have a struct Position, like this:
typedef struct Position { int x, y; } Position;
How may I pass it in NSObject performSelector:withObject:afterDelay:? Like this:
Position pos;
pos.x = pos.y = 1;
[self performSelector:#selector(foo:)
withObject:pos // ERROR
afterDelay:5.0f];
EDIT: changed code to fix typo
Uhm.. use a CGPoint and something like
[self performSelector:#selector(foo:)
withObject:[NSValue valueWithCGPoint:CGPointMake(pos.x, pos.y)]
afterDelay:5.0f];
And read it again as
NSValue v;
CGPoint point = [v CGPointValue];
or leave the Position class away completely, CGPoint does the same
You could wrap your custom type using NSValue class. The error is that you didn't provide an object reference to the method.
Try using NSValue's +(NSValue *)valueWithBytes:(const void *)value objCType:(const char *)type; class method. On the other side you can retrieve the value using -(void)getValue:(void *)buffer;.
preformSelector:withObject: accepts only objects as parameters, hence you'll have to implement your foo: method to accept an object. There are two ways to pass the struct as an object:
create a struct-like object or
wrap it into NSValue and unwrap it in the method.
Full answer, based on user756245's (which doesn't tell you how to use it, not a great deal of help). Also, Apple suggests you use a slightly different method these days, IIRC:
typedef myStruct { int a; } myStruct;
myStruct aLocalPointer = ... assign to it
[self performSelector:#selector(myOtherMethod:) withObject:[NSValue value:&aLocalPointer withObjCType:#encode(myStruct)] afterDelay:0.25];
This is most likely asking for trouble, but you can pass CGPoint as id by bridging it in this way:
withObject:(__bridge id)((void *)(&point))
This will lead to a crash if point goes out of scope and your selector tries to read it, though.

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];

How to pass and set a CGFloat by reference?

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