Universal App Template Rewrite

Almost 3 Years Ago

Just when I thought I had a somewhat decent grasp on developing and deploying iOS apps Apple came out with the iPad and threw a whole new element in the mix when it comes to developing.

It was almost three years ago that I published the first blog about my Universal App Template. I was inspired by, at the time, a little tutorial by a guy you might have heard of…Ray Wenderlich). His tutorial really helped me with a project I was working on and get through stumbling blocks. I wanted to provide a set of examples that any iOS developer could refer to that was straightforward and get up and running with creating a universal app in as short of time as possible.

Over the following months I added additional features such as iAd support, tabbar controller and iAd with tabbar support. Since then it is still the most visited article and starred/forked repo that I have.

Bueller, Bueller…

Over the years that followed I got busy and wasn’t able to keep up with the iOS updates, new features requested or bugs. The project was quickly becoming outdated.

I’m happy to say that I’ve carved out sometime to update this project. The plan is to start with the master branch, which is the most basic example, and update it from the ground up. I’ll then move on to the “feature” branches. I’m dropping support for iOS 3.2, 4.x and 5.x. Due to the fact that the iOS upgrades happen so rapidly, thanks to OTA, and iOS 7 is being released in less than a month, this is the perfect time to hit the reset button. The project, as well as, feature branches, will support ARC. I’ve also spent some time cleaning up the code base and removed a lot of duplicated code.

If you still need access to the “old version” I’ve tagged it.

No developer is perfect and I’m sure there are tons of things to improve so please drop me a line or file a bug and I’ll fix it ASAP.

Creating a Universal iOS Framework Sample Project

Evolutionary Not Revolutionary

It is evolutionary, not revolutionary, for most iOS developers to go from copying the same set of “library” files from project to project, to creating a static library which is then shared between projects to finally creating a universal framework.  From my humble point of view the universal framework is the ideal solution because it gives you the ability to just hand off a single framework (which is really a directory), which keeps code implementation hidden, and still have access to a static library that can be edited and shared within a shared workspace.

Having read a few different tutorials on creating a universal iOS framework the task seemed quite daunting and quite honestly over engineered.  However, with a project that I am going to be working on shortly I needed to be able to have both options: static lib and framework. So I dove back into the documentation.  Of all the blogs and tutorials that I came across the one that helped the most was written by Justin DeWind over at Atomic Object.

The instructions were very straightforward and setting up a project was extremely easy. However, when I went to build the framework I got the following error

lipo: can’t open input file: /Users/cwiles/Library/Developer/Xcode/DerivedData/StaticFramework-akqynrxfwazyswaujkdqvysbbznj/Build/Products/Release-iphonesimulator/libStaticFramework.a (No such file or directory)
Command /bin/sh failed with exit code 1

I checked and rechecked my steps and Xcode project settings, but I kept getting this damn error message.  24 comments and a sample project later, Justin tracked it down.  The issue was in the original bash script for building and moving files around assumed that there was a custom build directory inside the project and not using the standard DerivedData directory. Justin kindly updated his scripts and everything ran great. The benefits of using the standard DerviedData build directory is that you can run clean the directory for a specific target for a given project.  The benefits of using a custom build directory are:
  1. Makes it consistent between xcodebuild and Xcode
  2. The directory is always known
  3. It is configurable
With the sample project now compiling for me using the DerivedData directory I wanted to see if I would make it work no matter what the setting was for an individual’s needs.  As I started looking at the different preferences and settings that could be made at the project and target level the rabbit hole went pretty deep and I could see how someone, including myself, could make a mistake and screwing up the process.  I decided to step out of my comfort zone and look into xcconfig files.  The configuration files are text based and allow you the same flexibility and micro tweaking of your projects as using the standard project setting panes that you are used to.

The way the order of importance works is this:

“GUI” Project Build Settings overwritten by “GUI” Target Build Settings” and “Config” Build Settings
“Config” Build Settings overwritten by “Config” Target Settings

The basic setup I implemented for using the xcconfig files is creating a Project-(Shared, Debug, Release) and Aggregate-(Shared, Debug, Release).  This might have been overkill or not have followed best practices, but it did allow for a large range of flexibility for the project and targets.

Two of the most recognizable customizations that are in direct relation to this project are the target’s name and build directory. You can set  them in the project level configs or the target level configs. I have set in the target level so that if you create other targets then they those can inherit project level settings or have specifics just for that particular target.

Canonical list of Xcode variables

Summary

A huge thanks for Justin DeWind and the rest of the Atomic Object crew for the original post and taking the time to help me troubleshoot this. I hope my sample project is a welcomed addition.  If you haven’t you should check out the rest of their posts...lots of great stuff.

If you have a feature request, find a bug or have a tip, especially with the xcconfigs PLEASE let me know.

Sample Project

StaticFramework-Sample-Project

Twitter Tabbar Indicator Added to Universal iOS Template

Today I pushed a nice little update to the Tabbar Support branch of my iOS-Universal App Template project on Github.  I added in the "Twitter tabbar slider" indicator.  Though it isn't that flashy it was the attention to detail that made Tweetie so popular and usable when it first came.  While it has since been duplicated I found it interesting that most examples don't have support for landscape orientation nor for iPads.  After looking through @boctor's code on idevrecipes.com I figured I would be able to drop the code in for my template within a few hours.

If it seems too good to be true then it usually is.  I realized why I didn't see a whole lot of support for the indicators in other orientations or for the iPad.  The first obstacle was orientation support.  In @boctor's code the indicator is added as a subview to the main window.  This is not a bad practice because it ensures that the indicator is always on top of any subviews within the app. Unfortunately UIWindow doesn't support orientation, so when the device rotates the image looks crooked.  The solution is to add the indicator to the tabBarController's view.  Now that the image is repositioning itself with the orientation, unfortunately the new position is not centered.  To ensure that you will position the indicator in the center of each tabbar item ,regardless of orientation, you have to use the following calculation:

The last piece to the puzzle was to be able to force the indicator to recalculate it's position based upon the orientation.  This wouldn't be an issue with UIViewController, but I don't want to add in boilerplate code for each VC that I have.  (I already have boilerplate that I am going to abstract out with the next update).  Using NSNotification or a custom protocol seemed like overkill…and it was.  I ended up creating a category for the UITabBarController that overrides:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration

and calls the delegate method for the tabbar that is selected.

The rotation animation on the splitviewcontroller seems a little sluggish so I need to track that down and I am hoping to take out the dependency for an image and draw it programmatically.

A BIG SHOUT OUT to Peter Boctor (http://idevrecipes.com/) and Loren Brichter for being innovative and providing the code that was the basis for my little addition.

Please Enter Your Password Gesture

The more and more that I develop apps the more I try to challenge myself to come with creative ways for users to use the apps. Really trying exploit the power of multi-touch. As mentioned in a previous post, this trend is becoming more and more mainstream. Unfortunately, when it comes to authentication, we are still stuck using the old attage of a PIN and/or using biometrics, which never really caught on with the masses. I personally think that has to do with implementation of it not the mechanism.

In order to try and contribute, to a hopefully better way to authenticate, I started working on a password gesture framework. Though password gestures aren't new what I think differentiates mine, at least conceptually, is how it deals with resetting it. My first thought was to just stick with the same old "email me my password", however email isn't always relaible and the "gesture" password isn't stored on a server, but on the device. In addition, I didn't want to have to rely on a separate server or component. Lastly, by doing that I am relying on an outdated "desktop" thought process of handling lost/forgotten passwords. So how do I give a user a usable and easy way to reset their password without having a server dependency or leaving the app?

My solution is that during the password setting process is to present the user a list of pictures and have them choose N out of X. If they need to reset their password they will be presented with the "reset" picture screen and select the correct ones. If the correct set of pictures are choosen then reset occurs. If not then fail. Due to my extremely busy schedule I haven't had the opportunity to really dedicate the time I want to. I am hoping that posting this to github that the iOS community will take it and make suggestions or fork and implement it with ideas and features that I haven't thought of.

I have started the project as a sample app, but once it reaches a stable point I will make it a static library that can be dropped into any project.

It goes without saying that I am really looking for feedback on this. All comments and suggestions are welcome.

Password Gestures on Github

Using CAAnimationGroup for View Animations

Lately I have been pushing myself to increase my knowledge and understanding of more advanced animation techniques. The more that I
dig into the lower level
core graphics framework and core animation the more impressed I become with their power. I also have a greater 
respect for those developers who can leverage their power in creative ways.

For most use cases leveraging
uiview basic animations with blocks will do exactly what you need. However, in my particular case I wanted to
accomplish the following. Scale, rotate and change center point of subview "A" to subview "B" all at the same time.

Taking my own advise I first started down the path of using basic uiview animations. I want to make sure that each different piece of
the animation would perform the way I wanted them to. Separately, they did exactly what I wanted. Unfortunately, grouping these together was
not going to happen with uiview animations.

When I ran the process all the animations executed, but the transition to subview b's center point was very jerky. To make sure that I didn't
miscalculate any of the individual animations I went back and tested each one separately. Each animation ran smoothly. When I ran the group within the block
I had the jerkiness problem of animation the center point.

After going back and reviewing Apple documentation I found what my problem was.
Imagine that. To do the rotation I apply a transform on
the view's layer. However, the transform performs it's animation based upon the views center point. Since I was trying to apply an
animation on the center point as well the group animation had to reposition subview A's center point first before it could apply any of
the other animations. Hence the jerkiness.

I pushed all my animations to a
CAAnimationGroup and all the transitions were performed.


-- 
Cory D. Wiles
kwylez@gmail.com
www.corywiles.com | twitter.com/kwylez

Custom UIActionSheet Using Core Animation

About four months I posted a blog and project that showed how to customize the buttons of a UIActionSheet.  In the disclaimer I stated that because of the use of the private api's if you attempted to submit your app with this technique to the App Store it will get rejected.

This time around a created a simple, yet effective customized, mock UIActionSheet.  Essentially it is just a custom UIView with three buttons that animates and dismisses just let an UIActionSheet.  All you have to do is assign a method to each of the buttons.

If I have time then I'll try and make it even more extensible by creating a custom delegate to make the classes even more reusable.

Upcoming to Universal iOS App on GitHub

In anticipation for the upcoming public release of iOS 4.2, I have updated my Universal iOS App project (iAd Branch).  The project will run on 3.2 and up with iAd support for iPhone and iPad (4.2 only for iPad).

I ran into some interesting hurdles while working on this update.  The first of which is that adding in iAd support for a project using a UISplitViewController SUCKS! #FAIL When iAds where first offered in the 4.0 iOS they came in two different size: 320 x 50 (ADBannerContentSizeIdentifier320x50) and 480 x 32 (ADBannerContentSizeIdentifier480x32) which served their purpose since you could use iAds only on the phone.  When iAd support was added for the iPad Apple was smart and deprecated those properties and added ADBannerContentSizeIdentifierPortrait and ADBannerContentSizeIdentifierLandscape, thus abstracting the dimensions that are available for any current and future devices.  This unification works great on the iPhone and iPad...except for when you implement UISplitViewController on the iPad.  The reason being that even though your root view or "detail" view controller are in landscape or portrait mode their widths aren't in the expected frame width for either choose of iAd. Thus you get an inaccurate display and you will an error in:

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error

stating that an ad has displayed but is being obscured. In order to get around this I had to add in some padding to readjust the 'y' coordinate for the tableview's frame (only when the ad appears).  Why the rotation, and only on the iPad, gets screwed up I am not sure at the moment.  I created a simple, iPad only project and got the same results so there might be a bug, but until I am able to verify, my "padding" works".

It is important that if you clone/run this project that you read the debug console for iad display errors.  These are relevant errors passed to the delegate method and don't have to do with my code.  You will notice in the video that ad fails to load the first round.  This is due to an error from Apple serving up the ad because inventory is not available. Second time is the charm.

*important - always implement delegates to handle failures

In the next few weeks I'll be adding a branch where the Universal app will have Tabbar support.

CWCustomAccessoryView - Custom UITableViewCell AccessoryView

Around the same time that Oliver Drobnik (Formely Dr. Touch) published his blog entry, Custom-Colored Disclosure Indicators, I was also in the middle a client's project where the table view cells each had a different colored uitablviewcellaccessory.  I had to deal with 20 different images for the accessory views (10 for pre-iPhone4 and 10 for retina display).   At the time I knew having to manage the images themselves and the code to display those views was unwieldy and cumbersome.  I took inspiration from Oliver's post to come up with a class, CWCustomAccessoryView, which allows the developer to customize the way the accessoryView for a cell looks which includes the stroke, _>_, and fill color.


Though the code is almost a month old and I haven't had that much time on improving it, but after reading Ray Wenderlich's blog on Arc's and Paths I see I need to make the accessory view look for like Apple's detail disclosure button to make everything look really polished.

Per usual the code is hosted over at GitHub.  Comments and improvements are ALWAYS welcomed.

Customizing UIActionSheet Buttons

One of the great benefits of iOS development is that Apple has provided the ability to customize almost any element thus not limiting a designer or developer with a stock look and feel.  Just take a look at subtle examples in Twitter for iPhone to the extreme of the Outside Weather app or Starbucks.  I am working on a nice size project and one of the requirements is to have the UIActionSheet buttons be a different color than the default gray color.  This turned out the be as straightforward as trying to change the look and feel of a tabbar.

::NOTE TO APPLE:: Customizing Tabbars and UIActionSheet buttons should be a lot easier. ::END NOTE::

It took a few hours, but I finally knocked it out.  At first glance I figured that each one of the buttons would be an instance of UIButton and I could located them in the view hierarchy and just update the background color either in a delegate method or subclass UIActionSheet and override drawRect:.  NEGATIVE.  

My next possible approach was to create my own custom view(s) and slap them on the UIActionSheet's main view and send everything else to the back.  Granted that has worked for some people and is a totally viable option, but I found it to be a very hacky solution for what I was doing.

After looking up a few questions on StackOverflow it turns out that sometime after iOS 3.1 the subviews in the UIActionSheet are an undocumented class instances of UIThreePartButton.

::BIG DISCLAIMER - YOUR APP WILL PROBABLY GET REJECTED IF YOU SUBMIT WITH THIS TECHNIQUE::

After digging up that little nugget about UIThreePartButton I finally had turned a corner.  The next hurdle was trying to find the correct method to use from the UIThreePartButton class to change the background color.  Unfortunately, there isn't a backgroundColor property for that.  Granted since I am dealing with a class that inherits form UIView I could set the subviews backgroundColor property to [UIColor redColor], but when I did that I didn't get the expected result of a button with a red background.  The button became a red tint and the view behind the button was red as well.  Obstacle.  Looking at the methods/properties that I DID have I went on a little intuition that Apple wasn't using a color, but a stretchable background image for the button.  I grabbed the background graphic that I wanted and used - (void) setBackgroundImage:.  SUCCESS!!!!!!!

I wasn't quite finished.  Background button was what I wanted, but I needed to change the font color from black to white.  But wait there isn't a method to set the font. However, UIPushButton inherits from UIThreePartButton so once again going on an educated guess/intution I was able to use setTitleColor:forState: and perfection.  Excatly what I wanted and needed.  UIActionSheet with red buttons and white font.

Even though I can't submit any app to the AppStore because of the undocumented class working through the exercise was very enlightening in the areas of ui customization, design patterns and general problem solving skills which should always be in the top of a developer's skillset.

I posted my example on github.  It was compiled with 4.0 with XCode 4 Preview 3, but XCode 3.x should work.  If you run into any problems then let me know.

Creating a Universal iOS App Tutorial

Just when I thought I had a somewhat decent grasp on developing and deploying iOS apps Apple came out with the iPad and threw a whole new element in the mix when it comes to developing.  Thankfully, the iPad will allow iPhone apps to run on the device, but the user experience is definitely sub-par.  So what is the best approach to providing an native iPhone app and a native iPad app?  The first option is to duplicate your existing iPhone app code base and modify all your views and some of the controllers to take advantage of the features in the 3.2 SDK.  The problem with that is the massive DUPLICATION of code and to be honest it seems quite lazy.  I have seen lots of examples where developers use the idiom check for which device is being used, as well as, runtime checks for selectors in order to leverage the correct methods/classes for the given device.  While this is certainly a better approach then having two separate code bases with 90% of the same code you now have code that is sprinkled/littered with if/else checks.  Unfortunately, you are once again stuck with code that will be maintainable for long.  After reading the chapter on universal apps from the upcoming book from Pragmatic Programmers, iPad Programming, I found a much better design pattern of splitting out the app into Shared, iPhone and iPad resources, classes and delegates.

As a side note, due to the ever exponential growth of iOS device popularity developers are not going to have the bonus of just jumping straight into writing an app like we did when there was just the iPhone.  A lot more thought needs to be given to design patterns (especially regards to the quality of your MVC) and application flow.

In order to make life a little easier on myself since a few universal apps are coming in my near future I decided to create a basic "template" for a universal app.

Features
  • Compiled for 3.2 and 4.0
  • Utilizes navigation controller based app for iPhone device and SplitViewController for iPad
  • Shared "model" class and controller classes
  • Separate resources (classes/xibs) for the different devices

Comments and improvements are ALWAYS welcome.  One improvement that I know I want to make is having the "detail" controller from the SplitViewController to be a UINavigationController.