Calling UIGestureRecognizer from UITouch object

401 views Asked by At

I am trying to associate a Gesture with UITouch object because I need to pass data through a target action Method.

I have something implemented but it is inefficient,it get 100% of the CPU processing, it is probably because it is coded incorrectly.

There is my instance method for the UITouch event which call the UIPangesture

- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event
{
return YES;


UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
                                      initWithTarget:self action:@selector(handlePan:)];



[self addGestureRecognizer: panGesture];



}

There is my instance method for the UIPAnGestureRecognizer

- (IBAction)handlePan:(UIPanGestureRecognizer *)event
{
if (event.numberOfTouches==1)
{
    CGPoint lastPoint = [event locationOfTouch: event.numberOfTouches - 1 inView:     event.view];
    CGRect bounds = self.bounds;
    CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    CGPoint delta = CGPointMake(lastPoint.x - center.x,  lastPoint.y - center.y);
    CGFloat angle = (delta.y == 0 ? delta.x >= 0 ? 0 : M_PI : atan2(delta.y, delta.x));
    angle = fmod(angle,  M_PI * 2.0);
    angle += angle >= 0 ? 0 : M_PI * 2.0;
    UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:1. brightness:1. alpha:1];
    if ([color getRed: &r green: &g blue:&b alpha: &a]){
        rValue = r;
        gValue = g;
        bValue = b;

        [self setNeedsDisplay];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
        [self updateLabels];


    }
  }
}

And there there the methods which call the action method to obtain the variables from the color picker

- (void)setup:(CsoundObj *)csoundObj
{
NSLog(@"Color value - R : %f G : %f : B %f", rValue, gValue, bValue);
channelPtrR = [csoundObj getInputChannelPtr:@"mix" channelType:CSOUND_CONTROL_CHANNEL];
channelPtrG = [csoundObj getInputChannelPtr:@"pitch" channelType:CSOUND_CONTROL_CHANNEL];
channelPtrB = [csoundObj getInputChannelPtr:@"c" channelType:CSOUND_CONTROL_CHANNEL];
cachedValueR = rValue;
cachedValueG = gValue;
cachedValueB = bValue;
self.cacheDirty = YES;

[self addTarget:self action:@selector(updateValueCache:) forControlEvents:UIControlEventValueChanged];
}

- (void)updateValueCache:(id)sender
{
cachedValueR = ((CustomView*)sender).rValue;
cachedValueG = ((CustomView*)sender).gValue;
cachedValueB = ((CustomView*)sender).bValue;
self.cacheDirty = YES;
}

- (void)updateValuesToCsound
{
if (self.cacheDirty) {
    *channelPtrR = cachedValueR;
    *channelPtrG = cachedValueG;
    *channelPtrB = cachedValueB;
    self.cacheDirty = NO;
}
}

- (void)updateValuesFromCsound
{

}

- (void)cleanup
{
[self removeTarget:self action:@selector(updateValueCache:)   forControlEvents:UIControlEventValueChanged];
}

I know the problem it is on the instance method for the UITouch event which call the UIPangesture, any other way to do it more efficiently?

1

There are 1 answers

1
HalR On BEST ANSWER

I think that you are calling this section of code way too often:

   CGPoint lastPoint = [event locationOfTouch: event.numberOfTouches - 1 inView:     event.view];
    CGRect bounds = self.bounds;
    CGPoint center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
    CGPoint delta = CGPointMake(lastPoint.x - center.x,  lastPoint.y - center.y);
    CGFloat angle = (delta.y == 0 ? delta.x >= 0 ? 0 : M_PI : atan2(delta.y, delta.x));
    angle = fmod(angle,  M_PI * 2.0);
    angle += angle >= 0 ? 0 : M_PI * 2.0;
    UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:1. brightness:1. alpha:1];
    if ([color getRed: &r green: &g blue:&b alpha: &a]){
        rValue = r;
        gValue = g;
        bValue = b;

        [self setNeedsDisplay];
        [self sendActionsForControlEvents:UIControlEventValueChanged];
        [self updateLabels];


    }

You are likely calling it when there is no change, or little change. There are two things you could do to reduce the number of calls. You can test for a significant change in the angle like this:

//class property
@property (nonatomic, assign) CGFloat lastAngle;

//In your code
    CGFloat deltaAngle = fabs(self.lastAngle - angle)
    if (deltaAngle > 0.5) {  //select whatever delta works best
        angle += angle >= 0 ? 0 : M_PI * 2.0;
        UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:1. brightness:1. alpha:1];
        if ([color getRed: &r green: &g blue:&b alpha: &a]){
            rValue = r;
            gValue = g;
            bValue = b;

            [self sendActionsForControlEvents:UIControlEventValueChanged];
            [self updateLabels];
            [self setNeedsDisplay];
        }
    }

Or you can test for time since the last update like this:

  //class property
    @property (nonatomic, retain) NSDate *lastTime;

    //set it when the view loads
    self.lastTime = [NSDate date];

    //In your code
        NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:lastdate];
        self.lastTime = [NSDate date];
        if (interval > 0.05) {  //select whatever time interval works best
            angle += angle >= 0 ? 0 : M_PI * 2.0;
            UIColor *color = [UIColor colorWithHue: angle / (M_PI * 2.0) saturation:1. brightness:1. alpha:1];
            if ([color getRed: &r green: &g blue:&b alpha: &a]){
                rValue = r;
                gValue = g;
                bValue = b;

                [self sendActionsForControlEvents:UIControlEventValueChanged];
                [self updateLabels];
                [self setNeedsDisplay];
            }
        }

Also, are you sure you need the [self setNeedsDisplay] ?