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
$102.47
Apple Inc.
+2.71
MSFT
$44.88
Microsoft Corpora
+0.80
GOOG
$526.54
Google Inc.
+5.70

MacTech Search:
Community Search:

Software Updates via MacUpdate

EyeTV 3.6.6 - Watch and record TV on you...
EyeTV brings a rich TV experience to your Mac. Watch live TV on your Mac. Pause, rewind, and record whenever you want. EyeTV gives you powerful control over what you watch and how you watch it. Put... Read more
RapidWeaver 6.0 - Create template-based...
RapidWeaver is a next-generation Web design application to help you easily create professional-looking Web sites in minutes. No knowledge of complex code is required, RapidWeaver will take care of... Read more
NTFS 12.0.39 - Provides full read and wr...
Paragon NTFS breaks down the barriers between Windows and OS X. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS, providing full read and write access to... Read more
RestoreMeNot 2.0.3 - Disable window rest...
RestoreMeNot provides a simple way to disable the window restoration for individual applications so that you can fine-tune this behavior to suit your needs. Please note that RestoreMeNot is designed... Read more
Macgo Blu-ray Player 2.10.9.1750 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Apple iOS 8.1 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
TechTool Pro 7.0.5 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PDFKey Pro 4.0.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Yasu 2.9.1 - System maintenance app; per...
Yasu was originally created with System Administrators who service large groups of workstations in mind, Yasu (Yet Another System Utility) was made to do a specific group of maintenance tasks... Read more
Hazel 3.3 - Create rules for organizing...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a... Read more

Latest Forum Discussions

See All

Swap Heroes (Games)
Swap Heroes 1.0 Device: iOS Universal Category: Games Price: $.99, Version: 1.0 (iTunes) Description: **Half price for a limited time only** Swap Heroes is a casual turn-based strategy adventure. Form a group of heroes and guide them... | Read more »
Ghost Blade (Games)
Ghost Blade 1.1 Device: iOS Universal Category: Games Price: $4.99, Version: 1.1 (iTunes) Description: Get the most outstanding 3D Action Game from App Store NOW! For those who dare pursue dreams. Masterpiece of Yu Shi Game ---China... | Read more »
Fiete – A Day on a Farm Review
Fiete – A Day on a Farm Review By Amy Solomon on October 21st, 2014 Our Rating: :: A MEMORABLE EXPERIENCEUniversal App - Designed for iPhone and iPad Fiete – A day on a farm in an interactive app for young children full of... | Read more »
Tilt to Live: Gauntlet’s Revenge is Almo...
Tilt to Live: Gauntlet’s Revenge is Almost Here Posted by Jessica Fisher on October 21st, 2014 [ permalink ] One Man Left has announced the official release date of Tilt to Live: Gauntlet’s Re | Read more »
Sago Mini Monsters Celebrates Halloween...
Sago Mini Monsters Celebrates Halloween with Fun Costumes and Special Treats. Posted by Jessica Fisher on October 21st, 2014 [ permal | Read more »
Inferno 2 Review
Inferno 2 Review By Andrew Fisher on October 21st, 2014 Our Rating: :: TWIN STICK GOODNESSUniversal App - Designed for iPhone and iPad With tight controls and awesome, stark visuals, Inferno 2 is loads of fun.   | Read more »
Clips Review
Clips Review By Jennifer Allen on October 21st, 2014 Our Rating: :: CONVENIENT PASTINGUniversal App - Designed for iPhone and iPad Making copying and pasting more powerful than usual, Clips is a great way to move stuff around.   | Read more »
MonSense Review
MonSense Review By Jennifer Allen on October 21st, 2014 Our Rating: :: ORGANIZED FINANCESiPhone App - Designed for the iPhone, compatible with the iPad Organize your finances with the quick and easy to use, MonSense.   | Read more »
This Week at 148Apps: October 13-17, 201...
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Angry Birds Transformers Review
Angry Birds Transformers Review By Jennifer Allen on October 20th, 2014 Our Rating: :: TRANSFORMED BIRDSUniversal App - Designed for iPhone and iPad Transformed in a way you wouldn’t expect, Angry Birds Transformers is a quite... | Read more »

Price Scanner via MacPrices.net

Select MacBook Airs $100 off MSRP, free shipp...
B&H Photo has 2014 a couple of MacBook Airs on sale for $100 off MSRP. Shipping is free, and B&H charges NY sales tax only. They also include free copies of Parallels Desktop and LoJack for... Read more
13-inch 2.5GHz MacBook Pro on sale for $100 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $999.99 including free shipping plus NY sales tax only. Their price is $100 off MSRP. Read more
Strong iPhone, Mac And App Store Sales Drive...
Apple on Monday announced financial results for its fiscal 2014 fourth quarter ended September 27, 2014. The Company posted quarterly revenue of $42.1 billion and quarterly net profit of $8.5 billion... Read more
Apple Posts How-To For OS X Recovery
OS X 10.7 Lion and later include OS X Recovery. This feature includes all of the tools you need to reinstall OS X, repair your disk, and even restore from a Time Machine backup. OS X Recovery... Read more
Mac OS X Versions (Builds) Supported By Vario...
Apple Support has posted a handy resource explaining which Mac OS X versions (builds) originally shipped with or are available for your computer via retail discs, downloads, or Software Update. Apple... Read more
Deals on 2011 13-inch MacBook Airs, from $649
Daily Steals has the Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB) available for $699 with a 90 day warranty. The Mid-2011 13″ 1.7GHz i5 MacBook Air (4GB/128GB SSD) is available for $649 at Other... Read more
2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros now available for $1599 including free shipping plus NY sales tax only. Their price is $400 off original MSRP. B&H... Read more
Updated iPad Prices
We’ve updated our iPad Air Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers, including the new iPad Air 2 and the... Read more
Apple Pay Available to Millions of Visa Cardh...
Visa Inc. brings secure, convenient payments to iPad Air 2 and iPad mini 3as well as iPhone 6 and 6 Plus. Starting October 20th, eligible Visa cardholders in the U.S. will be able to use Apple Pay,... Read more
Textkraft Pocket – the missing TextEdit for i...
infovole GmbH has announced the release and immediate availability of Textkraft Pocket 1.0, a professional text editor and note taking app for Apple’s iPhone. In March 2014 rumors were all about... Read more

Jobs Board

Senior Event Manager, *Apple* Retail Market...
…This senior level position is responsible for leading and imagining the Apple Retail Team's global event strategy. Delivering an overarching brand story; in-store, Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager / Business Analyst, WW *Appl...
…a senior project manager / business analyst to work within our Worldwide Apple Fulfillment Operations and the Business Process Re-engineering team. This role will work Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.