Pittsburgh Tech Fest: iOS Best Practices slides & code

Pittsburgh Tech Fest was great this year! It was a perfect opportunity to learn about some different technologies and techniques.  I’d like to give a special thanks to Dave and Eric for doing an awesome job organizing the event and the speakers.

For those that are interested, below are the links to the talk I did on iOS Best Practices: Avoid the Bloat and feel free to comment or ask any questions on this post!

Code before refactoring: https://github.com/JAgostoni/iOS-Best-Practices/tree/master/UglyApp
Code after refactoring: https://github.com/JAgostoni/iOS-Best-Practices/tree/master/NotSoUglyApp
Code as presented at Pittsburgh Tech Fest: https://github.com/JAgostoni/iOS-Best-Practices/tree/master/PghTechFest

PowerPoint Slides: iOS Best Practices – Pittsburgh Tech Fest
PDF Slides: iOS Best Practices (PDF) – Pittsburgh Tech Fest

Thanks again to those that attended my talk!

Advertisements

TFS Xcode Build – v1.0 Released

Xcode, TFS and the ALM …

Many organizations have been faced with centralizing all of their ALM tools in order to enable better integration across all the tools for each role in your app lifecycle.  Team Foundation Server (TFS) provides an excelllent integration environment for Microsoft .NET projects and even application developed in Eclipse (Java, Android, etc.).  There have been many recent advances into the mobile space especially in iOS applications and my work is certainly no exclusion to this.  Since CEI has adopted TFS as our ALM platform I have been keeping all of my Xcode projects in TFS via the Subversion bridge.

But what about builds?

While storing Xcode projects in TFS works quite well (including the ability to associate with Work Items) one of the primary features of TFS (and any integrated ALM platform) is Build Automation.  Since Xcode projects can ONLY be built on Mac OS X there simply was no way to trigger a build using Team Build in TFS.  Alternatives exists, for sure … there are other CI platforms that can be triggered via SVN (svnbridge in TFS) but that requires more investment in software.

What I wanted was a solution leveraging Team Build as much as possible and a Mac only where it was needed to compile the Xcode project.  The thought of implemeting a Team Build Agent on the Mac was …. frightening 😉  So, instead, I decided to automate copying the source code from the Team Build server to the Mac (using SCP), remotely triggering xcodebuild (via SSH), and finally retrieving the results (again, via SCP).  It turns out this was pretty straight-forward and reliable.  To share this, I created a Codeplex project to host the source code and binaries.

TFS Xcode Build v1.0

Check out the project hosted on Codeplex here: http://tfsxcodebuild.codeplex.com/.  There you can find the latest source code, binary release and documentation.

iOS Best Practices – Singletons

Problem

Many examples found online utilize the AppDelegate instance for global storage/variables.  While this is a quick way of sharing data and methods between views and classes it can (and usually does) lead to several problems:

No control over global variables/storage

Each referencing class assumes direct control over this variable and won’t necessarily respect how another class is expecting to use it.  With a singleton, the data has been fully encapsulated and controlled in one place.

Repeated business logc

If there is any business logic on how this global storage is to be used it has to be repeated throughout the application.  While some may “encapsulate” this by using accessor methods the logic is in the wrong place.

Big Ball Of Mud

Very quickly, the AppDelegate class will become a big ball of mud and VERY difficult to maintain.  This is compounded over time as the app is revisioned and different developers add more and more code to the ball of mud.

Fixing the problem: Singleton

One way of fixing the “I need to put all my global variables in the AppDelegate” is to use Singletons.  A singleton is a design pattern (and implementation) ensuring that a given class exists with one and only one instance.  The developer can now store like variables and implementations together with the confidence that the same data will be retained throughout the application.  In fact, the AppDelegate is held in a singleton of your application ([UIApplication sharedApplication]).

The developer must also ensure to not repeat the same “big ball of mud” anti-pattern by simply moving all the code from the AppDelegate into one Singleton class.  The concept of single-purpose classes will be covered in a future post.

Implementation

The implementation is pretty straight-forward based on Apple’s Fundamentals and is made even simpler using ARC in iOS 5.  The trick is ensuring all code that references this class is using the exact same instance.

Steps/tips for a Singleton in Objective-C:

1. Implement a “shared manager” static method to dynamically create and retrieve the same instance each time.

static SingletonSample *sharedObject;
+ (SingletonSample*)sharedInstance
{
if (sharedObject == nil) {
sharedObject = [[super allocWithZone:NULL] init];
}
return sharedObject;
}

2. Leverage public shared methods as a convenience factor to encourage use of the singleton.

+(NSString *) getSomeData {
    // Ensure we are using the shared instance
    SingletonSample *shared = [SingletonSample sharedInstance];
    return shared.someData;
}

3. Create and use instance variables and methods as you normally would

@interface SingletonSample : NSObject {
    // Instance variables:
    //   - Declare as usual.  The alloc/sharedIntance.
    NSString *someData;
}

// Properties as usual
@property (nonatomic, retain) NSString *someData;

4. Use the class via the shared methods and/or instance

- (IBAction)singletonTouched:(id)sender {
    // Using the convenience method simplifies the code even more
    self.singletonLabel.text = [SingletonSample getSomeData];
}

The full source code with sample application is available here: https://github.com/JAgostoni/iOS-Best-Practices/tree/master/BigBallOfMud

iOS Best Practices – Introduction

As my work gets more and more into mobile development (primarily iOS) I find our typical adoption to best practices (in .NET and Java, for example) not as strong. Whatever the reason, these practices are just as important on mobile platforms as they are on web and desktop platforms. The fact that a mobile device has more constrained resources or has fewer technology choices should have no impact on proper coding and design practices.

There are several books (Apple and otherwise) that I can recommend that cover basic coding conventions and UI design guidelines so i’ll try not to re-hash much of that here. As I encounter references and resources such as these I will link to them in a resources section.

The following series of posts is meant to document iOS design and development best practices as I have encountered them both in practice and as I have found them researching across the Internet. I encourage anyone following along to not only share the practices but to critique and contribute as well.

This introductory post will serve to index all the posted best practices:
1. Avoiding the big ball of mud (part 1) – Singletons – http://wp.me/p15S8e-3d

Test Flight: Simplified Beta Deployments for iOS Apps

One of the more challenging things in creating iOS applications is the whole provisioning and deployment process.  This becomes especially true during beta testing of your application using Ad-Hoc distribution.

The process is something like this:

  1. Gather all the UDIDs from your test subjects
  2. Enter these into the iOS Provisioning Portal
  3. Create a distribution certificate (if you haven’t already)
  4. Create an Ad-Hoc provisioning profile
  5. Download the profile and certificate
  6. Configure and build your app signing with these credentials

Then, your testers need to get the application and install it.  Generally like this:

  1. Email the testers the provisioning profile and app bundle
  2. The tester need to drag both to iTunes (or Organizer) and then tether and sync

This makes it a little cumbersome for most testers and difficult for non-tech savvy users.  One could post the app bundle to a website with a manifest and then create a launch page (like an internal app store) and then notify the users.  This is where Test Flight (www.testflightapp.com) comes in … managing the web-delivery of your application in a really easy-to-use process.

Remembering the above, now I do this:

  1. (optional) Ask your test users to register their devices
  2. (optional) Create a team out of these testers and download their device IDs
  3. (optional) Upload all of these device IDs at one time to the Provisioning Portal
  4. Follow the same process as above to create a provisioning profile and build
  5. Now upload the IPA bundle to Test Flight and I am done

At this point, the testers can receive a notification of the new build (and subsequent builds) and simply visit Test Flight on their device.  They will be able to install your beta app straight from the browser.  Further, I can report on who has installed the app and who has not.

All this and the website has a nice easy to use design on top of that!

Updated iPad view resizing for keyboard…

There were a couple of glitches in the code I had originally posted in “iPad: resize view to account for keyboard” especially when dealing with a scroll view within a split-view controller, etc.

Originally, I was using the “setContentOffset” method on the UIScrollView:

[scrollView setContentOffset:scrollPoint];

This was problematic depending on the orientation and so forth.  Frankly, I could never get it to behave the way I wanted.  After much debugging I looked at some other methods and found: scrollRectToVisible.  Well … that sounds like just what I need and no longer have to worry about calculating the perfect position for the scroll point.  Here was the updated line:

[scrollView scrollRectToVisible:activeField.frame animated:YES];

There. Much better! See the original post for the rest of the tutorial.

SNLog – Simple logging framework for iOS

[SNLog Project Page Link]

Logging

A simple task that every developer runs into when creating software is proper logging and tracing.  What I have found is the simplest solution for logging is always the best.

Requirements are almost always the same:

  1. Need to log to the console when debugging
  2. Need to write to a file/database for runtime tracing and diagnostics

There are lots of frameworks for just about every platform out there but logging on the iPhone seemed to be lacking so I decided to create my own as an exercise.  Something that would be applicable to my current projects as well as to help out anyone else that might need something like this.

NSLog

NSLog is the de-facto standard for logging during debugging in Xcode but is primarily temporary scaffolding in your code that needs removed prior to deploying the application.  I wanted something as simple to use as NSLog that could be configured to log somewhere more persistent than the console.

SNLog

The plan of attack on this was straightforward:

  1. Minimize the files that need included in the project (just two, the .h and .m)
  2. Make use of it as easy as NSLog
  3. Re-define NSLog to use the framework instead of the built-in function
  4. Use a strategy pattern to allow multiple logging mechanisms (console and file built-in)

In addition, I ran into the following additions while I was working on it:

  1. Don’t let the file logging grow unbounded (especially on a mobile device)
  2. Capturing the log level/importance can allow different mechanisms to capture the level that is required

So that’s it … in two simple files I was able to create a simple logging mechanism that is a drop-in replacement for NSLog.  I can keep all those frivolous NSLog statements in my code and choose where to redirect the log.

Check out the Project Page for more details and the download.