Can I build UIView elements on a separate thread? - objective-c

I have an app that has to load and render a fair amount of content onto screen (mostly loading from a database).
I won't post all the code here but in effect it simply builds up a set of UIView objects that are added to a UIScrollView object. Nothing too complicated, just loaded quite a lot of stuff. This currently takes a second or so render everything (running on the main thread).
I want to show an activity indicator whilst the loading is happening, and I think the best way to do this is to have the method that takes a long time happen on a background thread and "report back" when it is complete.
The question is this. I know all the actual drawing is done by the main thread, so is it possible to create a new thread and have that build up a set of UIView objects that are then drawn on screen?

there is a great WWDC2012 session video, that deals exactly with your use case:
WWDC2012 Building Concurrent User Interfaces in iOS
Basically the trick is to prepare and draw the views on another queue and ship it over to the main queue.

You are correct. All the UI work should be done on the main thread. In your case I would suggest you to add the UIView object which are visible to the scrollview and add rest of them only when scrollview starts moving to that point. You can keep on adding views once they are about to be visible and remove any views which are not needed from the scrollview. This normally helps in better memory management.

Related

What may cause all UIView animations to finish instantly?

I have an iOS app where I use a lot of UIView animations. They'll all work perfectly for a very long time, then suddenly all animations finish instantly instead of using the specified duration. No errors and the app still functions, but the animations don't work properly.
The app will do a lot of downloading small graphic files in the background then call a selector on the main thread to present the graphics.
Does anyone know what may cause this kind of behavior?
I know it's not okay to handle UIKit in backgrounnd threads but thought it was limited to all drawing, like adding subviews etc. It seems creating and changing views (without adding them as subviews) is not okay either. My problem in particular was creating UIImageViews in a background thread. I changed the code to load into UIImages and create the UIImageViews in the presentation code, which is run in the main thread and now it's completely stable.

iAD best practices for shared AdBannerView's and animated transitions

I have a global ADBannerView that I show on most of my top-level Views. When each view loads, it does a -removeFromSuper on the adBanner, then adds it as a subview.
However, when animating from one top-level view to another, this causes the ad to suddenly disappear from the departing view before the transition starts.
I've tried using viewWillAppear/Disappear as well, but in each case, they don't seem to get called at an appropriate time to remove/add the banner.
I assume it's a very bad thing to have the ADBannerView's view belong to subviews on two different top-level Viewsat the same time.
The only other thing that comes to mind is animating away the ad before the transition occurs; another animation in the queue would be a bit of a pain, though, and seems like a misguided solution.
Is there any other reasonably simple and elegant way to share an ad banner between top-level Views where transitions are involved?

Slow UITabBar item loading

There is the problem in my project, this problem can bring lots of unpleasant feelings for customer.
So app is basically ground on UITabBarController and when I want to load one of UIViewController it loads too long (~ 1.5s in first launch and after switching there is seeing pause) - its very bad for user experience, as you know.
So I want to know some way to preload this section before user want to enter there (section doesn't loads first). There are few questions which can be the same with first glance but I don't want to have a solution like "spinner while loading".
If anybody knows elegant solution I'll very thankful.
Alexey
To me this sounds like you do lot of work in either your init method, the viewDidLoad or the viewWillAppear method of your UIViewController.
On the first load I don't know an answer, but you could load the other view controllers in the UITabBarController in a background thread so they are loaded when you tap them.
EDIT:
On first load you could use a very simple start screen and load the first screen also on the background thread. But then you would have to add a new view.

UIPageViewController optimization and possible solution

I am using a UIPageViewController in my app to display number of images (1024x768 size). Is it ok to make array of UIViewControllers each with his picture and in set appropriate for each page? Maybe if you get like 50 pictures it will crash? At the moment I store images in Documents folder so I can remove images from view controllers that are not on screen
This wouldn't be very efficient, you'd be much better off doing the same thing with UIImageViews. Even then you have to be careful. Probably the best way to handle this would be to using image views and deallocating them when they go more than one image width out of the screens bounds. Then of course reallocing when the image in question is the next image in line to be displayed in either direction.
EDIT: It looks like you can use the following UIPageViewController Datasource methods to set which view controller do basically have queued and waiting to the right/left. Using these you should be able to only allocate 3 view controllers at a time.
– pageViewController:viewControllerBeforeViewController:
– pageViewController:viewControllerAfterViewController:
Then you can use this to set the initial controller:
Set the initial view controller using UIPageViewController's
-setViewControllers:direction:animated:completion:
The sentence below is quoted from Apple's documentation and is leading me to believe that the controller may be able to only load the necessary view controllers into memory on its own.
View controllers are either provided one at a time (or two at a time,
depending upon the spine position and double-sided state) via the
setViewControllers:direction:animated:completion: method, or provided
as-needed by the data source. Gesture-based navigation is enabled only
when a data source is provided.

Loading UIViews in the background on application launch

I have a simple iPad application with 5 views. On the first view, the user is asked to make some selections and set some options. From this information, the other 4 views are programatically changed after an NSNotification message is sent to them. (i.e controls are added, updated).
My problem is that when the application is first loaded, the user sees View1, but View2, View3, View4 and View5 have never been opened yet, so any changes I make programatically to those views are not done and when the user navigates to them (via the tab bar) for the first time, no changes are shown.
[EDIT: I should point out that the code for making the changes to each view is contained within the ViewController itself, and is executed when the view observes the incoming NSNotification. When the view is not loaded, it understandably never received the incoming NSNotification.]
Only after the user looks at any of those screens at least once and then goes back to View1 and makes changes, are the other Views updated properly.
I thought I could get around this issue by actively loading Views 2,3,4 and 5 into memory on application start, so that they are ready to begin receiving notifications right away.
Is there an easy way to do this in iOS 5?
Why do the view changes straight away?
I would store an indicator of the changes needed when the users answers the questions on the first view and then apply the changes on -viewDidLoad of each view that needs to be changed.
Instead of trying to load the views into memory, I'd suggest you initialize these views with the options that the user set on the first view. What I usually do in such situations, when I have a global parameters that are used in many places, I create a utility class to keep the data, make it a singleton, then access the shared instance in the viewDidLoad in the views that use the data during initialization.