Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS animations stop working in my app in iOS7

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?

like image 758
user1010819 Avatar asked Oct 16 '13 19:10

user1010819


2 Answers

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.

like image 181
Vinay Kumar Avatar answered Sep 22 '22 21:09

Vinay Kumar


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

like image 37
Brian Nickel Avatar answered Sep 26 '22 21:09

Brian Nickel