Many UIViews + QLViewController = very slow performance - ios

I am building a calendar control. It generally works well and is responsive, despite using hundreds of UIViews (each cell in the example image is a UIView).
http://i.stack.imgur.com/6g1hQ.png
I have run into a problem in which the calendar is put in an app. It is fully obscured by some other controls and finally by a Quick Look viewcontroller. When the Quick Look is dismissed it takes a long time (10 seconds) before the app appears to respond.
Any view other than Quick Look has no slowness symptoms
Any help would be appreciated.

The problem was Autolayout. It simply cannot handle more than a trial number of views. Each nested view impacts the rendering time exponentially.
I end up writing my own "MagicLayout" system that does the same job, but it takes about 500 ms instead of 10000ms. The amount of time to dismiss a ViewController went from 10 seconds to about 10ms
Coming soon to a Xamarin component store near you.

Related

iOS CPU Activity Suddenly Dies

Long story here, so bear with me...
I have a view controller which, when presented more than three times throughout the life of an application session, will hang and lock and freeze my entire application. Even the Springboard locks up until my app's fully backgrounded! In Xcode's inspector, I noticed rather alarmingly that the memory footprint would jump a good 5-8 MB every time I presented that view, and it wouldn't go down again after dismissal. By the time the fourth invocation rolls around, the app's already using 40 MB of memory.
My first thought was, "OMG, itz a memry leek!" The second one told me to hop into Instruments and track it down.
While the Leaks tool did help some, it only told me that the app was leaking like crazy. All it would tell me was that, somewhere in these four second intervals, I had gained between "4 new leaks" and "17 new leaks." They did correspond to my opening that view, though, and once I started commenting random stuff (and following the sometimes helpful guidance of the Allocations tool), I tracked most of them down to three extra lines of code. "Oh well, I don't need those views anyway!" Those three lines no longer exist, and Instruments no longer complains.
My only complaint here is that my UI still behaves the same! On the fourth presentation, the entire app slows down. Upon further inspection of Xcode's instruments, I see that not only is the memory still going up (only to 30 rather than 40 MB this time), but the CPU activity has tanked!
Ok, granted I should have looked there in the first place, but I ain't perfect!
I ran the app again, and found that the overall CPU activity rose consistently the more I presented that view controller. By the third one, it was up to 40-60%. The main thread seemed pretty clear, and most of the activity was spread between eight other background threads (who knows what all those do).
The fourth time I opened that view, I had expected everything to block like crazy. It didn't. The CPU just... stopped. It was running at around 50-ish% when, by the time my finger had left the screen, it was down at 1%. All of the thread graphs shrunk from spiked stalagmites to tiny waves in a puddle. According to the pie chart, the vast majority of the processor was free to do as it liked. It doesn't like me.
I literally have no clue why it does this. I've been stuck in a room for days now trying to figure this out. Any help or advice would be much appreciated.
Does anyone have any idea why this happens, how this happens, or what I can do to make this not happen?? I'm drawing a blank here...
Thank you so much!
It should be noted that I got these by running the app on my iPhone 5s. Yes, I did try on the simulator, but my little MacBook Air took it like a champ, and was no help in figuring this out, except to tell me that the problem happened on iPhones.
I've run into this before, and the following is my general approach that usually allows me to fix these types of memory leaks.
First I would put a print statement into you viewController to see if your VC is being deallocated when it is being popped.
deinit {
print(self.description)
}
The next step, in the case that the ViewController is not being deallocated, I would start by removing core pieces, bottom up, commenting them out chunks one step at a time, yet leaving the back control that hides the view controller visible. Usually you can isolate the memory leak once you see the deInit get called after removing some code, you may have hit the part that made a strong cycle reference.
One more thing, ensure that all your delegates are declared weak, and search through your code for closures, and check that the closures aren't holding hard references within, especially to self.
Also, checkout this article to see the about using unowned or weak, when passing in instances into a closure, could be helpful.
http://krakendev.io/blog/weak-and-unowned-references-in-swift

UICollectionView paging breaks after 2^24 pixels

The setup
I have a UICollectionView that allows the user to page through pictures, 12 to a page. There are upwards of 200,000 pictures that should all be available in the app. I'm not expecting a user to scroll to page 20,000, so there's function to jump to a certain page.
The problem
In landscape orientation, paging breaks down on page 16,385. The collection no longer adjusts to the page boundary. If you go back before page 16,384, you can get it to start working again, but no page past 16,385 works.
My delegate also stops getting scrollViewDidEndDecelerating: the message when the bug shows up.
The hypothesis
Page 16,385 in landscape orientation happens to start at pixel 16,777,216 which happens to be 2^24. I think that there's something in UICollectionView or UIScrollView that breaks past 2^24.
Is this just an undocumented limit? Am I out of luck?
The example
I've uploaded a project that demonstrates the problem. Here's the relevant view controller. If you shake your iPad or the simulator, you'll be taken to page 16,384, one page before the bug shows up.
The snark
If you don't think a user should need to be able to go to page 20,000, that's cool. I don't think it's relevant to the question.
I'd say this is an undocumented limitation and would file a Radar bug report, attaching the sample project as evidence. If you are looking for an alternative method, you could try using a UIPageViewController with a collection view for each page. You can choose the swiping animation, rather than the default iBooks-esque animation, and replicate your sample project very closely.
You could just load say 10,000 pages and when the user jumps, load an appropriately different 10,000 pages.
I wonder whether you've tried using multiple sections? Is the limitation per section or for the entire CV?

Jittery WebGL Scroller

I've built a scroller prototype using WebGL. The problem is, when it's combined with other non-WebGL elements on the same page, the scroller becomes jittery and the quality is quite poor. You can see a demo here (scroller is at the bottom, ignore the Chinese characters) - http://viewer-test.appspot.com/Viewer.html?type=presentation&id=6a169bb8-e440-4338-9e3a-8b5e429f32ee&showui=false Even if I take out the video, the scroller still slows when the CPU spikes every time that RSS feed top right shows a new feed snippet.
I had considered using Web Workers to run the scroller on a different thread, but came across another post in this forum that said that Web Workers can't be used with WebGL. What are my other options to ensure smooth scrolling?
Thx.
Are you using RequestAnimationFrame for your animation callbacks? If not, you should. It's managed by the browser to time the draw of your element with the others on the page and with the system screen sync, so you get the smoothest presentation possible. If you do your animation using setTimeout or setInterval, you'll almost always end up out of sync with the pages rendering, which leads to dropped frames and stutters.

iPad performance issues

I have this problem with performance of my iPad app..
For developing, I use MonoDevelop, which takes care of Garbage collecting. Still my questions are rather generic, I'd say.
OK, I use TabBarController with 5 NavigationControllers. Inside nav controllers there are some controllers, whose views are TableViews or ScrollViews. Next child is always just regular view.
I have a few questions:
1) TableViews never scroll smoothly. I have some alpha transparency, but since I did my graphics in Photoshop and not programmatically, this transparency should not cause much problems. It doesn't matter whether I have few or many results in table.
On the other hand, I have ScrollView which serves same purpose, i.e. to be a table with different layout and buttons have Photoshop generated transparency as well. It works perfectly.
For tables I applied DequeueReusableCell() which works fine (I see that memory usage is not increasing after scrolling). So why would tables scroll so jerky?
2) My app supports rotation. When I scroll table or scrollView and simultaneously tilt the device a bit, I get maybe 1 or 2 FPS. What is the best way to implement rotation? As I understand, ShouldAutorotateToInterfaceOrientation has to be overridden in all controllers in NavigationController chain. Also, I need to add observer in View I want some changes to happen. Do I have to use BeginGeneratingDeviceOrientationNotifications() in all views or is it enough to do it in Main.cs? Maybe this slows it down?
3) After some time app starts getting memory warnings and then crashes eventually. I tried to read logs and run app with Instruments, but can't find the cause of crash.
4) What exactly happens to a View popped from NavigationController stack? I can't reuse it. But could it be that Monotouch (or me) doesn't dispose it correctly?
I have almost same app for iPhone without support for rotation which never crashes. I think I'm doing something wrong with this rotation, but I'm not sure what.
Any help will be appreciated the most. So, thank you in advance.
Regards
1 - transparencies are always a problem. Even if you're not rendering the images in code, the phone still needs to do the compositing of the image, and that may take a lot of time. UITableViews have to calculate the final composite image every time a new cell is displayed, or the table is scrolled, while UIScrollViews can calculate only once, since the image won't change. So be very careful about it, turn the transparency off, and check if performance improves.
2 - You shouldn't need to notify every uiview in your application. Receive the notification in the controllers that you want to update only, like for example if you want to rearrange items in the UIViewControllers view.
3 - you have one (or many) memory leaks. My guess is that MonoTouch probably can't garbage collect UIViews or UIViewControllers, because they're still being linked from somewhere in UIKit, like a UINavigationController
4 - UIViews are not disposed by UIKit until the app gets a memory warning notification.
Like Eduardo said, alpha transparency in Views comes at a price. There are some tools that you can use to identify the bottlenecks discussed in these WWDC 2011 talks from:
https://developer.apple.com/videos/wwdc/2011/
iOS Performance and Power Optimization with Instruments
Understanding UIKit Rendering
In the "Debug" menu of the iOS simulator you can find various debugging tools that will color different regions of the screen indicating where some problematic rendering is taking place. The WWDC 2011 talks show what you can do to fix those problems.
For your memory problems, it is very likely that you have something pointing out to your objects around, so you need to make sure those objects are gone. While we currently are not shipping our new profiler for MonoTouch that can show the source of the problem, I wrote a "poor man's" debug utility that will help you narrow down which objects are alive. It is available here:
http://tirania.org/tmp/HttpDebug.cs
Call HttpDebug.Start () from your application and as you run, connect with a web browser to http://localhost:5000 to get a list of live Objective-C objects surfaced to C#. The tool is not perfect and shows a lot of irrelevant data, but it would at least give you an idea of what is going on.

AS2: Wait for actionscript to run before loading frame

I have a script that takes lots of content and builds 1000s of MovieClips on the stage, does lots of drawing etc. Due to the high amount of work needed when the frame first loads this can sometimes be delayed by a second or two.
The more the user uses the application the longer and longer this is likely to be (more data to siphon through and build).
My question to you is how do I make sure the frame doesn't show (serve a loading image or something) until it is built? I don't want the user to see the skeleton of the page and then everything appear a second or two later.
The way we do it:
Frame 1 is a loading frame. It simply continually polls progress (onEnterFrame) until it is sufficiently "complete" to move on to the frame that is needed. In your case, it might be that you're testing to see if you've instantiated enough objects, in our case it was whether framesloaded was sufficiently high.
We often put a "loading graphic" in frame 1. Other than that we have the "am I ready to finally move on yet?". Most recently our loader just had a circle which continued rotating.
As a side note: wait until everything is completely ready if you're working with an AS3 loader. Loading half-cocked left me working until 3 AM on Easter one year. I was not happy.

Resources