Displaying a loading indicator for UIWebView using UIActivityIndicatorView

Posted by Filip Ekberg on December 1 2010 4 Comments

More and more apps today uses only the native application as a shell around their web-based application to get their app into App Store. A drawback with doing this is that you might get really annoying load times and you have to decide where to put the “wait for the data”-scene.

In my opinion you have two alternatives

  • Either you load all data in the App Delegate and have the Default.png shown untill all data is downloaded
  • Or you can start the loading in the App Delegate and not wait for it to finish and display a loading indicator once the application finished loading.

I’ve evaluated both of these methods and find that the second one enhanced the feeling of the application, no one accepts to wait for 5 seconds before an application is somewhat interactive.

Therefore I’ll show how to add a Loading indicator using the UIActivityIndicatorView.

You need to declare the UIActivityIndicatorView in your header file so it is accessable from all delegate methods.

UIActivityIndicatorView *loadingIndicator;

Then you need to initiate a UIActivityIndicatorView like this:

loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(145, 190, 20,20)];
[loadingIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[loadingIndicator setHidesWhenStopped:YES];

The first line allocates the resources for a UIActivityIndicatorView and the initializes it and puts it in the center of the screen, this is in landscape mode.

After that we set the style to gray and tell it to dissapear when we stop the animation. You can choose between three different color-schemes for this indicator. Check the apple developer reference for more information about that.

Now you are ready to add the loading indicator to you web view like this:

[webView addSubview:loadingIndicator];

I take for granted that you have a web view that’s called webView and that it has webView.delegate = self;. So that you can use the delegate methods to start and stop the loading indicator animation.

Now we are at the final step of the journey to get a loading indicator to our web view in the -(void)webViewDidStartLoad:(UIWebView *)webView delegate method we add the following:

[loadingIndicator startAnimating];

This will start the spinning loader inside the Web View, now to remove it, go to your delegate method for -(void)webViewDidFinishLoad:(UIWebView *)webView and add the following:

[loadingIndicator stopAnimating];

And you are all set! Now you should have a loading animation that displays a spinning wheel as long as the data loads.

Vote on HN

A work around to the memory leaks in NSXMLParser

Posted by Filip Ekberg on November 30 2010 7 Comments

Lately I’ve experimenting a bit with parsing XML in Objective-C and discovered something that I’d like to share with you all.

First of all, consider the following “standard” way of downloading an XML and parsing it

NSXMLParser *parser = [[NSXMLParser alloc]
            initWithContentsOfURL: [NSURL
            URLWithString:@"http://some-xml-url.com/my.xml"]];

You would think that this line of code is Solid, all it’s supposed to do is download the content, release the temporary resources for fetching data and store the final content for the parsing later on. However somewhere in the process there’s a resource that isn’t cleaned up properly and you will get a memory warning the “Build and Analyze” method wont find it but when you run the application with a Performance tool looking for leaks you will end up getting something like this:

Leaked Object
Malloc 512 Bytes

Responsible Frame
allocateCollectableUnscannedStorage

Leaked Object
NSConcreteMapTable

Responsible Frame
+[NSMapTable alloc]

I tried a lot of suggestions to fix this issue some of them being to set the sharedURLCache to 0 like this:

[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];

These alone did not solve the problem, so on the quest to find a proper work around I came up with this solution:

[[NSURLCache sharedURLCache] setMemoryCapacity:0];
[[NSURLCache sharedURLCache] setDiskCapacity:0];

NSData *xml = [NSData
        dataWithContentsOfURL: [NSURL
        URLWithString:@"http://some-xml-url.com/my.xml"]];

NSXMLParser *parser = [[NSXMLParser alloc] initWithData:xml];;

And that did it, after this I no longer received any memory warnings.

Vote on HN