Thursday, April 15, 2010

World is Flat Moment

We were talking to a potential customer yesterday in Argentina about doing some programming work and we've gotten a new customer recently in Switzerland.

With things like Sykpe, email, timezones and IM thinking about working 9 to 5 seems so quaint.

Wednesday, April 14, 2010

UIPopoverController and SplitView with iPad

[Update: This is the most popular post on this blog by about a factor of 100. If you wouldn't mind leaving a comment as to what you were looking for as you arrived I would appreciate it. I am happy to modify and expand this tutorial to make it more useful. -wt]

I have been working a lot on the Massage Helper application recently and think that I'm almost done. Something that I really struggled with was ensuring that popover views were getting dismissed correctly. Apple's guidelines require that only one UIPopoverController is visible at any time. For most popovers this is a relatively straightforward process. We just need to remember to set a variable in our view to hold the currently visible popover and each time we want to display a new popover we need to dismiss any visible popover's first.

In these examples, I'm using the template that Apple provides when we start a project as a split-view project. If you want to follow along, simply create a new project in XCode of type SplitView and then just build and go. In landscape mode, you will see the split view and in portrait mode, the smaller of the views will become a popover. It is this popover that we are talking about. The sample template has a RootViewController (the smaller view that becomes the popover) and a DetailViewController (the bigger view that is always visible).

The sample template has a property associated with the DetailViewController called "popoverController". Whenever a popover is displayed, this property gets to point to it. If the popoverController property is set to nil then no popover is being displayed. We have added, a little function called "managePopovers" that checks the property and if a popover is being displayed is gets dismissed. We will call managePopovers each time we are about to display a new popover. This code is lifted from the "setDetailItem:" function of the DetailViewController.m. Here are the examples.

managePopovers

if (popoverController != nil) {

[popoverController dismissPopoverAnimated:YES];

}


Displaying one of my popovers

-(IBAction)updateSessionDate:(id)sender{

DateChangeViewController* myDateChange = [[DateChangeViewController alloc] init];

UIPopoverController *tempPopover = [[UIPopoverController alloc] initWithContentViewController:myDateChange];


[self managePopovers];

self.popoverController = tempPopover;

tempPopover.delegate = self;

[myDateChange release];

[tempPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

}


The DateChangeViewController referenced above does all of its setup without a .nib. The key to managing the popovers is that we call managePopovers and then set the popoverController property of the view equal to the popover we are about to display.

Sidenote: One other thing I discovered is that Popovers don't seem to like .nib files very much. When I would try to create a view from a .nib and use it in a popover, I tended to get errors about key value compliance. I haven't tried to explore if it's me or the computer, I just started to create any view that needs to be in a popover programatically.

So, simple. However, there is one popover that doesn't quite work well and that is the popover associated with the split view itself (in the Apple template it is the popover of the list of locations). The SplitView template that Apple provides only cares about the one popover it needs to function as a demonstration. So, when the split view sets itself up it sets the popoverController property but then it doesn't set the popoverController property on subsequent times the SplitView popover displays. Popovers will dismiss themselves whenever the user taps outside of their bounds, so if you only have one popover, you never need to dismiss it. This is what the Apple template relies on. The issue with that is that tapping on a UIBarButtonItem to display another popover doesn't trigger the event to dismiss a popover. So, using the code above we can get the Apple supplied popover to dismiss the first time we display our DateChange popover, but the next time we display the Apple supplied popover we can't get it to dismiss.

Thankfully, the key to fixing this is to implement one of the methods that Apple provides for SplitView controllers and their delegates. There are actually 3 methods a SplitView controller can support, but the Apple template only uses two of them. The willPresentViewController method gives us the opportunity to set the popoverController property each time the SplitView controller's popover is about to display.

Here is my implementation of the method (this is in the DetailViewController.m):

- (void)splitViewController:(UISplitViewController*)svc popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController{

[self managePopovers];

self.popoverController = pc;

}

Now, every time the popover associated with the SplitView itself displays, the method is called and the popoverController property gets set.

This was a maddening part of working with the UIPopoverController class, so I hope that you stumble across this little hint and that it saves you some time. If anyone at Apple is reading, it would be great if you added the willPresentViewController code to the SplitView template and then commented it out like you do for the UITableView and other templates.

Monday, April 5, 2010

Tutorial on Mercurial

I'm still using Mercurial and feel like it's making more sense every day. I came across Joel Spolsky's recent article and tutorials on Mercurial and they have helped. I am relearning the command line and vim. Joel's company has a GUI for Mercurial which looks interesting, but I'm not in the market for that yet. Maybe when the projects get bigger.

So far my biggest improvements in how I use Mercurial have been tweaking the .hgignore file and distributing the branches across my desktop and laptop.

I would like to start using version control on my word processing documents next.