问题
I'm animating a view (by revealing it) after which I need to post a notification (once the animation completes). However the way the app's designed, there's another notification sent out when the view is hidden (via animation). So essentially I have a 'showView' and a 'hideView' method. Each do something like so:
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
[context setDuration: 0.25];
[[myView animator] setAlphaValue: 0];
} completionHandler:^{
// post notification now
}];
The problem is that in another thread in the background, I have a periodic timer which performs a 'sanity check' to see if the view needs to be hidden if it's not needed. It's an aggressive approach but necessary as many components of the app respond to different events and scenarios. Due to this I at times get a 'race condition' where the user has clicked to 'showView' but at the same time one of our threads feel the view should be immediately hidden.
When both post a notification on the main thread, the app hangs indefinitely in a SpinLock. I could completely avoid this situation if I was able to figure out if the animation block above was 'cancelled' (i.e. another animation block executed on the same view). In such situations I would not post the notification, which would then not force a check.
Long story short: I need to be able to check if the 'completionHandler' was called after animation successfully ended or if it was cancelled. I know in iOS this is possible but I can't find any way to do this in OS X. Please help.
回答1:
I encountered a similar problem. I solved it by using a currentAnimationUUID
instance variable.
NSUUID *animationUUID = [[NSUUID alloc] init];
self.currentAnimationUUID = animationUUID;
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
// set properties to animate
} completionHandler:^{
BOOL isCancelled = ![self.currentAnimationUUID isEqual:animationUUID];
if (isCancelled) {
return;
}
self.currentAnimationUUID = nil;
// do stuff
}];
Swift version:
let animationUUID = UUID()
currentAnimationUUID = animationUUID
NSAnimationContext.runAnimationGroup({ context in
// set properties to animate
}, completionHandler: {
let isCancelled = self.currentAnimationUUID != animationUUID
guard !isCancelled else {
return
}
self.currentAnimationUUID = nil
// do stuff
})
来源:https://stackoverflow.com/questions/18772798/check-if-nsanimationcontext-runanimationgroup-cancelled-or-succeeded