ios - Creating a method to perform animations and wait for completion using a semaphore in objective c -
i trying create method makes use of uiview's "+animatewithduration:animations:completion" method perform animations, , wait completion. aware place code come after in completion block, avoid because there substantial amount of code after including more animations, leave me nested blocks.
i tried implement method below using semaphore, don't think best way it, because doesn't work. can tell me wrong code, and/or best way of achieving same goal is?
+(void)animateandwaitforcompletionwithduration:(nstimeinterval)duration animations:(void (^)(void))animations { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); [uiview animatewithduration:duration animations:animations completion:^(bool finished) { dispatch_semaphore_signal(semaphore); }]; dispatch_semaphore_wait(semaphore, dispatch_time_forever); }
i'm not sure what's wrong code when call method shown below, completion block never runs , end in limbo.
[foo animateandwaitforcompletionwithduration:0.5 animations:^{ //do stuff }];
-------------------------------------------edit-------------------------------------------------
if facing similar issue, might interested see code used. uses recursion make use of each completion block, without having nest each function call.
+(void)animateblocks:(nsarray*)animations withdurations:(nsarray*)durations { [foo animateblocks:animations withdurations:durations atindex:0]; } +(void)animateblocks:(nsarray*)animations withdurations:(nsarray*)durations atindex:(nsuinteger)i { if (i < [animations count] && < [durations count]) { [uiview animatewithduration:[(nsnumber*)durations[i] floatvalue] animations:(void(^)(void))animations[i] completion:^(bool finished){ [foo animateblocks:animations withdurations:durations atindex:i+1]; }]; } }
which can used so
[foo animateblocks:@[^{/*first animation*/}, ^{/*second animation*/}] withdurations:@[[nsnumber numberwithfloat:2.0], [nsnumber numberwithfloat:2.0]]];
in ios 7 , later 1 employ keyframe animation achieve effect.
for example, 2 second animation sequence composed of 4 separate animations take 25% of entire animation each like:
[uiview animatekeyframeswithduration:2.0 delay:0.0 options:uiviewkeyframeanimationoptionrepeat animations:^{ [uiview addkeyframewithrelativestarttime:0.00 relativeduration:0.25 animations:^{ viewtoanimate.frame = ...; }]; [uiview addkeyframewithrelativestarttime:0.25 relativeduration:0.25 animations:^{ viewtoanimate.frame = ...; }]; [uiview addkeyframewithrelativestarttime:0.50 relativeduration:0.25 animations:^{ viewtoanimate.frame = ...; }]; [uiview addkeyframewithrelativestarttime:0.75 relativeduration:0.25 animations:^{ viewtoanimate.frame = ...; }]; } completion:nil];
in earlier ios versions, queue series of animations couple of ways, i'd encourage avoid using semaphore on main thread.
one approach wrap animation in concurrent nsoperation
subclass, doesn't complete until animation does. can add animations own custom serial queue:
nsoperationqueue *animationqueue = [[nsoperationqueue alloc] init]; animationqueue.maxconcurrentoperationcount = 1; [animationqueue addoperation:[[animationoperation alloc] initwithduration:1.0 delay:0.0 options:0 animations:^{ viewtoanimate.center = point1; }]]; [animationqueue addoperation:[[animationoperation alloc] initwithduration:1.0 delay:0.0 options:0 animations:^{ viewtoanimate.center = point2; }]]; [animationqueue addoperation:[[animationoperation alloc] initwithduration:1.0 delay:0.0 options:0 animations:^{ viewtoanimate.center = point3; }]]; [animationqueue addoperation:[[animationoperation alloc] initwithduration:1.0 delay:0.0 options:0 animations:^{ viewtoanimate.center = point4; }]];
the animationoperation
subclass might like:
// animationoperation.h #import <foundation/foundation.h> @interface animationoperation : nsoperation - (instancetype)initwithduration:(nstimeinterval)duration delay:(nstimeinterval)delay options:(uiviewanimationoptions)options animations:(void (^)(void))animations; @end
and
// animationoperation.m #import "animationoperation.h" @interface animationoperation () @property (nonatomic, readwrite, getter = isfinished) bool finished; @property (nonatomic, readwrite, getter = isexecuting) bool executing; @property (nonatomic, copy) void (^animations)(void); @property (nonatomic) uiviewanimationoptions options; @property (nonatomic) nstimeinterval duration; @property (nonatomic) nstimeinterval delay; @end @implementation animationoperation @synthesize finished = _finished; @synthesize executing = _executing; - (instancetype)initwithduration:(nstimeinterval)duration delay:(nstimeinterval)delay options:(uiviewanimationoptions)options animations:(void (^)(void))animations { self = [super init]; if (self) { _animations = animations; _options = options; _delay = delay; _duration = duration; } return self; } - (void)start { if ([self iscancelled]) { self.finished = yes; return; } self.executing = yes; [[nsoperationqueue mainqueue] addoperationwithblock:^{ [uiview animatewithduration:self.duration delay:self.delay options:self.options animations:self.animations completion:^(bool finished) { [self completeoperation]; }]; }]; } #pragma mark - nsoperation methods - (void)completeoperation { self.executing = no; self.finished = yes; } - (bool)isconcurrent { return yes; } - (void)setexecuting:(bool)executing { if (_executing != executing) { [self willchangevalueforkey:@"isexecuting"]; _executing = executing; [self didchangevalueforkey:@"isexecuting"]; } } - (void)setfinished:(bool)finished { if (_finished != finished) { [self willchangevalueforkey:@"isfinished"]; _finished = finished; [self didchangevalueforkey:@"isfinished"]; } } @end
in demonstration, above, used serial queue. use concurrent queue, use nsoperation
dependencies manage relationship between various animation operations. lots of options here.
if want cancel animations, following:
calayer *layer = [viewtoanimate.layer presentationlayer]; cgrect frame = layer.frame; // identify [animationqueue cancelalloperations]; // cancel operations [viewtoanimate.layer removeallanimations]; // cancel animations viewtoanimate.frame = frame; // set final position
you incorporate custom cancel
method in operation, too, if want.
Comments
Post a Comment