Friday, September 28, 2012

Test Device Tango

With the release of iPhone 5 and Apple dropping support for arm v6 (so, effectively dropping support for anything that won't run iOS 4.3) we have to shuffle some things around.

The iPhone 3G and iPod Touch that were our lowest end devices will now be repurposed as music only devices or recycled. We considered selling them on eBay, but that seems cruel since they won't really work with apps.

We acquired an iPad 1 to use as the lowest end test device for iPads. It is running 5.1.1 and apparently will never get another meaningful upgrade from Apple. This means that we don't have an actual iPad that runs 4.3 and will have to rely on the simulator if any bugs appear. It is tempting at this point to set the minimum for all iPad projects to 5.1.1 since we don't trust the simulator for testing. We have an iPad "3" running iOS 6 as the other test device.

We are running iOS 6 on an iPhone 3GS which will become the main device to test performance. If an app runs well on that, it will be fine. We have an iPhone 4 with 5.1.1 installed to use to test any 5.x issues. In a few days, we will add an iPhone 5 with iOS 6 to round out the test devices.

As always, we keep an eye on David Smith's Version Stats to help guide our decisions about what to support. For all new projects, we are setting a minimum iOS level of 5.0 unless the client wants to target iOS 6 features. If Apple ever wanted to take a page from Google and show the versions of devices that have recently hit the App store, we would not complain.

Monday, September 17, 2012

Referencing a UIViewController After Embedding

The UIStoryboard is a timesaver. However, as with everything else, there are always little tricks that befuddle us all. Today, I had a regular modal segue that went from one UIViewController to a second UIViewController. When the segue fired, I set a delegate reference. Everything worked wonderfully!
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue destinationViewController] respondsToSelector:@selector(delegate)])
    {
        [[segue destinationViewController] setDelegate:self];
    }
    
}
However, I now decided that I needed to embed one of my UIViewControllers in a UINavigationController so that I could browse some more data in that part of my app. However, now, the code above did not assign my delegate to my UIViewController. The reason for this is that the [[segue destinationViewController]] was not pointing to my UIViewController. It is now pointing to the UINavigationController.

To fix this, I took advantage of two things:
- segue's can have names
- you can cast an object

Here is new code that will reach through the UINavigationController to my UIViewController and set the delegate.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([[segue identifier] isEqualToString:@"detailSegue"]) {
        UINavigationController *tempController = [segue destinationViewController];
        if ([[tempController topViewController] respondsToSelector:@selector(delegate)]) {
                   [(DMTW_ArticleDetailViewController*)[tempController topViewController] setDelegate:self];
        }

    }
    
    if ([[segue destinationViewController] respondsToSelector:@selector(delegate)])
    {
        [[segue destinationViewController] setDelegate:self];
    }
    
}

We can see here that for all of the other segues we will just set the delegate like always. However with the segue of "detailSegue" we will do something different. We will first cast the [segue destinationViewController] to be a UINavigationController and then we will check the topViewController to see if it responds to "delegate". If it does we will set the delegate.

Notice, we are being a little lazy with this line.
 [(DMTW_ArticleDetailViewController*)[tempController topViewControllersetDelegate:self];
We probably should have kept the same two line format as we did for setting tempController as a UINavigationController and done something like
DMTW_ArticleDetailViewController *tempArticleController = [tempController topViewController];
[[tempArticleControllersetDelegate:self];
But, where's the fun in that? If you are running into a similar issue, hope this helps clear it up for you.