UIViewController animations stop working
Asked Answered
G

4

21

My app runs fine in iOS6, but in an unspecified upcoming version of iOS that I cannot name for NDA reasons, all UIViewController transition animations stop working. New views just pop into place instantly. I am not sure if this unspecified future version of iOS is the cause, as I've seen this happen occasionally in iOS6.

Sometimes animations start working for a while and then stop shortly after, making me think it's some sort of memory warning issue, but my app is using a fairly reasonable ~125MB of RAM at most times. Can anyone offer any advice or things to investigate?

Galactose answered 16/8, 2013 at 19:51 Comment(10)
More info would be useful here. What are you animating and how? Can you post some relevant code? Otherwise, you might have more luck on the Apple Dev forums.Weasel
I am doing absolutely normal [self.navigationController pushViewController: viewController animated: YES] - style view controller transitions. Sadly the apple dev forums are a bit of a wasteland compared to SO in my experience, but I've got a thread open there too.Galactose
You're not using custom subclasses of UIViewControllers at all? Just stock parts? I haven't ever heard of animations stopping because of memory pressures; that seems unlikely.Spouse
They're subclasses, but completely standard ones. I'm definitely not doing anything weird that I can tell. They have views, I'm using them in the normal ways.Galactose
Any calls to layout subviews in custom views or anything like that which could be interrupting the natural flow of things?Spouse
No, not at all - no use of layoutSubviews at all. As I say, it works fine in iOS6. I've seen it break but only a fluke once in a few months.Galactose
Are you changing any UIViewController -modalPresentationStyle to UIModalPresentationCurrentContext?Breakneck
If same code base exists in iOS 6 and you are occasionally witnessing it in iOS6 too, why don't you post it for review?Goldin
Code might help. Are you enabling or disabling animations somewhere in your code? Or is the view controller presented twice in a row? You might check in viewWill/DidAppear.Fujimoto
Hey Guyz I am having the exact same problem?? Are you guyz sure that it happens only because of doing UIKit stuff in background or memory issues or anything else.Its a little urgent!!Backcross
I
40

The described behavior has always existed: if you do work on background threads and then call and UIKit methods then more often than not the update will be delayed in a weird way.

Because of this you should always dispatch_async onto the main queue to update the UI.

Those bugs are very hard to catch since they do not always occur predictably.

To catch them I built a method that swizzles some UIKit methods to check if they are called on the main thread. This allows you to stop on a symbolic breakpoint, whenever you have forgotten to dispatch back onto main queue.

https://github.com/Cocoanetics/DTFoundation/blob/develop/Core/Source/iOS/Debug/UIView%2BDTDebug.m

Irrelievable answered 22/8, 2013 at 6:3 Comment(6)
That code is exactly how I found the background thread stuff.Galactose
From iHunter's source, you need DTObjectBlockExecutor, NSObject+DTRuntime, and UIView+DTDebug, to swizzle the view method and catch the issues.Galactose
It's a bit of a PITA to get the code into your project (because of the dependencies and Cocoapods not being complete), but once you set the breakpoint you'll find the bad line of code in a few moments. Thanks!Barbarbarbara
How can I use UIView_DTDebug class in my project. I have added DTDebug,DTObjectBlockerExecutor,NSObject,UIVew classes from source. But I am getting errors: cannot find interface declaration for UIView and many more....Pretentious
Thanks a lot for the link! Helped me find UI calls that were made from the a background thread.Stacistacia
@Irrelievable How would I go about using this code in a Swift framework that I'm building? I've dropped the necessary files into my framework and I have a bridging header there. My framework is then being used in a sample project written in Obj-C. methodCalledNotFromMainThread is not getting called even when the animations stop working.Peculium
G
15

A good workaround from the Apple dev forums on this issue:

Do this:

[UIView setAnimationsEnabled:YES] 

And animations start working again. I suspect that this is either a straight up iOS7 bug, or somewhere in my code an animation or UIViewController launch is happening on a background thread, causing animations to stop. Probably unrelated to the unspecified future version of iOS.

Galactose answered 19/8, 2013 at 19:15 Comment(2)
Fyi, on our app view animations seems to work ok, fyi. Also Added one to question. Thought it is an ok question.Coastline
why you are posting as answer? that too TWO answers? please put this in question after editing it...Rumpus
G
0

This issue appears to be caused by doing UIKit stuff in background threads. I have a pre-render cache full of NSOperations that renders complex UIViews to UIImages to cache the output. This seemed to work fine in iOS6, but probably does cross the line somewhat. I'll need to replace this functionality with something that renders images and text to a graphics buffer rather than using UIViews and UILabels at all.

Galactose answered 20/8, 2013 at 18:46 Comment(0)
M
0

All you have to do is catch hold of main queue while updating UI on receiving response from an API.Ios uses main queue by default for updating UI but it is not 100 percent efficient.Hence you have to make sure that the UI gets updated on main thread only and the way to do that is as below:

DispatchQueue.main.async{
  //UI related code eg: 
  self.label.text = "abc" 
  self.button.setTitle("xyz",.normal)
  self.tableView.reloadData()
}

If you are not catching hold of main thread animations may or may not work. But if you are using main thread animations will definetely work.

Correct Code while updating UI on api response:

Alamofire.getApiCall(paramaters: parameters, completion:{
  response in 
  // UI related code.
  DispatchQueue.main.async{
    self.label.text = "abc" 
    self.button.setTitle("xyz",.normal)
    self.tableView.reloadData()
  }
})

Incorrect Code which may cause animations to stop and lead to weird crashes:

  Alamofire.getApiCall(paramaters: parameters, completion:{
  response in 
  // UI related code.
    self.label.text = "abc" 
    self.button.setTitle("xyz",.normal)
    self.tableView.reloadData()
})
Mccubbin answered 5/9, 2017 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.