Question

I am seeing that all ios animations in my app stop working.Its happening very frequently in iOS7.

I had an app which is supporting iOS 5, 6 and 7. I am seeing recently that all iOS animations stop working in the app in iOS7?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top