I have a set number of ViewControllers in my app. They are allocated and initialized at application launch and released at exit. They are used by a NavigationController to be pushed/popped. In these ViewControllers there are WebViews (actually there is nothing else).
My problem is :
When I want to change de content (URL) of a WebView that is not on the current TopViewController, the content isn't loaded until I push/pop the associated ViewController.
And the transition us "ugly". The pushed/popped Viewcontroller shows old content at worst or blank page at best, before the ViewController is in full view THEN the new content is shown.
I tried lots of things (even putting the "loadRequest" in a different thread with looks stupid).
Do you know any way to make things go smooth?
In general you should plan your UI for slow UIWebView loads, because you can't plan ahead to know how long things will take. What I often do is have a UIView that has a spinner and a message such as "Loading..." that is layered on top of the UIWebView. Here's how I use it:
In viewWillAppear: I unhide the loading view and start the spinner.
In webViewDidFinishLoad I hide the loading view.
If webViewDidFail gets called, then you're not showing some interim or invalid content while the page loads. You can present a UIAlertView in that case.
If you're curious, you can see this in the high score page of my game (Lexitect, free)
Related
IPhone SDK - Leaking Memory with performSelectorInBackground
seems to suggest you can actually pushViewController in background thread.
But I get a warning from stackoverflow people that I shouldn't do this.
eg. (iphone) start timer from background thread?
is pushViewController considered "UI updating"?
(because I know that UI updating should be done in main thread only)
If it is so,
when a viewController takes a while to load, and want to show an indicator while loading.
What is my option?
Couple of strategies here.
1) BEFORE you do the push, but at the point you know you are going to do it, bring up a suitable activity view on the current view. I do this in some apps where you click on a row in a table but the pushed view has to do some web comms that takes time, so I leave the table cell highlighted in blue and add a white spinner to the left of the disclosure indicator. Works well.
2) Use lazy loading to get the new view controller on screen quickly, but defer the heavy code until after it has loaded so that the new controller can look after it's own activity view. By lazy loading I mean you should do as little as possible in the init method and make careful use of viewdidload / viewwillappear / viewdidappear etc to spread the work out and get an activity view on screen as soon as you can.
Suppose I have a navigation controller where the next action is to take a picture or select an image from the library.
If I initialize UIImagePickerController during didSelectRowAtIndexPath:, (I believe) the response will be a little slower as the controller needs to initialized. Also, if the user cancels and opens again, it would reinstantiate that controller every time.
However, if I create the controller during viewDidLoad: of the navigation controller, it takes up memory while the user is on that view. Side questions: Does this, however, slow down the loading time of the navigation?
Or should it be done in an NSOperation when the view is loaded?
Overall, what would be the best place to load the ImagePicker?
I'd lazy load the controller when it first gets called (in didSelectRowAtIndexPath) so it wouldn't have to be reloaded every time, and not worry about initialization time.
It seems that in your case you will always need an image picker on didSelectRowAtIndexPath. You can load it on the view and customize (camera, cameraroll, etc.) and present on the row selection. Probably it doesn't matter that much. UIImagePickerController presentation is very slow anyway, especially with the camera.
I don't recommend an NSOperation for this task.
how do I use multiple UITabBar tabs for controlling a single UIWebView?
An Example:
Pressing tab1: UIWebView loads index.html
Pressing tab2: the same UIWebView loads customers.html
Pressing tab3: the same UIWebView loads tos.html
My approach was to put the UIWebView in the AppDelegate and set self.webview of every ViewController to that single UIWebView. However, the WebView gets displayed, but is white and doesn't load anything.
Any hints?
WebViews are expensive so your approach is probably right, but you may want to start out with creating a separate webview in each tab view controller and see if things are working as you expect there first. The overhead may start causing your app to start receiving memory warnings, but this would at least allow you to see if your pages will at least load correctly in that context.
Also, can you post some code that shows how you're adding your webview to each view controller? If you are not setting the frame of your webview using -setFrame, once you've added the webview as a subview of your view controller view, it won't show up correctly.
You need to -removeFromSuperview and then -addSubview to move the webview around; just re-assigning to an instance variable won't do the trick.
A tab bar is really the wrong model for what you are trying to do. If you want to switch content what you really want is a ToolBar, because that is meant to alter an-place view in various ways - TabBar is meant for switching between multiple unrelated views, and as such you are fighting against it when you try to use the same view across multiple tabs.
Now if you really have totally unrelated content, why not consider just using different UIWebViews, one per tab. They are not so heavy that loading having multiple instances really hurts anything, and tabs do not load content until pressed so they will not all load at once. To conserve memory you could even toss away view controllers when tabs are switched. But having each view manage its own web view makes more sense and means you can keep the content cached much easier.
i am having a UIWebView showing and HTML page that has some checkboxes, radio buttons. My Application has tabbar controller that switches b/w two controllers. How i can maintain the current state of UIWebView. ( e.g. i have selected a checkbox and i change the tab and go to other ViewController and again come back to UIWebView. the WebView resets itself and goes to the start... i want to maintain the state of UIWebView ( all the checkboxes clicked) .. how i will do that ??
any idea ??
thanks in advance
It sounds like you're loading your web view in viewDidAppear:, or some other method that gets called each time you switch to the tab. If you load your web view in viewDidLoad:, it will only get loaded once, and will retain its state when you switch tabs.
EDIT: When I wrote this answer back in 2009, I apparently didn't understand the view controller life cycle as well as I thought I did. Corey Floyd was right. The viewDidLoad: method can also get called multiple times, because UIViewController will unload its view in low memory situations if the view isn't being displayed. When the user switches back to the view, viewDidLoad gets called again to reconstruct the view.
How embarrassing.
I have an idea that might help:
to get the status from your app to the webpage, give the variables' values as request parameters with the called URL and let the webpage handle them and view the form elements accordingly.
to get the status from the webpage back to your app, let the webpage be refreshed each time any of its element is updated, and with the new URL give the new values of the changed elements. Back to your app, you can implement the UIWebViewDelegate and inside the method WebViewDidFinishLoad (or WebViewDidStartLoad as you prefer) use the webView.request.URL to parse the GET parameters and update your app accordingly.
hope this will help.
I have looked at the PageControl example from Apple and have an architectural requirement difference. In the example the scroll view and page control objects are at the app delegate level. This means the scroll view and page control appears on every view of the application.
However, I have a "settings" view toggled from an info button (for now) that should not have these controls displayed. Therefore, I need to move my scroll view, page control, and view controllers objects down a layer and I'm struggling with how to best do this.
For example, the primary application view consists of metals (periodic elements). From this view I need a scroll view, page control, and info button on every view descending from here. Each metal will have it's own subclass where different images, calculations, etc will be displayed but I believe I need each of these subclassed elements to share the same scroll view, page control, and viewControllers array, right? Do I need a singleton?
What you are describing is kind of like how the native Weather application works. Each time you swipe, the info light is rendered as part of the page you are viewing. However, no matter what info light you tap, when it flips over you still get the same settings. Obviously this is how Apple thinks the UI should work because they did it that way. There is no reason you can't do the same.
In this situation, you don't need to create a singleton, you can use [UIApplication sharedApplication] as your singleton to get to your custom application delegate via the delegate property.
Look at Crème where I do exactly what you describe. The main view is scrollview+pagecontrol. Upon triggering the app into settings mode, the settings panel comes up that does not have a page control.
The solution is simply that you have a simple top-level UIViewController, and you make both the scrollview and pageview children of that viewcontroller. And for settings, you animate the modal settings dialog with a flip animation into the top-level UIViewController.