Variable Scope in Objective-C - objective-c

I'm getting started with Objective-C, and there is something about variables scope that I still didn't get. I searched about it, but I still couldn't catch what I'm doing wrong.
I'm trying to create a code that will give me the x,y difference between two point. The first NSLog inside the first IF shows the right value for pointWhereDragBegan.x and .y, but when I try to get the value of the pointWhereDragBegan in the second IF statement, the value I get for pointWhereDragBegan.x is -1.998683 and .y is 0.0.
I'm sure it is something really simple, I just can't catch my mistake.
- (void)drag:(UILongPressGestureRecognizer *)drag{
CGPoint pointWhereDragBegan;
if(drag.state == UIGestureRecognizerStateBegan){
pointWhereDragBegan = [drag locationInView:self];
NSLog(#"Drag started at %f,%f",pointWhereDragBegan.x,pointWhereDragBegan.y);
}
if(drag.state == UIGestureRecognizerStateEnded){
CGPoint pointWhereDragEnded = [drag locationInView:self];
float xDragged = pointWhereDragEnded.x - pointWhereDragBegan.x;
float yDragged = pointWhereDragEnded.y - pointWhereDragBegan.y;
NSLog(#"Drag ended at %f,%f",pointWhereDragEnded.x,pointWhereDragEnded.y);
NSLog(#"The user moved %f, %f",xDragged,yDragged);
}
}

drag.state will never be simultaneously UIGestureRecognizerStateBegan and UIGestureRecognizerStateEnded. This method should be invoked twice: once in each state.
As a result, in order to fix your issue, you'll need to persist pointWhereDragBegan outside the method scope. For example, you might use an instance variable.

Related

Xcode save value of variable “before and after”

I currently have this code attempting to save the value of a specific variable in before, and then re-saving the new value of the variable a second later to a variable named after.
- (void)getAfter {
after = Currentitems;
NSLog(#"%d, %d", before, after);
}
- (void)detectItems {
before = Currentitems;
[self performSelector:#selector(getAfter) withObject:nil afterDelay:1];
}
The function "detectBPS" runs every second as well. However, both of the before and after variables equal the same thing. How can I achieve what I am attempting to do?
Edit: I've read the suggestions. However, how can I implement KVO? Nevertheless, I'd still rather use (and am more open to) different/simpler suggestions as well.

Sending nil to CGPoint type parameter

Suppose I have this method:
- (void)placeView:(UIView*)theView withCenterIn:(CGPoint)centerPoint;
So I pass the view and a point to te the view's center.
But it happens that I do not need to specify the center, just the view.
Passing "nil" leads to error.
Please, suggest how to skip passing the center point.
Keep in mind that I need to use that method like this:
- (void)placeView:(UIView*)theView withCenterIn:(CGPoint)centerPoint{
if(centerPoint == nil){//and I understand that it's a wrong comparison, as I cannot pass "nil" to CGPoint
//set a random center point
}
else{
//set that view to the specified point
}
}
Thanks in advance
You can't use nil as a "no point" indicator, because it is only for objects, and CGPoint is a struct. (As dasblinkenlight has already said.)
In my geometry library, I've defined a "null" CGPoint to use as a "no point" placeholder, and a function to test for it. Since the components of a CGPoint are CGFloats, and floats have a "invalid value" representation already -- NAN, defined in math.h -- I think that's the best thing to use:
// Get NAN definition
#include <math.h>
const CGPoint WSSCGPointNull = {(CGFloat)NAN, (CGFloat)NAN};
BOOL WSSCGPointIsNull( CGPoint point ){
return isnan(point.x) && isnan(point.y);
}
CGPoint is a C struct, you cannot pass nil for it. You can create a separate method that does not take the unnecessary CGPoint, and get rid of your if statement, like this:
- (void)placeView:(UIView*)theView withCenterIn:(CGPoint)centerPoint{
//set that view to the specified point
}
- (void)placeView:(UIView*)theView {
//set a random center point
}
If you insist on keeping one method, you could designate one point as "special" (say, CGMakePoint(CGFLOAT_MAX, CGFLOAT_MAX)), wrap it in a #define, and use instead of nil.
Yet another solution would be to wrap your CGPoint in NSValue:
NSValue *v = [NSValue withPoint:CGMakePoint(12, 34)];
CGPoint p = [v pointValue];

cocos2d sub-classing

I know that cocos2d has scheduling callbacks to do nice things but when you need to use one CCAction (like CCMoveTo one) in order to move a sprite from position a to b, you do not have the ability to make small position arrangements to the sprite position for as long as the action is in effect.
The only possible way I found is by making a sub-class of CCMoveTo in order to check for obstacles and therefore provide some kind of movement to the left or right to a sprite that was moving from top to the bottom of the iPhone screen. The problem is that the sub-class does not have access to the parent class' instance variables (like the startPosition_ one) because they have not been declared as properties.
So I used the following snippet to overcome this situation but I wonder if I am doing something wrong...
- (void)myUpdate:(ccTime)time {
if(delegate && method_) {
NSNumber *num = (NSNumber *)[delegate performSelector:method_ withObject:ownTarget];
if(num) {
double xpos = [num doubleValue];
[num release];
CCMoveTo *parent = [super retain];
parent->startPosition_.x += xpos;
[parent release];
}
[super update:time];
}
Is it correct to retain/release the super-class? The "[super update:time];" at the bottom of the code will make the final positioning.
CCMoveTo *parent = [super retain];
Ouch! This statement makes absolutely no sense. It is the same as writing:
[self retain];
As for accessing the super class' instance variables: unless they're declared #private you can access them. I just checked: they're not #private. You should be able to write in your subclass:
startPosition_.x += xpos;
If that doesn't work make sure your class is really a subclass of CCMoveTo, and not some other class.
Finally, I'd like to say that actions are very limited when it comes to implementing gameplay. You're probably much better off to simply animate your game objects by modifying their position property every frame, based on a velocity vector. You have much more freedom over the position and position updates, and none of the side effects of actions such as a one-frame delay every time you run a new action.
-(void) update:(ccTime)delta
{
// modify velocity based on whatever you need, ie gravity, or just heading in one direction
// then update the node's position by adding the current velocity to move it:
self.position = CGPointMake(self.position.x + velocity.x, self.position.y + velocity.y);
}

How do I return CGpoint function?

If i have this function:
-(CGPoint)limitPosition:(CGPoint)position {
//code here
return position;
}
how do I return it to a variable?
This:
CGPoint a;
CGPoint b;
a = [self limitPosition: b];
Doesnt work.
Without a clearer description of what you mean by "doesn't work", and probably what's going on where you have //code here, it's hard to say.
Basically, you can pass a CGPoint to and from a function or method with the syntax as you have it. It'll be passed by value, so that any changes to position inside the function will not be reflected in the variable passed as argument (b), but should be copied back in the return value (to a).
In the code fragment shown, you don't initialise a or b, so they may contain garbage. And obviously the method body isn't doing much. But otherwise it looks kosher, so the problem is probably elsewhere.

Passing arguments by value or by reference in objective C

I'm kind of new with objective c and I'm trying to pass an argument by reference but is behaving like it were a value. Do you know why this doesn't work?
This is the function:
- (void) checkRedColorText:(UILabel *)labelToChange {
NSComparisonResult startLaterThanEnd = [startDate compare:endDate];
if (startLaterThanEnd == NSOrderedDescending){
labelToChange.textColor = [UIColor redColor];
}
else{
labelToChange.textColor = [UIColor blackColor];
}
}
And this is the call:
UILabel *startHourLabel; // This is properly initialized in other part of the code
[self checkRedColorText:startHourLabel];
Thanks for your help
Objective-C only support passing parameters by value. The problem here has probably been fixed already (Since this question is more than a year old) but I need to clarify some things regarding arguments and Objective-C.
Objective-C is a strict superset of C which means that everything C does, Obj-C does it too.
By having a quick look at Wikipedia, you can see that Function parameters are always passed by value
Objective-C is no different. What's happening here is that whenever we are passing an object to a function (In this case a UILabel *), we pass the value contained at the pointer's address.
Whatever you do, it will always be the value of what you are passing. If you want to pass the value of the reference you would have to pass it a **object (Like often seen when passing NSError).
This is the same thing with scalars, they are passed by value, hence you can modify the value of the variable you received in your method and that won't change the value of the original variable that you passed to the function.
Here's an example to ease the understanding:
- (void)parentFunction {
int i = 0;
[self modifyValueOfPassedArgument:i];
//i == 0 still!
}
- (void)modifyValueOfPassedArgument:(NSInteger)j {
//j == 0! but j is a copied variable. It is _NOT_ i
j = 23;
//j now == 23, but this hasn't changed the value of i.
}
If you wanted to be able to modify i, you would have to pass the value of the reference by doing the following:
- (void)parentFunction {
int i = 0; //Stack allocated. Kept it that way for sake of simplicity
[self modifyValueOfPassedReference:&i];
//i == 23!
}
- (void)modifyValueOfPassedReference:(NSInteger *)j {
//j == 0, and this points to i! We can modify i from here.
*j = 23;
//j now == 23, and i also == 23!
}
Objective-C, like Java, only has pass-by-value. Like Java, objects are always accessed through pointers. "objects" are never values directly, hence you never assign or pass an object. You are passing an object pointer by value. But that does not seem to be the issue -- you are trying to modify the object pointed to by the pointer, which is perfectly allowed and has nothing to do with pass-by-value vs. pass-by-reference. I don't see any problem with your code.
In objective-c, there is no way to pass objects by value (unless you explicitly copy it, but that's another story). Poke around your code -- are you sure checkRedColorText: is called? What about [startDate compare:endDate], does it ever not equal NSOrderedDescending? Is labelToChange nil?
Did you edit out code between this line
UILabel *startHourLabel;
and this line?
[self checkRedColorText:startHourLabel];
If not, the problem is that you're re-declaring your startHourLabel variable, so you're losing any sort of initialization that was there previously. You should be getting a compiler error here.
Here are the possibilities for why this doesn't work:
the label you pass in to checkRedColorText is not the one you think it is.
the comparison result is always coming out the same way.
... actually, there is no 3.
You claim you initialised startHourLabel elsewhere, but, if it is a label from a nib file, you should not be initialising it at all. It should be declared as an IBOutlet and connected to the label in the nib with interface builder.
If it is not a label in the nib i.e. you are deliberately creating it programmatically, you need to check the address of the label you initialise and check the address of the label passed in to checkRedColorText. Either NSLog its address at initialisation and in checkRedColorText or inspect it with the debugger.