iOS Diary: Showing an Activity Spinner Over a UITableView

I’ve only been developing for iOS for a couple of weeks now, but it’s already obvious how ubiquitous the UITableView is in user interfaces. This makes sense. iPhone/Pad/Pod apps are often of the “list info and drill” variety, and the UITableView brings a lot of utility to the, um, table for lists, and even for constructing static dialogs. UITableViews automatically scroll if your content is too long for the vertical screen space, and they give you a lot of control over how individual cells and rows are styled. In the app I recently worked on we used a UITableView to list some stuff that was fetched as XML from a REST webservice. The webservice was taking about 4-5 seconds to retrieve the data over a wifi connection, and I knew it would likely be slower over 3G data connections. To let the user know what was going on I wanted to display an animated activity spinner while the transaction was enroute. If you’ve used the YouTube app for iOS then you’ve seen one of these in action.

The spinner is displayed over the contents of the table view, without obstructing the tab bar control. You can freely switch to another tab while the spinner is displayed over the current tab. It’s a nice, clean way to show that one tab is busy, while allowing the other tabs in the application to remain available. When I tried to replicate this behavior in our app, however, I quickly ran into some quirks. UITableView might be a useful control, but it isn’t all that lenient about how its views are managed. More on that below. First, let’s make the spinner itself.

Fortunately the iOS UIKit contains a view called UIActivityIndicatorView that makes this a pretty easy task. Basically the indicator view provides the little animated spinner. You set up its properties and provide a container. Here’s what the declaration of a reusable spinner overlay might look like. The syntax highlighter doesn’t deal with Objective-C, so I am just using the C filter. Apologies if it doesn’t look right.

// MyActivityOverlayViewController.h
#import <UIKit/UIKit.h>

@interface MyActivityOverlayController : UIViewController {
    UILabel *activityLabel;
    UIActivityIndicatorView *activityIndicator;
    UIView *container;
    CGRect frame;
}
-(id)initWithFrame:(CGRect) theFrame;

As you can see, not much to it. We have an interface derived from UIViewController, with ivars to hold pointers to a label, the spinner, and a container to hold them both. There is also an init method that takes a frame. I’ll talk more about this below, but essentially I found it useful to establish the size I wanted the view to be at initialization. That gets stored in the frame ivar.

So that’s the controller interface. Next let’s look at some key aspects of the implementation. First the init method:

// MyActivityOverlayViewController.m
#import "MyActivityOverlayViewController.h"

-(id)initWithFrame:(CGRect)theFrame {
    if (self = [super init]) {
        frame = theFrame;
        self.view.frame = theFrame;
    }
    return self;
}

This is a pretty simple init method. First it saves the frame, because it will be used later to size and center the nested controls, and then it sets the size of the default view created by the UIViewController. Next we need to create the controls and build our simple view hierarchy. The overridden loadView method is where that gets done:

-(void)loadView {
    [super loadView];
    container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 110, 30)];
    activityLabel = [[UILabel alloc] init];
    activityLabel.text = NSLocalizedString(@"Loading", @"string1");
    activityLabel.textColor = [UIColor lightGrayColor];
    activityLabel.font = [UIFont boldSystemFontOfSize:17];
    [container addSubview:activityLabel];
    activityLabel.frame = CGRectMake(0, 3, 70, 25);

    activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
    [container addSubview:activityIndicator];
    activityIndicator.frame = CGRectMake(80, 0, 30, 30);

    [self.view addSubview:container];
    container.center = CGPointMake(frame.size.width/2, frame.size.height/2);
    self.view.backgroundColor = [UIColor whiteColor];
}

This method does a bit more work. After calling the superclass loadView it creates a container to hold the label and activity spinner. Having them inside a container makes it easy to center the group in the owning view. It then creates the label, sets a few style properties, and adds it to the container’s view as a subview. You can set these properties any way you want. I was shooting for essentially the same look as the YouTube app. The last thing that happens to the label is that its frame is set. The size of the rectangle used was figured out based on the font size and relative positioning I wanted, but what’s important is that the size was set after the label was added to its owning view (i.e. the container). I’m not sure why this was important, but it was. Hey, I’ve only been at this a couple of weeks.

The next thing that happens is that the activity indicator itself is created. You’ll note that I’m not autoreleasing any of these objects, so I have to make sure to release them in the dealloc override. I know that UITableView retains its added views, and if that is also true of UIView I could autorelease the controls here and let the view manage them, but as I wasn’t sure of the behavior I opted to play it safe. After the indicator is created it is added to the container view and its frame is also set. Lastly the container itself is added to the UIViewController’s view, it’s center is set to the center of the frame we saved in the init method, and its background color is set to white.

Just a few additional things to finish off the implementation. First we need to start the indicator spinning. The indicator view provides methods called startAnimating and stopAnimating for just this purpose, and you could provide pass-through methods on your overlay controller. That would be the way to go if, for example, you wanted to display the overlay and then start and stop the animation and alter the label as different actions occur. In my case I’m going to have it start spinning whenever its displayed, and stop when it goes away. For that purpose you can override viewWillAppear, and viewWillDisappear:

-(void)viewWillAppear:(BOOL) animated {
    [super viewWillAppear:animated];
    [activityIndicator startAnimating];
}

-(void)viewWillDisappear:(BOOL) animated {
    [super viewWillDisappear:animated];
    [activityIndicator stopAnimating];
}

The only other thing we need to do is clean up after ourselves:

-(void)dealloc {
    if (container != nil) [container release];
    if (activityLabel != nil) [activityLabel release];
    if (activityIndicator != nil) [activityIndicator release];
    [super dealloc]
}

And that does it for a simple implementation of a UIView that can be initialized with a frame size, and that will create a centered combination of a light gray activity spinner and light gray label on a white background. Now all we have to do is display it somewhere. That, as it turns out, is the tricky bit.

To get something on the screen we have a couple of choices. We could tell the tab bar controller to present it as a modal, or to push it as a page. Neither is a very good choice in this instance. Pushed controllers are not modal; they come with a back button by default. Modal controllers take up the whole screen and prevent access to the tab bar. So that’s not what we’re after. The other alternative is to play with views. To do this we would create an instance of the ActivityOverlayViewController, and then pass its view to the addSubView method of our UITableView’s view.

None of my attempts at doing this worked. I tried different combinations of methods to insert the view and then bring it to the top, but whatever I did things got screwed up one way or another. Toward the end I actually got it to display, but the table view drew the cell border lines over it, and that I was not able to work around. Instead, what I had to do was insert the activity spinner view as a subview in the view that owned the table view. In other words, it had to be a sibling view of the table view, not a child, and it had to be on top. Here’s what I came up with:

-(void)showActivityView {
    if (overlayController == nil) {
        overlayController = [[ActivityOverlayViewController alloc] initWithFrame:self.view.superview.bounds];
    }
    [self.view.superview insertSubview:overlayController.view aboveSubview:self.view];
}

So the first thing to note here is that my activity controller is initialized with a rectangle representing the bounds, or inside dimension, of my table view’s superview. The second thing is that it is explicitly added to that view using the method that let’s you specify a view over which it should be placed in the view stack. In this case I want it inserted above the table view.

And that pretty much does it. Add that method, and an ivar to hold the pointer to the ActivityOverlayViewController, to the controller for your table view and you’re all set. To get rid of it when your background action is done, call:

-(void)hideActivityView {
    [overlayController.view removeFromSuperView];
}

And of course remember to clean up after yourself in your dealloc method. Here’s what the result looks like…

The final caveat is that as I mentioned above I am quite new to all this, so if somebody knows a better way to get this done then I hope to hear of it. Meanwhile this works and achieves the desired behavior.

iOS Diary: When is a Property Access Not a Property Access?

Today I ran into a memory error in the iOS application I am working on. The event had special significance for me because I think Clinton was president the last time I saw an actual access violation. C# .NET programmers enjoy the benefits of a managed execution environment, and we don’t see those things much any more. I remembered them from years of C and C++ programming, and I knew in general what to look for, but figuring out specifically what patterns represented risks in Objective-C required reading up on how memory management is handled for Cocoa apps running on iOS.

The answer is that it ain’t much handled at all. The scheme relies on manual reference counting using messages like retain, release, and autorelease, and there are a number of rules for when you should send these messages to a given object. One blog post I read called this a “convention-based” regime, which is a good term for it. The important thing when adhering to a convention is to understand what the rules are. Fortunately the rules for Objective-C aren’t numerous or difficult to understand. In a nutshell: if you own an object you must release it. The corollary might be: if you release an object it better be one you created, or one you have taken ownership of by sending it a retain message. The whole thing rests on knowing whether or not you own an object. One of the places where this gets tricky, as old C++ hands will have no difficulty believing, is in property sets and gets.

Fortunately the rules here aren’t all that obtuse either, and they boil down to: when you set a property release the current value, and retain the new value. There are some variations, but in general that’s what you’re going to want to do. Code that gets the value of a property should adhere to another rule: when you receive an object from a method not prefixed with alloc, init, or copy, or when you are passed an object as an argument to a method call, you don’t own it. You don’t release it unless you have first called retain on it. If everybody plays by those rules then everything works fine, but of course that’s always been the rub with primitive languages: voluntary compliance.

In any case, our code did appear to play by those rules, and yet it was still crashing. The scenario was a simple one…

@interface SomeClass
    int someProperty;
@end
@property (retain, nonatomic) int someProperty;

The @property syntax tells the compiler to generate accessor methods named ‘someProperty’ and ‘setSomeProperty’ that adhere to the rules for setting and returning properties. The ‘retain’ and ‘nonatomic’ attributes are instructions to the compiler on how to generate those accessors, in this case adding code to release/retain in the setter, and not adding code to guarantee transactional atomicity. Based on what I could see we were adhering to best practices in using the @property syntax to implement our properties. And yet… it was still crashing.

The line that was faulting looked like this…

self.anotherProperty = someProperty;

Veteran Objective-C programmers will already see a problem here. The line above was faulting trying to read someProperty. The value of someProperty had been set earlier in a line that looked like this…

someProperty = aStringWeWerePassed;

Veteran Objective-C programmers may actually be laughing audibly at this stage of the discussion. The problem with these two lines of code is obvious to them, but it’s the kind of thing a C# programmer would blow right by without a second thought. Naturally, if you define a property and then assign to it, the setter method is going to be invoked. Right?

Uh, no. I’ve been learning as I proceed deeper into this thing that the best way to grok what is going on in Objective-C is to let the old C ethos flood back into your soul. If you never had a C ethos, because you never worked in C, may your deity of choice aid you. In ‘Old C’ the compiler knows diddly squat about properties, and it doesn’t know when to turn a simple and obvious assignment into a call to a method. It doesn’t know unless you tell it, and the way to tell it is like this…

self.someProperty = aStringWeWerePassed;
// or
[self setsomeProperty:aStringWeWerePassed];

Either of these will work, but what we were doing was a simple assignment of one pointer value to another, without going through the setter method, and without calling retain or release or any of that stuff. Specifically, the reason the program was crashing is that when you are passed an object in a method (in a callback from NSXmlParser in this case) the object is guaranteed to be around until the method that passed it to you returns. If you want to keep it longer than that you call retain on it. That’s what happens in the property setter, except that as you know now we weren’t going through the property setter when we set the value. By the time we read that value later the memory had been deallocated.

Objective-C, as I have grown fond of saying, actually is your father’s programming language.

More on Remote Connections to the VS Web Server

Well, I may have been a little premature in my post below on using port forwarding to connect a remote client to the Visual Studio development web server. When I tested the approach my app was able to connect and begin a request, but there was a database problem that was masking the result, and I assumed that when it was fixed the request would round-trip successfully. Instead I found that the request wasn’t completing because the connection was being reset. I still think the technique will work, but since I am not sure why it didn’t in this case I thought I should clarify the post. Here’s what I saw:

I set up the services to run under the development server on localhost:35000. I then started Portforward.exe and set up a redirect from 192.168.0.100:8888 (the dev machine’s local address) to localhost:35000. The remote client is an iOS app running on an iPod Touch connected via wifi with the address 192.168.0.111. The request was received successfully, the service processed the request successfuly, the result was serialized successfully, but once I let the program run out of the service method the client would report a connection reset. This was tested from the iPod, as well as from a simple console client on another windows box, with the same result.

I fired up Wireshark and monitored the exchange. The inbound request was sent in two packets. The first contained the POST header, and the second contained the request body. After the service finished processing the response header packet was written (including 200 OK and the correct content length), and then RST was sent and the connection was dropped. So, given this scenario I am sort of suspicious that the problem lies with Portforward.exe, but I don’t have time to find a different forwarder, or write one, and test it again. Until I do I can’t really say that the technique will work. In the end I had to go ahead and install IIS to enable the full debugging scenario I needed.

Remote Connections to Visual Studio’s Web Server

The integrated development web server in Visual Studio is a handy tool. Since its introduction developers of ASP.NET web applications and web services have been able to build and test their code locally, without having to take the post-build step of publishing to an IIS server first. A nice tool, but a slightly crippled one. Presumably because Microsoft did not want people to use the full-featured server to deploy production applications it only accepts connections from localhost. In my current work on an iOS app I wanted to issue http requests from an iPod Touch over a wifi network, and send them to a REST web service running under Visual Studio 2010 on my development machine. Ordinarily you can’ t do this. You’d have to install the service code in a local instance of IIS and set VS up to step through it there.

If you Google around on this problem you’ll find a number of solutions. The actual code inside the server that rejects remote connections is just a couple of lines and not at all complicated. For this reason some people have suggested using ildasm to disassemble the web server assembly and comment out the relevant test. But there is a much easier and less intrusive way to get around this problem, and it just takes a couple of minutes to set up.

First, find and download a port forwarding utility for Windows. I use Portforward by Trent Waddington, because it is small, requires no installation, and is easy to use. His download link is to an exe file so I won’t post it here, but you can find it midway down this page. What you’re going to do with the port forwarding utility is make Visual Studio’s web server think your connection is coming from localhost, when in fact it is coming from a remote device.

Once you have the port forwarding utility, open up your VS application, and get into the project properties dialog. Click the ‘web’ tab and look for the ‘Servers’ section of the property page. The radio button next to ‘Use Visual Studio development server’ should be checked. Below it check the radio button next to ‘specific port’, and then type a port number into the edit box on the right. I usually use 35000. Save the project properties. Build and run. Your web application is now running on the dev server and listening for http connections on whatever port you chose.

Now start the port forwarding utility and set up a forwarding rule. You do this in various ways in different tools, but in Portforward you click “Redirections” and then “Add” and it pops a little dialog. Let’s say that the machine you’re running the web app on has an IP of 192.168.0.100, and your client is going to try to connect to port 8080. Set up a rule that forwards 192.168.0.100:8080 to localhost:35000 and you’re good to go. Now when your client connects the connection will be redirected to the development web server on localhost, which will make it happy, and make you happy at the same time.

iOS Diary: XCode Project and Target Settings

After a couple of years of Silverlight and WPF/WCF development on .NET I got handed a nice new assignment the other day, along with some shiny new toys. The job is to complete a partially-implemented iPhone/iPod app, which requires coming to terms with a few technologies that are new to me, namely Objective-C, Cocoa Touch, Xcode, and iOS 4 itself. It’s a bit of a dream assignment as far as fun factor goes, and I hope my boss doesn’t read this blog. He’d probably start thinking I should be grateful. And perhaps I should, if not for the project then at least for the Macbook Pro and iPod Touch 4G that came with it. Both are slick little bundles of cool, albeit at premium prices. But who can hate a free loaner? I powered up and dove in.

The learning curve is surprisingly gentle for a developer with a background in C/C++. Yes, Objective-C syntax is whacky, and it is very dated in terms of its support for object-oriented programming. Cocoa Touch is like any other deep class framework/UI toolkit, and will just take awhile to learn. The tools and environment, fortunately, were much less of a hurdle. The Mac is a Unix box deep down; all the old familiar commands work, and what you do through the GUI is intuitive enough. Xcode itself is not utterly alien to anyone who works in an IDE, but it does have more of an Eclipse feel to it, and it has a few gotchas. One of the ones I encountered today involves how project and target settings are organized.

A little background first. There are two ways to test an iOS application during development. You can use the simulator that comes with the SDK, like the one Google ships with their Android SDK. That works great for most things, but eventually you’re going to want to run your code on a device. If you’re developing an app that works with the push notification service eventually comes sooner, because that API and service don’t work with the emulator. One of the differences between the emulator and an actual device is that applications pushed to a device must be signed with a developer certificate, and the device must have a provisioning profile pushed to it. My problem came in the code signing phase.

After you create your developer certificate on the Apple iOS Provisioning Portal, and have it downloaded and installed, you have to tell XCode to use it to sign the linked binary before copying to the device. The likely place to look for this, it seemed to me, was in the project settings, accessible from the XCode Project menu. And indeed that’s where you’ll find it, in the fourth section down, entitled “Code Signing.” In my case, because the code had been worked on by another developer, his certificate was still specified for signing purposes, and wasn’t installed locally for obvious reasons. I changed this setting to my own certificate, and assumed all would be well.

All was not well. When I tried to build I got an error complaining that the compiler couldn’t find the right developer certificate, and there in the error text was the other developer’s name. Now wait a minute here… I went back in to the project settings and scanned them all carefully: no other occurrences of his name in sight. I reinstalled my dev certificate and reprovisioned the device. Still no go. I sent an email out to the guys who had worked on it before, and who responded promptly with a couple of Google search results, but they all dealt with situations where the developer is using the wrong or an invalid cert. I knew mine was valid. I even tried searching for the other dev’s name using Spotlight. Nothing.

Eventually I stumbled on the contents of the project package and realized that the project file was stored inside it as XML. In the XML document I found the XCBuildConfiguration section listing my cert, and the other dev’s. Obviously he was still associated with the project, but how and why? I had looked the project settings over very carefully, and he wasn’t in them. In tracing through the references in the project file I realized that I was associated with a configuration called “PBXProject” whereas he was listed in the section for “PBXNativeTarget.” Resisting an impulse to just edit the damn text file (a couple of hours had gone missing by now) I headed back into XCode, and finally figured it out.

In the XCode “Projects” menu you can click “Edit Project Settings” and make changes to properties of the project as a whole, which is what I had done previously. What I hadn’t understood at the time was the relationship between project settings and target settings in XCode. A little further down in the Project menu you can see “Edit Active Target Settings.” When I clicked that I saw a set of property pages identical to the eye with the settings at the project level, but there in the code signing section was the other guy’s cert, not mine. It turns out that settings for targets are inherited from the project settings, and can then be specialized. Presumably the other guy had manually set this property at the target level. When I changed it to point to my own cert all was well, and I could build and run the app on my device.

The next phase of this project is going to involve rounding out the GUI implementation, so I hope to have some interesting things to say about Obj-C and Cocoa along the way.