Friday, July 8, 2011

Creating Static Libraries For iOS

What’s a static library

In computer science, a static library or statically-linked library is a set of routines, external functions and variables which are resolved in a caller at compile-time and copied into a target application by a compiler, linker, or binder, producing an object file and a stand-alone executable. This executable and the process of compiling it are both known as a static build of the program. Historically, libraries could only be static.
On the iPhone, static libraries have a .a extention and can only contain code. This means that any resources (xibs, images, etc…) must be packed either in a bundle or shipped separately than the library. We won’t go into this part today.

Why Use Static Libraries

There are a number of reasons to use static libraries, but the main two are distribution to others without revealing source code, and code reuse across projects.
1. Distribution:
Say you have a great idea for a view that given a few images, creates a beautiful photo mosaic. Now, others might want to use your awesome mosaic class as part of their fart-light (fart machine flashlight) app to make mosaic fart-lights from your photo library. You have done a ton of work to make your mosaic app and don’t want to just give away the code. $$$ you decide to sell your code. However, would-be thieves might not honor your awesome license and begin to redistribute the code as if it were their own (oh noooz). Boom static library.
Bundle up your code into a static library and package it with the header files. Now others can purchase your library, use it in their own apps to make fart mosaics without revealing the source and you can continue to sell copy after copy.
2. Code reuse:
So, you have like 30 apps in the store that do just about nothing. However they all have some common code, say a farting engine. Rather than dragging all of the source files in and having redundant code all over the place, you can just compile your fart engine once and use the library in all of your projects.

Where Can I Get Me One Of These?

Well, let’s dig in and create a sample static library. The project we are going to create is code-only (remember we are not going over resources in this tutorial) and will be a simple math library with two methods exposed. It will be able to compute fibonacci numbers given number n and compute a factorial value given number n (I know, pretty dang exciting).

Step 1: Starting a New Static Library Project

This is pretty straight forward as Apple has made it pretty simple to create a static library.
Open XCode and start a new project. Under iOS, select Library and “Cocoa Touch Static Library”. We are going to name ours ICodeMathUtils. This will create a nice new project for us that builds a .a file.

One thing to note is, NO class files get created by default. Don’t freak out, we will create some manually.

Step 2: Code your static library

First we need to add some files. Add a new NSObject subclass to your project and name it MathFunctions.m.
Add this code to the header file:
#import 
 
@interface MathFunctions : NSObject {
}
 
- (NSArray *) fibonacci:(NSInteger) n;
- (NSInteger) factorial:(NSInteger) n;
 
@end
Nothing fancy, just our method declarations. When we distribute the library file, this header file MUST be included as well.
One thing I should point out here is don’t make every iVar public! As a newer developer (or a stubborn lazy one: Im looking at you @cruffenach), you might think it’s cool to make a public property out of EVERYTHING. This is bad form and here is where it will bite you. You don’t want the external world being able to muck with things that you don’t want them to.
And Now the .m file for the implementation:
#import "MathFunctions.h"
 
@implementation MathFunctions
 
- (NSArray *) fibonacci:(NSInteger) n {
 
 NSMutableArray *fib = [NSMutableArray array];
 
 int a = 0;
 int b = 1;
 int sum;
 int i;
 
 for (i=0;i < n;i++)
 {
  [fib addObject:[NSNumber numberWithInt:a]];
  sum = a + b;
  a = b;
  b = sum;
 }
 
 return (NSArray *) fib;
}
 
- (NSInteger) factorial:(NSInteger) n {
 if ( n <= 1 )
  return 1;
 else
  return n * [self factorial:( n-1 )];
}
@end
This code should be very familiar to any CS 101 student : ). And that’s it for our static library. The best way to test this puppy out before distributing is to create a new unit test target, set up some unit tests, and check it out that way. That tutorial is for another day.

Building And Distributing Your Library

Once you are happy with your library, simply build it in XCode. Obviously, don’t do build and run as you can’t run it (again unless you have a test suite). Now, look under the Products group in XCode and you should see a file called lib(libraryName).a. In our case, it’s libICodeMathUtils.a.
Right click on that file and select “Reveal In Finder”. Drag this file into a new folder that you create where you will be bundling all of your library files. I just created a folder on my desktop named iCodeBlogsMathLibrary. Now, do the same with all of the .h files. In our case, just copy MathFunctions.h into this new directory. Your directory structure should now look like:
iCodeBlogsMathLibarby
|- libICodeMathUtils.a
|- MathFunctions.h
Now you can zip this folder and sell it to would-be iOS developers for millions!

Linking Your Library In A New Project


So now that you have built your shiny new static library, it’s time to test it out in another application. XCode has a number of ways to actually achieve this, but I will show the most simple and Mac-like… drag and drop : ).
Create a new View-Based project (or whatever it doesn’t really matter). I named mine MathTest.
Now, just drag this folder into the project and XCode will set up all of the linking automagically. When prompted to copy, I usually say yes, but you can do whatever you want depending on how you intend on using the library. Sometimes just linking and not copying is far more beneficial if you have multiple projects sharing a single library. It ensures that they all use the most up to date version.
You should now see the .a file along with the header files in the new project.

Using The Static Library Code

Now that all of the linking is set up, you just use your library like any other class. In the App Delegate class of my test project, I simple did this:
// Import at the top
#import "MathFunctions.h"
And in the applicationDidFinishLaunchingMethod…
MathFunctions *mFunctions = [[[MathFunctions alloc] init] autorelease];
NSLog(@"fibonacci for 10 = %@", [mFunctions fibonacci:10]);
NSLog(@"10! = %d",[mFunctions factorial:10]);
This of course prints out:
2011-04-07 11:48:49.528 MathTest[854:607] fibonacci for 10 = (
    0,
    1,
    1,
    2,
    3,
    5,
    8,
    13,
    21,
    34
)
2011-04-07 11:48:49.533 MathTest[854:607] 10! = 3628800
And there it is! Static library code being executed in a totally separate project.

You can download the source code here.

No comments:

Post a Comment