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/.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Microsoft Remote Desktop 8.0.19 - Connec...
With Microsoft Remote Desktop, you can connect to a remote PC and your work resources from almost anywhere. Experience the power of Windows with RemoteFX in a Remote Desktop client designed to help... Read more
OmniGraffle 6.3 - Create diagrams, flow...
OmniGraffle helps you draw beautiful diagrams, family trees, flow charts, org charts, layouts, and (mathematically speaking) any other directed or non-directed graphs. We've had people use Graffle to... Read more
PDFKey Pro 4.3.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
Ableton Live 9.2.2 - Record music using...
Ableton Live lets you create and record music on your Mac. Use digital instruments, pre-recorded sounds, and sampled loops to arrange, produce, and perform your music like never before. Ableton Live... Read more
Macs Fan Control 1.3.1.0 - Monitor and c...
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
NetShade 6.3.1 - Browse privately using...
NetShade is an anonymous proxy and VPN app+service for Mac. Unblock your Internet through NetShade's high-speed proxy and VPN servers spanning seven countries. NetShade masks your IP address as you... Read more
Dragon Dictate 4.0.7 - Premium voice-rec...
With Dragon Dictate speech recognition software, you can use your voice to create and edit text or interact with your favorite Mac applications. Far more than just speech-to-text, Dragon Dictate lets... Read more
Persecond 1.0.2 - Timelapse video made e...
Persecond is the easy, fun way to create a beautiful timelapse video. Import an image sequence from any camera, trim the length of your video, adjust the speed and playback direction, and you’re done... Read more
GIMP 2.8.14p2 - Powerful, free image edi...
GIMP is a multi-platform photo manipulation tool. GIMP is an acronym for GNU Image Manipulation Program. The GIMP is suitable for a variety of image manipulation tasks, including photo retouching,... Read more
Sandvox 2.10.2 - Easily build eye-catchi...
Sandvox is for Mac users who want to create a professional looking website quickly and easily. With Sandvox, you don't need to be a Web genius to build a stylish, feature-rich, standards-compliant... Read more

ReBoard: Revolutionary Keyboard (Utilit...
ReBoard: Revolutionary Keyboard 1.0 Device: iOS Universal Category: Utilities Price: $1.99, Version: 1.0 (iTunes) Description: Do everything within the keyboard without switching apps! If you are in WhatsApp, how do you schedule a... | Read more »
Tiny Empire (Games)
Tiny Empire 1.1.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.3 (iTunes) Description: Launch cannonballs and blow tiny orcs into thousands of pieces in this intuitive fantasy-themed puzzle shooter! Embark on an... | Read more »
Astropad Mini (Productivity)
Astropad Mini 1.0 Device: iOS iPhone Category: Productivity Price: $4.99, Version: 1.0 (iTunes) Description: *** 50% off introductory price! ​*** Get the high-end experience of a Wacom tablet at a fraction of the price with Astropad... | Read more »
Emo Chorus (Music)
Emo Chorus 1.0.0 Device: iOS Universal Category: Music Price: $1.99, Version: 1.0.0 (iTunes) Description: Realistic Choir simulator ranging from simple Chorus emulation to full ensemble Choir with 128 members. ### introductory offer... | Read more »
Forest Spirit (Games)
Forest Spirit 1.0.5 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.5 (iTunes) Description: | Read more »
Ski Safari 2 (Games)
Ski Safari 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The world's most fantastical, fun, family-friendly skiing game is back and better than ever! Play as Sven's sister Evana, share... | Read more »
Lara Croft GO (Games)
Lara Croft GO 1.0.47768 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.47768 (iTunes) Description: Lara Croft GO is a turn based puzzle-adventure set in a long-forgotten world. Explore the ruins of an ancient... | Read more »
Whispering Willows (Games)
Whispering Willows 1.23 Device: iOS Universal Category: Games Price: $4.99, Version: 1.23 (iTunes) Description: **LAUNCH SALE 50% OFF** - Whispering Willows is on sale for 50% off ($4.99) until September 9th. | Read more »
Calvino Noir (Games)
Calvino Noir 1.1 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: The film noir stealth game. Calvino Noir is the exploratory, sneaking adventure through the 1930s European criminal underworld.... | Read more »
Angel Sword (Games)
Angel Sword 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: Prepare to adventure in the most epic full scale multiplayer 3D RPG for mobile! Experience amazing detailed graphics in full HD.... | Read more »

Price Scanner via MacPrices.net

Apple and Cisco Partner to Deliver Fast-Lane...
Apple and Cisco have announced a partnership to create a “fast lane” for iOS business users by optimizing Cisco networks for iOS devices and apps. The alliance integrates iPhone with Cisco enterprise... Read more
Apple offering refurbished 2015 13-inch Retin...
The Apple Store is offering Apple Certified Refurbished 2015 13″ Retina MacBook Pros for up to $270 (15%) off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
Apple refurbished 2015 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2015 11″ and 13″ MacBook Airs (the latest models), available for up to $180 off the cost of new models. An Apple one-year warranty is included with... Read more
21-inch iMacs on sale for up to $120 off MSRP
B&H Photo has 21″ iMacs on sale for up to $120 off MSRP including free shipping plus NY sales tax only: - 21″ 1.4GHz iMac: $999.99 $100 off - 21″ 2.7GHz iMac: $1199.99 $100 off - 21″ 2.9GHz iMac... Read more
5K iMacs on sale for up to $150 off MSRP, fre...
B&H Photo has the 27″ 3.3GHz 5K iMac on sale for $1899.99 including free shipping plus NY tax only. Their price is $100 off MSRP. They have the 27″ 3.5GHz 5K iMac on sale for $2149.99 $2199.99, $... Read more
1.4GHz Mac mini, refurbished, available for $...
The Apple Store has Apple Certified Refurbished 1.4GHz Mac minis available for $419. Apple’s one-year warranty is included, and shipping is free. Their price is $80 off MSRP, and it’s the lowest... Read more
iPad Air 2 on sale for up to $100 off MSRP
Best Buy has iPad Air 2s on sale for up to $100 off MSRP on their online store for a limited time. Choose free shipping or free local store pickup (if available). Sale prices available for online... Read more
MacBook Airs on sale for $100 off MSRP
Best Buy has MacBook Airs on sale for $100 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Sale prices for online orders only, in-store prices may vary... Read more
Big Grips Lift Handle For iPad Air and iPad A...
KEM Ventures, Inc. which pioneered the extra-large, super-protective iPad case market with the introduction of Big Grips Frame and Stand in 2011, is launching Big Grips Lift featuring a new super-... Read more
Samsung Launches Galaxy Tab S2, Its Most Powe...
Samsung Electronics America, Inc. has announced the U.S. release of the Galaxy Tab S2, its thinnest, lightest, ultra-fast tablet. Blending form and function, elegant design and multitasking power,... Read more

Jobs Board

*Apple* Evangelist - JAMF Software (United S...
The Apple Evangelist is responsible for building and cultivating strategic relationships with Apple 's small and mid-market business development field teams. This Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Desktop Analyst - KDS Staffing (Unit...
…field and consistent professional recruiting achievement. Job Description: Title: Apple Desktop AnalystPosition Type: Full-time PermanentLocation: White Plains, NYHot Read more
*Apple* Systems Engineer (Mclean, VA and NYC...
Title: Apple Systems Engineer (Mclean, VA and NYC) Location: United States-New York-New York-200 Park Ave (22005) Other Locations: United States-Virginia-Vienna-Towers Read more
*Apple* Systems Engineer (Mclean, VA and NYC...
…Assist in providing strategic direction and technical leadership within the Apple portfolio, including desktops, laptops, and printing environment. This person will Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.