TweetFollow Us on Twitter

The Road to Code: Custom House

Volume Number: 26
Issue Number: 01
Column Tag: The Road to Code

The Road to Code: Custom House

Creating and using custom frameworks

by Dave Dribin

Introduction

We've talked at length about the system provided frameworks, namely Foundation and AppKit. This month we're going to learn a little bit more about frameworks and how to create and use your own custom frameworks.

Libraries

In order to understand frameworks, we need to take a few steps back and talk about how source files are actually turned into an executable program. For C-based languages, including Objective-C, turning source code into a program consists of a two-step process involving tools called a compiler and linker. In the first stage, the compiler turns source files into object files. Source files have file extensions of .c for C source code or .m for Objective-C source code. Object files have .o extension, no matter what the source language is. The linker takes all the object files and combines them into the final executable, sometimes called a binary.


Figure 1: Compile and link process

Figure 1 shows how two C source files, file1.c and file2.c, are turned into an executable named program. The compiler turns file1.c into file1.o and file2.c into file2.o by a process known as compiling. The linker then combines file1.o and file2.o into the final executable named program by a process known as linking. Objective-C programs are compiled in exactly the same manner, except the source files have a .m extension.

This two-step compile and link process helps scale programs to many source files. It allows developers to split up code into multiple source files in a way that make sense for the project. This not only helps from an organizational standpoint, but helps speed up compile times. If you change one function, only the source file that contains it needs to be recompiled. All other object files can be re-used when linking the final executable.

Static Libraries

A library, in a generic sense, is a bit of code that is designed to be used and shared among many applications. Back in the early days of C programming, it became clear that there were common needs that most programs had, such as manipulating strings and handling file I/O. Instead of having each program write these from scratch every time, wouldn't it be better if you could use the same functions from application to application? This would save time and help reduce bugs.

Prior to the invention of libraries, each program wanting to share code between them had only one option: share the source files. Say we had string manipulation functions in a file named string.c, each program would need their own copy of this file. While this is fine if the shared code can fit into one file, if the shared code gets big enough to be split into multiple files, this can become unwieldy. Plus, why bother having each application compile the same source files over and over again, when they could share the object files?

Enter static libraries. Static libraries combine multiple object files into a single file called a static library. The linker can then use the static library to pull in shared code. Say we've got XML parsing code we want to share among applications, and we want to create an XML static library. First, we compile all our XML related files into a single static library. Figure 2 shows this process. The source files are compiled as usual, but instead of linking them together into an executable, a tool called the archiver combines all the object files into a static library. Static libraries have the .a extension, but they are also always prefixed with lib. Thus libxml.a is file name of the static library named xml.


Figure 2: Create static library

Using this static library is fairly easy. Figure 3 shows a program that feeds libxml.a to the linker. The linker will pull the shared XML parsing code into the executable, along with its object files.


Figure 3: Link with static library

Dynamic Libraries

While static libraries are a big improvement over manually including shared code in every project, they're not without limitations. Since the shared code is included in each of the final executables, each executable takes up more disk space. For example, if a static library is 20 megabytes in size, every executable will contain this same 20 megabytes of code, wasting disk space. Also, if the library is updated to fix a bug, each of the executables must be re-linked to pull in the new code.

In order to help combat these issues, a new kind of library was created called a dynamic library. In Windows, a dynamic library is called a dynamically linked library, or DLL, and in Linux a dynamic library is called shared library. A dynamic library has a .dyld extension on Mac OS X but the same lib prefix as static libraries. To continue our example from earlier, the XML dynamic library would be named libxml.dyld.

Dynamic libraries are linked into an application in a similar fashion to static libraries, by telling the linker about them. The big difference is that the code is not copied into the resultant executable, but a reference to the dynamic library is recorded in the final executable. When the executable is run, the operating system finds the dynamic library file and pulls the code into the program at runtime. Because of this, the executable needs the dynamic library at runtime. This is not the case for static libraries.

Because the code is not copied to the executable, the file size of the executable is smaller. However, the big benefit of dynamic libraries is that the version of the dynamic library used at runtime does not need to be the same as the version linked against. Thus, if the system includes an XML library, and it gets updated to fix a bug, you don't have to re-link to get the fixed bug in your program. It will automatically use the new library when it runs.

Frameworks

One issue with both static and dynamic libraries is that the library file only contains compiled code. The API for the library is defined in header files. The typical convention on Unix systems is to place static and dynamic libraries in /usr/lib for system installed libraries and the corresponding header files go into /usr/include. By splitting the API from the library into two separate directories, it's hard to know which header files are for which library. Also, installing new libraries must be done carefully to not clash with existing libraries.

The fine folks at Apple (well NeXT, actually) decided to utilize bundles to help solve this problem. In case you don't remember, bundles are just directories with a special file extension. For example, Cocoa applications are bundles that use the .app file extension. Figure 4 shows what the directory structure of a simple application bundle looks like. Normally, the Finder hides all this from the user, but you can see it by choosing Show Package Contents from the Finder's contextual menu. The bundle contains the actual executable in the Contents/MacOS directory, but the application can contain other resources such as nib files, images, and localized strings. Putting all assets of an application into one bundle makes it easy for users to install and remove applications.


Figure 4: Application bundle contents

Frameworks are another kind of bundle that contains a dynamic library, along with its header files. It can even contain other resources such as images and Interface Builder plug-ins. Packing all of these related files together into a single directory makes distributing and updating shared code even easier.

Almost all shared Objective-C code is distributed as frameworks. Foundation and AppKit are the frameworks we are most familiar with. But we, too, can create our own frameworks. What if we want to share code between multiple applications? Or we have some nifty code that we think others will want to use in their applications, too? We're going to cover how to create our own frameworks.

Creating a Custom Framework

We are going to walk through creating an application that uses an embedded custom framework. The application will be called Hello World and the framework will be called HelloKit. We'll also put each of these in their own Xcode project and show how to link two Xcode projects together. Let's start off by creating the framework.

Start off by creating a new project using the Cocoa Framework template and name it HelloKit. Add a new class to the project named HelloObject and update the header file to match Listing 1 and the implementation to match Listing 2.

Listing 1: HelloObject.h

#import <Foundation/Foundation.h>
@interface HelloObject : NSObject
{
}
- (NSString *)greeting;
@end

Listing 2: HelloObject.m

#import "HelloObject.h”
@implementation HelloObject
- (NSString *)greeting;
{
    return @”Hello World!”;
}
@end

As you can see, this is a very simple class for demonstration purposes only. It's customary for frameworks to have a master header file with the same name as the framework that pulls in all header files for the entire framework. An example of this is the #import statement on the first line of the HelloObject.h file that includes the Foundation framework. Even though we've only got one class file right now, it's good to plan for the long term and create our own master header file. Create a new header file and name it HelloKit.h. It's going to be very simple right now, just one line of code:

#import <HelloKit/HelloObject.h>

And that's all the code we have to do for our framework. We have to mark our header files as public so that they are copied into the framework bundle. To do this, select the HelloKit target, and then change the Role of our two headers from project to public as shown in Figure 5.


Figure 5: Public headers

Before we can use this framework in another application, we need to learn a bit more about how Mac OS X locates frameworks used by an application.

Install Names

Every framework knows where it is supposed to be installed on the file system. This is called the install name and is recorded inside the framework. For example, all system provided frameworks are located in /System/Library/Frameworks, and their install name matches this. You can view the install name of a framework using the otool command line utility with the –D option:

% otool -D /System/Library/Frameworks/Foundation.framework/Foundation 
/System/Library/Frameworks/Foundation.framework/Foundation:
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation

When you link against a framework, the application also remembers the install name. When the application is run, it looks for the framework where the install name says it should be. This is fine for system-installed frameworks. They'll always be in /System/Library/Frameworks. But where does our custom framework live? It can actually be in a number of places:

/Library/Frameworks,

~/Library/Frameworks,

or embedded directly into an application or other framework bundle.

Because there is no way for us to foresee all uses, and there's only one install name, we have to pick one of theses locations. What does the Xcode template use for frameworks? Open up the build settings for the HelloKit target and search for "install” as in Figure 6.


Figure 6: Default install name

As you can see, it's using our home directory. This isn't useful for us, because we want to embed this framework into our application. If we use the default install name, it won't be able to find the framework. Before I explain how to fix this, I ought to tell you that embedded frameworks go in a directory named Contents/Frameworks inside the application bundle. Thus, our Hello World application should have the directory structure shown in Figure 7.


Figure 7: Application bundle with a framework

@loader_path

Since a user can install the application anywhere, we don't want to use /Applications as our install name. Mac OS X has special keywords that provide us with the flexibility we are looking for. In Mac OS X 10.4 and later, you can use the @loader_path keyword, by changing the Installation Directory of the framework to:

@loader_path/../Frameworks

Let's parse this out. @loader_path is a special keyword that gets substituted with the path of the actual executable. For our Hello World application, this path will be:

Hello World.app/Contents/MacOS/Hello World

The .. tells Mac OS X to go up to the parent directory, Contents, and the look for a directory named Frameworks there. The final, expanded out path would be:

Hello World.app/Contents/Frameworks

@loader_path works not only for applications but for frameworks that embed other frameworks and plug-ins that embed frameworks, too.

On Mac OS X 10.3 and earlier, @loader_path wasn't available, but a keyword called @executable_path was available that pointed to the running application's executable. This worked fine for frameworks embedded in applications, but didn't allow for frameworks to be embedded into other frameworks or plug-ins. You really shouldn't use @executable_path anymore, but I wanted to explain it in case you saw it in other projects.

@rpath

The @loader_path keyword still has some limitations, however. It means you must install the framework embedded inside another application or bundle. You can't install it in the home directory, either. This typically led developers to create embeddable and non-embeddable versions of the framework. The problem is that a framework distributor doesn't know exactly where the framework will eventually be used, yet it has to chose a single installation directory. Since this is not ideal, Mac OS X 10.5 comes with a new keyword called @rpath. This keyword allows the user of the framework to decide where the framework will be installed rather than the framework distributor.

To use @rpath, set the Installation Directory to be only @rpath, as shown in Figure 8.


Figure 8: rpath install name

With this in place, we can now move on to embedding this framework into our application.

Embedding a Framework

Create a new Cocoa application project called Hello World and add a new class called HelloWorldAppDelegate. This is standard so far, but it's about to get a bit tricky, so hang in there. We'll be fiddling around with some parts of Xcode we haven't used before.

Locate the HelloKit.xcodeproj file in the Finder and drag it directly into the Groups & Files section of the Hello World project. It should be added to the list, and you should be able to see the HelloKit framework underneath the sub-project as shown in Figure 9.


Figure 9: Embedded project

With the Hello World application target selected, choose Project > New Build Phase > New Copy Files Build Phase. Change the Destination to Frameworks as shown in Figure 10.


Figure 10: Copy files phase

Next, open the disclosure triangle to the Hello World target, and rename the new Copy Files phase to be Copy Frameworks. Finally, move it between the Copy Bundle Resources and the Compile Sources build phases, as shown in Figure 11.


Figure 11: Build phase order

Now that we've got our build target set up to copy over embedded frameworks into the correct directory, we've got to use this for the HelloKit framework. We want to make sure that the framework is built before the application, so double click on the Hello World target and add the framework as a direct dependency of the application, as shown in Figure 12.


Figure 12: Adding a target dependency

Setting up the dependency builds the framework before the application gets built, but we still need to copy the framework into our bundle and link against the framework. Drag the HelloKit.framework product into both the Copy Frameworks and Link Binary with Libraries phases, as shown in Figure 13.


Figure 13: Copy and link framework

We've got to change a couple more build settings of the application, and then we're done messing around with the target. As it stands, Xcode does not know where to find the framework at compile time. We need to setup the Framework Search Paths for the application target. Again, double click on the target and add the following to Framework Search Paths:

$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)

The resulting build setting window is shown in Figure 14.


Figure 14: Framework search paths

The final build setting we need to set is the Runtime Search Paths. Remember that we used @rpath as the install name of our framework. Setting the Runtime Search Paths allows us to control what @rpath expands out to be. Since we copied the framework to our embedded Contents/Framework directory, we want to set the Runtime Search Paths to:

@loader_path/../Frameworks

The resulting build setting window is shown in Figure 15.


Figure 15: Runtime search paths

Notice that we're again using the @loader_path keyword, since that expands to the executable of our application. With all that grunt work out of the way, we're finally able to use our framework. We've set up our application target to build the framework target, copy it into our application bundle, and properly link against it. Now it's time to use this framework. Fortunately, this part is easy.

Make the HelloWorldAppDelegate implementation file look like Listing 3.

Listing 3: HelloWorldAppDelegate.m

#import "HelloWorldAppDelegate.h”
#import <HelloKit/HelloKit.h>
@implementation HelloWorldAppDelegate
- (void)awakeFromNib
{
    HelloObject * hello = [[HelloObject alloc] init];
    NSString * greeting = [hello greeting];
    [hello release];
    NSLog(@”Greeting: %@”, greeting);
}
@end

We import the master include file of the HelloKit framework at the top of the file. Then, we use the HelloObject class in awakeFromNib. Make sure an instance of HelloWorldAppDelegate is instantiated in the nib, and run the application. You should get the following output in the console:

Greeting: Hello World!

Conclusion

Whew! This is a lot of work to go through for such a simple framework, but the same steps can be applied to custom frameworks of any size. Xcode can be a fickle beast sometimes, so double-check all the steps carefully if things aren't working out. As usual, the project may be downloaded from the MacTech website, as well. If you're having issues, compare your project against the working version.


Dave Dribin has been writing professional software for over eleven years. After five years programming embedded C in the telecom industry and a brief stint riding the Internet bubble, he decided to venture out on his own. Since 2001, he has been providing independent consulting services, and in 2006, he founded Bit Maki, Inc. Find out more at http://www.bitmaki.com/ and http://www.dribin.org/dave/.

 
AAPL
$97.19
Apple Inc.
+2.47
MSFT
$44.87
Microsoft Corpora
+0.04
GOOG
$595.98
Google Inc.
+1.24

MacTech Search:
Community Search:

Software Updates via MacUpdate

Firefox 31.0 - Fast, safe Web browser. (...
Firefox for Mac offers a fast, safe Web browsing experience. Browse quickly, securely, and effortlessly. With its industry-leading features, Firefox is the choice of Web development professionals... Read more
Little Snitch 3.3.3 - Alerts you to outg...
Little Snitch gives you control over your private outgoing data. Track background activityAs soon as your computer connects to the Internet, applications often have permission to send any... Read more
Thunderbird 31.0 - Email client from Moz...
As of July 2012, Thunderbird has transitioned to a new governance model, with new features being developed by the broader free software and open source community, and security fixes and improvements... Read more
Together 3.2 - Store and organize all of...
Together helps you organize your Mac, giving you the ability to store, edit and preview your files in a single clean, uncluttered interface. Smart storage. With simple drag-and-drop functionality,... Read more
Cyberduck 4.5 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
iExplorer 3.4 - View and transfer all th...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
Airmail 1.4 - Powerful, minimal email cl...
Airmail is a powerful, minimal mail client.It was designed to retain the same experience with a single or multiple accounts and provide a quick, modern and easy-to-use user experience. Airmail... Read more
Macs Fan Control 1.1.12 - Monitor and co...
Macs Fan Control allows you to monitor and control almost any aspect of your computer's fans, with support for controlling fan speed, temperature sensors pane, menu-bar icon, and autostart with... Read more
A Better Finder Rename 9.37 - File, phot...
A Better Finder Rename is the most complete renaming solution available on the market today. That's why, since 1996, tens of thousands of hobbyists, professionals and businesses depend on A Better... Read more
MacBook Air EFI Firmware Update 2.9 - Fo...
MacBook Air EFI Firmware Update is recommended for MacBook Air (Mid 2011) models. This update addresses an issue where systems may take longer to wake from sleep than expected and fixes a rare issue... Read more

Latest Forum Discussions

See All

Together for iOS (Productivity)
Together for iOS 1.0 Device: iOS Universal Category: Productivity Price: $9.99, Version: 1.0 (iTunes) Description: Together is an app for keeping things in one place. Notes, documents, images, movies, sounds, web pages and bookmarks... | Read more »
The Phantom PI Mission Apparition (Game...
The Phantom PI Mission Apparition 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: ** Release sale! 50% off for a limited time! ** The Phantom PI Mission Apparition is a spooky, puzzly, rock’... | Read more »
The Great Prank War (Games)
The Great Prank War 1.0.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.0 (iTunes) Description: Help Mordecai, Rigby, Muscle Man and Skips take the park back from Gene and his goons with a plethora of prank-related... | Read more »
Teenage Mutant Ninja Turtles (Games)
Teenage Mutant Ninja Turtles 1.0.0 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.0 (iTunes) Description: Download the all new Teenage Mutant Ninja Turtles Official Movie Game! | Read more »
Dream Revenant (Games)
Dream Revenant 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: EXCLUSIVE LAUNCH PRICE ! Dream Revenant is at $1.99 for a limited time ! | Read more »
Traps n' Gemstones (Games)
Traps n' Gemstones 1.00 Device: iOS Universal Category: Games Price: $2.99, Version: 1.00 (iTunes) Description: LAUNCH SALE! 40% off, JULY ONLY! TRAPS N' GEMSTONES is an adventurous platform game, among gamers typically known as the... | Read more »
Soccer Physics (Games)
Soccer Physics 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: One-button soccer game! So dumb it's fun. "Soccer Physics is probably the funniest football game you'll play on iOS" —... | Read more »
Ex-Angry Birds Developers Release Monsu...
Ex-Angry Birds Developers Release Monsu Teaser Trailer Posted by Jennifer Allen on July 23rd, 2014 [ permalink ] Finnish developer Boomlagoon has released a teaser trailer of their forthcoming side-scrolling action platformer, | Read more »
Dragons: Rise of Berk – Tips, Tricks, an...
Things have changed in Berk, the fantasy Viking village of DreamWorks’ How to Train Your Dragon series. Dragons and Vikings, once mortal enemies, now must learn to live together in peace. Dragons: Rise of Berk lets players manage dragon-Viking... | Read more »
Cowabunga! Teenage Mutant Ninja Turtles:...
Cowabunga! Teenage Mutant Ninja Turtles: Rooftop Run Is Currently Free Posted by Jennifer Allen on July 23rd, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »

Price Scanner via MacPrices.net

What Should Apple’s Next MacBook Priority Be;...
Stabley Times’ Phil Moore says that after expanding its iMac lineup with a new low end model, Apple’s next Mac hardware decision will be how it wants to approach expanding its MacBook lineup as well... Read more
ArtRage For iPhone Painting App Free During C...
ArtRage for iPhone is currently being offered for free (regularly $1.99) during Comic-Con San Diego #SDCC, July 24-27, in celebration of the upcoming ArtRage 4.5 and other 64-bit versions of the... Read more
With The Apple/IBM Alliance, Is The iPad Now...
Almost since the iPad was rolled out in 2010, and especially after Apple made a 128 GB storage configuration available in 2012, there’s been debate over whether the iPad is a serious tool for... Read more
MacBook Airs on sale starting at $799, free s...
B&H Photo has the new 2014 MacBook Airs on sale for up to $100 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels... Read more
Apple 27″ Thunderbolt Display (refurbished) a...
The Apple Store has Apple Certified Refurbished 27″ Thunderbolt Displays available for $799 including free shipping. That’s $200 off the cost of new models. Read more
WaterField Designs Unveils Cycling Ride Pouch...
High end computer case and bag maker WaterField Designs of San Francisco now enters the cycling market with the introduction of the Cycling Ride Pouch – an upscale toolkit with a scratch-free iPhone... Read more
Kingston Digital Ships Large Capacity Near 1T...
Kingston Digital, Inc., the Flash memory affiliate of Kingston Technology Company, Inc.,has announced its latest addition to the SSDNow V300 series, the V310. The Kingston SSDNow V310 solid-state... Read more
Apple’s Fiscal Third Quarter Results; Record...
Apple has announced financial results for its fiscal 2014 third quarter ended June 28, 2014, racking up quarterly revenue of $37.4 billion and quarterly net profit of $7.7 billion, or $1.28 per... Read more
15-inch 2.0GHz MacBook Pro Retina on sale for...
B&H Photo has the 15″ 2.0GHz Retina MacBook Pro on sale for $1829 including free shipping plus NY sales tax only. Their price is $170 off MSRP. B&H will also include free copies of Parallels... Read more
Apple restocks refurbished Mac minis for up t...
The Apple Store has restocked Apple Certified Refurbished Mac minis for up to $150 off the cost of new models. Apple’s one-year warranty is included with each mini, and shipping is free: - 2.5GHz Mac... Read more

Jobs Board

Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
Senior Interaction Designer, *Apple* Online...
**Job Summary** Apple is looking for a hands on Senior…will be a key player in designing for the Apple Online Store. The ideal designer will have a Read more
*Apple* Sales Chat Rep - Apple (United State...
…is looking for motivated, outgoing, and tech savvy individuals who want to offer Apple Customers an unparalleled customer experience over chat. At Apple , we believe Read more
Mac Expert - *Apple* Online Store Mexico -...
…MUST be fluent in English and Spanish to be considered for this position At Apple , we believe that hard work, a fun environment, creativity and innovation fuel the Read more
*Apple* Industrial Design CAD Sculptor - App...
**Job Summary** The Apple Industrial Design team is looking for a CAD sculptor/Digital 3D modeler to create high quality CAD models used in the industrial design process Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.