I have an iPad drawing app which uses core data and Quartz 2D. Users and I have been experiencing freeze problems that happen one or two times every hour if I am unlucky. I have tried everything I can to debug the problem, making sure there is no dead locks, no UI code being called from background threads and no core data methods called in different threads. (I used method swizzling to check them.)
But the problem is still here, and there is no crash log because the whole iPad just freeze and the user has to do a hard restart. It usually happens when I am drawing but I have no clue why it happens. It seems to be related to the fact that it updates some CAShapeLayers every time an UITouch is moved. (It is not feasible to use bitmaps instead because of memory usage) I even used Instruments to manually check every function that is called when I am drawing.
What else can I try to fix the problem? It has been bothering me for a few months now... and I begin to wonder if it is a bug from iOS.
Related
I have an iOS Xcode project that previously would load fast, but from time to time, now will hang for five seconds or more during loading. When the app is run on an iPhone, the launch screen displays instantly, but sometimes, not always, and unpredictably, the app just hangs for around 5 seconds or more until the actual interface is displayed. It occurs both on the simulator and device across different iOS versions 7, 8, 9.
Recently, a UIView's class that contains a drawRect function was changed slightly, it has an outlet connection to one of the ViewControllers, but no significant changes made overall. One ViewController has code in the ViewDidLoad, ViewWillAppear, ViewDidAppear functions. All these things I'm investigating if they are impacting the load time.
When I terminate the app, the next time I try running it, it loads super fast without issue. I have no idea what to make of this load behaviour.
Questions
1 - What methods can I use in Xcode to debug an app that loads slowly at irregular and unpredictable times?
2 - What obvious items should I be on the look out in the project that typically cause slow or prolonged load times?
3 - Does Xcode include tools to monitor the processes operating live while loading occurs?
4 - Is it possible to print output for load processes I can review?
Any experienced advice really appreciated. Thanks.
Not sure if you have looked instrumentation. It is the best way to determine this kind of issues with your app.
https://developer.apple.com/library/watchos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/index.html
When I terminate the app, the next time I try running it, it loads super fast without issue. I have no idea what to make of this load behavior.
Do you mean exiting the app? Or actually killing it? Cause if it is the former, then the reason is the app was just launched from a suspended state.
I would suggest take a closer look at didFinishLaunchingWithOptions:, and check if you are doing something that takes more time than needed. Run your app with the time profiler instrument, it will tell you where is your bottleneck.
I see a lot of posts about people trying to obscure sensitive information from their app snapshot so that its not readable in the multitasking app selector. But I have a different problem.
I'm trying to save as much memory in my app as possible when it enters the background, and one of my app's views has a lot of subviews that is the largest memory usage of my entire app. I've written code to remove and delete these subviews, which i then recreate when the app returns to the foreground (I've actually called these methods in the resign active and did become active methods). Everything is working fine but when I delete these subviews, the view correctly appears rather empty, just in time for the system app snapshot to be taken. So as the app is restored this empty view is displayed for a short time before the app renders properly.
I'd like to be able to manage these views but I guess it needs to happen AFTER the app snapshot has taken place.
Actually profiling the app's memory usage I've noticed that the large (70meg) memory usage that's present whilst the app is in the foreground drawing these views drops right down when the app is backgrounded even if i don't manually delete the views myself. The documentation is clear that the actual backing CA layers etc are all handled by the system so thankfully the majority of memory savings are already being made by the system itself. But still there's another 5-10meg that I can save by doing what I've described here so it feels like a good idea. Is it possible though?
I wonder if I should request to be left running a little longer which I think i saw was possible may be the solution? Especially if the app snapshot is taken before this extra time is given to the app.. This would mean the screenshot is correct and the memory is saved a split second later.
Thanks for your time, Cheers!
I'm not sure why you're worried about 5-10 megs of RAM. The system will reclaim lots of memory by blowing away the backing layers, as you said, and recreating them when the app is foregrounded again. But what, exactly, do you hope to accomplish by reclaiming more memory yourself?
Unfortunately you can't control when the snapshot is taken. You could, I suppose, do a dispatch_after to have your view destruction code happen after a delay, but this wouldn't be deterministic since you don't know when the snapshot will be taken. And it's also possible that the code won't be run at all if your app is asleep when the dispatch timer goes.
I think you may be optimizing prematurely.
Add a snapshot view on top of your view hierarchy before removing the subviews.
UIView *snapshotView = [view snapshotViewAfterScreenUpdates:NO];
Not exactly sure that will help save much of those few MBs you worry about, but that's the common way of doing something like this.
I'm making a game for iOS where you mostly drag big objects across the screen. When I run the game on an actual iPad/iPhone for a while (continuously dragging the object in circles across the screen) every 5 minutes or so the dragged object goes all stuttery for about 10-30 seconds. Then, it goes back to moving silky-smooth.
Visually, it looks like the game's frame rate dropped to 15 fps for a while, but in actual fact it's running at rock-solid 60 fps all the time. However, I noticed that the only thing that doesn't move smoothly is the dragged object, while the rest of the game is all running perfectly smooth.
This led me to believe that the stuttering is related to the touch input in iOS. So I started looking at touchesMoved, and saw that it's normally called every 16 milliseconds (so touch input runs at 60 fps). So far so good.
Then I noticed that when the object starts stuttering, touchesMoved starts being called at weird time intervals, fluctuating wildly between 8 milliseconds and 50 milliseconds.
So while the touchscreen is in this weird state, sometimes touchesMoved will get called just 8 milliseconds after the previous call, and sometimes it won't get called until 50 ms after the previous call. Of course, this makes the dragged object look all choppy because its position is updated at irregular intervals.
Do you have any idea what could be causing touchesMoved to stop being called at regular intervals, as it normally does?
Bonus:
-Whenever I tilt the screen to force the screen orientation to change, roughly 70% of the time the touchscreen goes into the aforementioned state where touchesMoved starts being called irregularly. Then after 10-20 seconds it goes back to normal and everything looks smooth again.
-I've tried this on two iPads and two iPhones, with iOS 6 and 7, and the issue appears in all of these devices.
-An OpenGLES view is used to display the graphics. It syncs to the display refresh rate using CADisplayLink.
-The Xcode project I'm using to test this has been generated by the unity3d game development tool, but I've found several non-unity games where the same issue appears. this appears to be a system-wide problem. note I'm measuring the timings in objective-c using CFAbsoluteTimeGetCurrent, completely outside unity.
This is not a bug in Unity.
Something inside the OS is getting into a bad state and the touch-drag messages stop flowing smoothly. Sometimes you'll get multiple updates in a frame and sometimes you'll get none.
The issue does not happen on iPhone4 or below, or if the game is running at 30Hz frame rate.
I experienced this bug while using an in-house engine I'd written while working at a previous company. It first manifest itself after upgrading the UI system of a scrabble genre game, where you drag the tiles about on the screen. This was utterly bizarre, and I was never able to pin down the exact reproduction steps, but they seem to be timing related, somehow.
It can also be seen on Angry Birds (unless they've fixed it by now), and a variety of other games on the market, basically anything with touch-drag scrolling or movement. For Angry Birds, just go into a level and start scrolling sideways. Most of the time it'll be silky smooth, but maybe 1 in 10 times, it'll be clunky. Re-start the app and try again.
A workaround is to drop the input update frequency to 30Hz for a few frames. This jolts the internals of the OS somehow and gives it time to straighten itself out, so when you crank it back up to 60Hz, it runs smoothly again.
Do that whenever you detect that the bad state has been entered.
I've also run into this. I can verify that it's a bug in Unity 4.3.x.
My 4.2.x builds process touches on device at 60Hz with TouchPhase.Moved on every frame.
My 4.3.x builds get 20-40Hz with TouchPhase.Stationary being emitted on dropped frames.
TestFlight history saved my sanity here.
Don't forget to file a bug with UT.
It's a real disaster. Sometimes it's lag and sometimes it's really smooth. It lags even when GPU and CPU utilization are below 10%. it's not Unity bug. I'm using cocos2d v3.
If someone found a cure, please post it!
I've been running into this as well. My current hypothesis which I still have to verify is that if you ask for a given frame rate (eg. 60fps), but your actually achieved frame rate is less than that (eg. 45fps) that this causes a timing/race condition issue between Unity requesting inputs from iOS at a higher frame rate than it actually is running at. However, if you set it to 30fps (at least in my UNity 5.2 tests with iOS 9.1) then you get a solid 30Hz of input. When I disabled a chunk of my game and it was running at a very solid 60fps, then I would consistently get 60Hz of input from the touch screen. This is what I have for now, but I have to prove this in a simple project which I haven't had time to do yet. Hope this helps someone else.
I found a potential solution to this problem here: https://forums.developer.apple.com/thread/62315 (posting here because it took me a lot of research to stumble across that link whereas this StackOverflow question was the first Google result).
To follow up on this, I got a resonse on my bug report to Apple. This
is the response:
"As long as you don't cause any display updates the screen stays in
low power and therefore 30hz mode, which in turn also keeps the event
input stream down at 30 hz. A workaround is to actually cause a
display update on each received move, even if it is just a one pixel
move of a view if input is needed while no explicit screen update will
be triggered."
In my application, using a GLKView, I set its
preferredFramesPerSecond to 60. Occasionally, my input rate would
randomly drop to 30hz. The response from Apple doesn't fully explain
why this would happen, but apparently the expected method of handling
this is to call display() directly from touchesMoved() while dragging.
I've subclassed GLKView and I set preferredFramesPerSecond to 60. On
touchesBegan(), I set isPaused=true, and start calling display()
within touchesMoved(). On touchesEnd(), I set isPaused=false. Doing
this, I'm no longer having any issues - the app is more performant
than it's ever been.
Apple's example TouchCanvas.xcodeproj does all drawing from within
touchesMoved() as well, so I guess this is the intended way to handle
this.
As far as I can tell, your best bet to achieve a smooth look may be to interpolate between touch events, rather than immediately mapping your objects to your touch position.
tl;dr: It seems just having a CADisplayLink causing any OpenGL context or Metal device to draw at 60fps can cause this.
I was repro'ing this on my iPhone 7 Plus w/ iOS 10.2.1.
I made a small sample simple app with a CADisplayLink with preferredFramesPerSecond = 60, and tried the following rendering approaches:
GLKView w/ display()
CAEAGLLayer, used as prescribed by Apple at WWDC (opaque, sole layer, fullscreen, nothing drawn above it)
MTLDevice
In each case, the render method would only clear the screen, not try drawing anything else.
In each case, I saw the input rate problem.
The following "tricks" also seemed to do nothing, when called inside touchesMoved:
Calling glkView.setNeedsDisplay() (with enableSetNeedsDisplay set to true)
Moving some other view
Calling glkView.display() (actually, seems like it can raise your input rate to 40 events per second. But it doesn't look any better, as far as I can tell, and seems wrong to do, so I wouldn't recommend it.)
I gave up, after running all these tests. Instead, I interpolate my object between the touch positions instead. So it's what I'd recommend, too.
But I figured I'd include my research here in case somebody else takes a stab at it and finds a better solution.
I don't have any hardcore data supporting this, but generally, you'll notice that any app you play with or one you're working on, when the app first loads, doing something such as displaying a modal view controller is slow the first time, but every subsequent time, it's really fast. For my app, when I present a modal view controller the first time, it takes about 3 seconds, but if I do it over and over again after that, it takes less than a second every time. What is the reason for this?
There's a bunch of possible explanations here.
Something's been cached. The first time, it had to load something from "disk," the second time it was already in memory. This could be an entire framework, or NIBs or graphic resources in the OS itself.
Memory management. iOS didn't have enough memory to satisfy the request the first time. iOS spent some time clearing out memory, possibly quitting background applications. The second time, it's already available.
Probably many others.
Caching. Off the top of my head, images are often cached, and I wouldn't be surprised if the nib was cached as well.
No, I don't notice this in my app. The cause of what you are seeing could be a hundred different things, so we need a bit more data to make an informed answer.
Suggest you run Instruments, narrow down the time window to the initial 3-second pause, then see what the machine is doing during that time. Run it multiple times and look at CPU, IO, memory, anything that could be slowing it down.
This is very difficult issue, since it doesn't occur every time.
When an app is just launched, returning from background, it is fine without any freezing.
After some time being in background, when I re-activate it, the whole UI is frozen for while, even the activity indicator is not animating. As time goes on, this freezing gets longer and finally causes the app to be terminated by iOS for not resuming in time.
I would like to learn what are the generic causes of an app to be unresponsive, especially if the app is supporting background running feature and re-activating after a period of being in background.
It looks like I have missed some fundamental techniques that should be respected to avoid freezing problems.
UPDATE: I am suspicious if saving UIImage into Core Data object can be the main reason. At launch, it's not visible, however, as time passes, numerous saveManagedObjectContext are performed while UIImage is still referenced.
Maybe I should have listened to the instruction not to save any image in Core Data?
check for your crash log if you are getting this
Exception Codes: 0x8badf00d
then its most probably your application is taking much time either in launch or while moving in background or terminate, actually app take much time in launch/shut iOS suspend it and our app freeze, there is no such time define in documents but as i experienced it should not be more then 4-5 seconds. check your app delegate applicationDidFinishLaunch or multitasking delegates there is some code which is taking time in completion. For more info lokk at these
http://developer.apple.com/library/ios/#technotes/tn2151/_index.html
http://en.wikipedia.org/wiki/Hexspeak