Kevin
Kevin

Reputation: 115

iOS iPhone sleep / interval before an action

in an UIRotationGestureRecognizer i will do an action drawCircleView. But this action should start max 10 times in a second.

UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateContainerView:)];

rotation.delegate = self;

[_containerView addGestureRecognizer:rotation];


- (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
{
    static CGFloat initialScale;
    if (sender.state == UIGestureRecognizerStateBegan) {
        initialScale = (_Ro + 0.1)*-1;
        _Rotation=0;
    }
    _Ro = (sender.rotation*-1);


    sleep(.1);
    [self drawCircleView];
}

I have test the following

sleep(0.1);
[NSThread sleepForTimeInterval:.1];
NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
[NSThread sleepForTimeInterval:.1];

But with all it seems that all the action goes in a queue.

How i can do this without a query queue?

Full code

//
    //  CLHoleEffect.m
    //
    //  Created by Kevin Siml - Appzer.de on 2013/10/23.
    //  Copyright (c) 2013 Appzer.de. All rights reserved.
    //

    #import "CLSwirlEffect.h"
    #import "UIView+Frame.h"

    @interface CLSwirlCircle : UIView
    @property (nonatomic, strong) UIColor *color;
    @end

    @interface CLSwirlEffect()
    <UIGestureRecognizerDelegate>
    @end

    @implementation CLSwirlEffect
    {
        UIView *_containerView;
        UIView *_container;
        CLSwirlCircle *_circleView;
        UILabel* circleLabel;

        CGFloat _X;
        CGFloat _Y;
        CGFloat _R;
        CGFloat _Ro;
        CGFloat _Rotation;

    }

    #pragma mark-

    + (NSString*)defaultTitle
    {
        return NSLocalizedStringWithDefaultValue(@"CLSwirlEffect_DefaultTitle", nil, [CLImageEditorTheme bundle], @"Swirl", @"");
    }

    + (BOOL)isAvailable
    {
        return ([UIDevice iosVersion] >= 5.0);
    }

    - (id)initWithSuperView:(UIView*)superview imageViewFrame:(CGRect)frame toolInfo:(CLImageToolInfo *)info
    {
        self = [super initWithSuperView:superview imageViewFrame:frame toolInfo:info];
        if(self){
            _containerView = [[UIView alloc] initWithFrame:frame];
            [superview addSubview:_containerView];
            _X = 0.5;
            _Y = 0.5;
            _R = 0.5;
            _Ro = 0.5;
            [self setUserInterface];
        }
        return self;
    }

    - (void)cleanup
    {
        [_containerView removeFromSuperview];
    }

    - (UIImage*)applyEffect:(UIImage*)image
    {
        CGFloat R = (_R + 0.1);
        GPUImageSwirlFilter *stillImageFilter = [[GPUImageSwirlFilter alloc] init];
        [stillImageFilter setAngle: _Ro];
        [stillImageFilter setRadius:R];
        [stillImageFilter setCenter:CGPointMake(_X,_Y)];
        UIImage *quickFilteredImage = [stillImageFilter imageByFilteringImage:image];
        return quickFilteredImage;
    }

    #pragma mark-

    - (void)setUserInterface
    {
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapContainerView:)];
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panContainerView:)];
        UIPinchGestureRecognizer *pinch    = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchContainerView:)];
        UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotateContainerView:)];

        pan.maximumNumberOfTouches = 1;

        tap.delegate = self;
        pan.delegate = self;
        pinch.delegate = self;
        rotation.delegate = self;

        [_containerView addGestureRecognizer:tap];
        [_containerView addGestureRecognizer:pan];
        [_containerView addGestureRecognizer:pinch];
        [_containerView addGestureRecognizer:rotation];

        _circleView = [[CLSwirlCircle alloc] init];
        _circleView.backgroundColor = [UIColor clearColor];
        _circleView.color = [UIColor whiteColor];
        [_containerView addSubview:_circleView];

        [self drawCircleView];
    }

    #define DEGREES_TO_RADIANS(x) (M_PI * x / 180.0)


    - (void)drawCircleView
    {
        CGFloat R = MIN(_containerView.width, _containerView.height) * (_R + 0.1) * 1.2;
        _circleView.width  = R;
        _circleView.height = R;
        _circleView.center = CGPointMake(_containerView.width * _X, _containerView.height * _Y);
        [_circleView setNeedsDisplay];

        [self.delegate effectParameterDidChange:self];

    }

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        // if the gesture recognizers are on different views, don't allow simultaneous recognition
        if (gestureRecognizer.view != otherGestureRecognizer.view)
            return NO;

        // if either of the gesture recognizers is the long press, don't allow simultaneous recognition
        if ([gestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]])
            return NO;

        return YES;
    }

    - (void)tapContainerView:(UITapGestureRecognizer*)sender
    {
        CGPoint point = [sender locationInView:_containerView];

        _X = MIN(1.0, MAX(0.0, point.x / _containerView.width));
        _Y = MIN(1.0, MAX(0.0, point.y / _containerView.height));

        [self drawCircleView];

        if (sender.state == UIGestureRecognizerStateEnded){
            [self.delegate effectParameterDidChange:self];
        }
    }
    - (void)panContainerView:(UIPanGestureRecognizer*)sender
    {

        CGPoint point = [sender locationInView:_containerView];
        _X = MIN(1.0, MAX(0.0, point.x / _containerView.width));
        _Y = MIN(1.0, MAX(0.0, point.y / _containerView.height));

        [self drawCircleView];

        if (sender.state == UIGestureRecognizerStateEnded){
            //[self.delegate effectParameterDidChange:self];
        }
    }

    - (void)pinchContainerView:(UIPinchGestureRecognizer*)sender
    {

        static CGFloat initialScale;
        if (sender.state == UIGestureRecognizerStateBegan) {
            initialScale = (_R + 0.1);
        }
        _R = MIN(1.1, MAX(0.1, initialScale * sender.scale)) - 0.1;

        [self drawCircleView];
        if (sender.state == UIGestureRecognizerStateEnded){
            // [self.delegate effectParameterDidChange:self];
        }
    }

    - (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
    {
        static CGFloat initialScale;
        if (sender.state == UIGestureRecognizerStateBegan) {
            initialScale = (_Ro + 0.1)*-1;
            _Rotation=0;
        }
        _Ro = (sender.rotation*-1);


        [self drawCircleView];
        if (sender.state == UIGestureRecognizerStateEnded){
            // [self.delegate effectParameterDidChange:self];
        }
    }

    @end

    #pragma mark- UI components

    @implementation CLSwirlCircle

    - (void)setFrame:(CGRect)frame
    {
        [super setFrame:frame];
        [self setNeedsDisplay];
    }

    - (void)setCenter:(CGPoint)center
    {
        [super setCenter:center];
        [self setNeedsDisplay];
    }

    - (void)drawRect:(CGRect)rect

    {
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGRect rct = self.bounds;
        rct.origin.x += 1;
        rct.origin.y += 1;
        rct.size.width -= 2;
        rct.size.height -= 2;

        CGContextSetStrokeColorWithColor(context, self.color.CGColor);
        CGContextStrokeEllipseInRect(context, rct);

        self.alpha = 1;

        [UIView animateWithDuration:kCLEffectToolAnimationDuration
                              delay:1
                            options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                         animations:^{
                             self.alpha = 0;
                         }
                         completion:^(BOOL finished) {
                         }
         ];
    }
    @end

Upvotes: 2

Views: 218

Answers (2)

Bamsworld
Bamsworld

Reputation: 5680

To restrict the method, rotateContainerView:, being called no more than ten times in a second you could timestamp the first call and compare each subsequent calls timestamp, allowing the method to complete only if the calls timestamp is greater than last calls timestamp plus 0.1 seconds.

Add a property of type NSDate -

@property (nonatomic, strong) NSDate *lastCall;

Then modify rotateContainerView: to something like this -

- (void)rotateContainerView:(UIRotationGestureRecognizer*)sender
{
    static CGFloat initialScale;
    NSDate *nowCall = [NSDate date];// timestamp

    if (sender.state == UIGestureRecognizerStateBegan) {
        lastCall = nowCall;
        initialScale = (_Ro + 0.1)*-1;
        _Rotation=0;
        _Ro = (sender.rotation*-1);
        [self drawCircleView];
    }
    else {
        if ([nowCall timeIntervalSinceDate:lastCall] > 0.1) {
              _Ro = (sender.rotation*-1);
              [self drawCircleView];
              lastCall = nowCall;
         }
    }
}

Upvotes: 1

Dylan Gattey
Dylan Gattey

Reputation: 1724

drawRect is what's actually drawing the view. Decouple your data changes and the drawing changes. Draw your circles from drawRect, but change the rotation from a data method that you call instead of your current calls to drawCircleView. If you need to update on intervals, use a NSTimer to schedule calls to a rotate method. But leave the drawing of the actual circles up to drawRect. That way, you have guaranteed rotations, but the drawing happens all the time (which I think is what you want).

Does that make sense?

Upvotes: 0

Related Questions