iOS animations stop working in my app in iOS7
In IOS 7 when some main method action is performed on background thread then the animations get disabled.
so for this you need to re-enable the animations like (A workaround)
[UIView setAnimationsEnabled:YES];
May be this can help.
I ran into this problem recently with some views I am laying out for size calculations on the background thread. By swizzling setAnimationsEnabled:
I found that the only time I was disabling animations from the background thread was in -[UIImageView setImage:]
.
Because this view was never rendered and image changes weren't required for my calculation, I was able to enclose this test in a main thread call:
if ([NSThread isMainThread]) {
self.answerImageView.image = [UIImage imageNamed:imgName];
}
It's worth noting I don't hit this issue in the initial view instantiation because I already load my template views in the main thread to avoid a Xib loading issue.
Other issues may be more complex but you should be able to come up with similar workarounds. Here's the category I use to detect background disabling of animations.
#import <UIKit/UIKit.h>
#import <JRSwizzle/JRSwizzle.h>
#ifdef DEBUG
@implementation UIView (BadBackgroundBehavior)
+ (void)load
{
NSError *error = nil;
if (![self jr_swizzleClassMethod:@selector(setAnimationsEnabled:) withClassMethod:@selector(SE_setAnimationsEnabled:) error:&error]) {
NSLog(@"Error! %@", error);
}
}
+ (void)SE_setAnimationsEnabled:(BOOL)enabled
{
NSAssert([NSThread isMainThread], @"This method is not thread safe. Look at the backtrace and decide if you really need to be doing this here.");
[self SE_setAnimationsEnabled:enabled];
}
@end
#endif
Update
It turns out that UIWebView
actually makes unsafe calls to setAnimationsEnabled:
when displaying a media element (rdar://20314684). This makes the above method very painful to have active all the time if your app allows arbitrary web content. Instead I've started using the below method as it lets me turn the breakpoint on and off and continue after failure:
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
#ifdef DEBUG
void SEViewAlertForUnsafeBackgroundCalls() {
NSLog(@"----------------------------------------------------------------------------------");
NSLog(@"Background call to setAnimationsEnabled: detected. This method is not thread safe.");
NSLog(@"Set a breakpoint at SEUIViewDidSetAnimationsOffMainThread to inspect this call.");
NSLog(@"----------------------------------------------------------------------------------");
}
@implementation UIView (BadBackgroundBehavior)
+ (void)load
{
method_exchangeImplementations(class_getInstanceMethod(object_getClass(self), @selector(setAnimationsEnabled:)),
class_getInstanceMethod(object_getClass(self), @selector(SE_setAnimationsEnabled:)));
}
+ (void)SE_setAnimationsEnabled:(BOOL)enabled
{
if (![NSThread isMainThread]) {
SEViewAlertForUnsafeBackgroundCalls();
}
[self SE_setAnimationsEnabled:enabled];
}
@end
#endif
With this code, you can stop your app by adding a symbolic breakpoint on SEViewAlertForUnsafeBackgroundCalls
or just sticking a breakpoint in the function body.
Gist
Extending Vinay's solution, that's what I do:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//make calculations
dispatch_async(dispatch_get_main_queue(),
^{
[UIView setAnimationsEnabled:YES];
});
});
It seems to solve the problem.