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

Cloud 4.1.1 - File sharing from your men...
Cloud is simple file sharing for the Mac. Drag a file from your Mac to the CloudApp icon in the menubar and we take care of the rest. A link to the file will automatically be copied to your clipboard... Read more
OmniFocus 2.7.1 - GTD task manager with...
OmniFocus helps you manage your tasks the way that you want, freeing you to focus your attention on the things that matter to you most. Capturing tasks and ideas is always a keyboard shortcut away in... Read more
CleanApp 5.1.1 - Application deinstaller...
CleanApp is an application deinstaller and archiver.... Your hard drive gets fuller day by day, but do you know why? CleanApp 5 provides you with insights how to reclaim disk space. There are... Read more
ForkLift 3.0 Beta 2 - Powerful file mana...
ForkLift is a powerful file manager and ferociously fast FTP client clothed in a clean and versatile UI that offers the combination of absolute simplicity and raw power expected from a well-executed... Read more
Sublime Text 3126 - Sophisticated text e...
Sublime Text is a sophisticated text editor for code, markup, and prose. You'll love the slick user interface, extraordinary features, and amazing performance. Features Goto Anything. Use Goto... Read more
1Password 6.3.3 - Powerful password mana...
1Password is a password manager that uniquely brings you both security and convenience. It is the only program that provides anti-phishing protection and goes beyond password management by adding Web... Read more
WhatsApp 0.2.1880 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
NeoFinder 6.9.3 - Catalog your external...
NeoFinder (formerly CDFinder) rapidly organizes your data, either on external or internal disks, or any other volumes. It catalogs all your data, so you stay in control of your data archive or disk... Read more
Amadeus Pro 2.3.1 - Multitrack sound rec...
Amadeus Pro lets you use your Mac computer for any audio-related task, such as live audio recording, digitizing tapes and records, converting between a variety of sound formats, etc. Thanks to its... Read more
Yasu 4.0.0 β - System maintenance app; p...
Yasu was 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 quickly within a... Read more

Our 5 Favorite iMessage Sticker Packs
At long last, iMessage joins the ranks of messaging apps the likes of LINE and Whatsapp, adding an impressive collection of stickers. They’re a great way to add a little something extra to your daily conversations. [Read more] | Read more »
How to get past Vulture Island's tr...
Vulture Island is a colorful and quirky mish-mash of platforming and puzzles. It’s creative and fresh, but sometimes the game can throw a curveball at you, leaving you stuck as to how you should progress. These tips will help you explore smoothly... | Read more »
The new Clash of Kings is just for Weste...
If you’ve played the original Clash of Kings, you’ll probably recognise the city building, alliance forging and strategic battles in Clash of Kings: The West. What sets this version apart is that it’s tailor made for a Western audience and the... | Read more »
Frost - Survival card game (Games)
Frost - Survival card game 1.12.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.12.1 (iTunes) Description: *Warning: the game will work on iPhone 5C and above and iPad Pro / 4. Other devices are not supported* | Read more »
How to build and care for your team in D...
Before you hit the trail and become a dog sledding legend, there’s actually a fair bit of prep work to be done. In Dog Sled Saga, you’re not only racing, you’re also building and caring for a team of furry friends. There’s a lot to consider—... | Read more »
How to win every race in Dog Sled Saga
If I had to guess, I’d say Dog Sled Saga is the most adorable racing game on the App Store right now. It’s a dog sled racing sim full of adorable, loyal puppies. Just look at those fluffy little tails wagging. Behind that cute, pixelated facade is... | Read more »
Let the war games commence in Gunship Ba...
Buzz Lightyear famously said, “This isn’t flying, this is falling – with style!” In the case of Gunship Battle: Second War, though, this really is flying - with style! The flight simulator app from Joycity puts you in control of 20 faithfully... | Read more »
How to get a high score in Fired Up
Fired Up is Noodlecake Games’ high score chasing, firefighting adventure. You take control of a wayward firefighter who propels himself up the side of a highrise with blasts of water. Sound silly? It is. It’s also pretty difficult. You can’t... | Read more »
NBA 2K17 (Games)
NBA 2K17 1.0 Device: iOS iPhone Category: Games Price: $7.99, Version: 1.0 (iTunes) Description: Following the record-breaking launch of NBA 2K16, the NBA 2K franchise continues to stake its claim as the most authentic sports video... | Read more »
Dog Sled Saga (Games)
Dog Sled Saga 1.0.1 Device: iOS Universal Category: Games Price: $3.99, Version: 1.0.1 (iTunes) Description: A game by Dan + Lisa As a rookie musher, foster a dogsledding team whose skills will grow if they're treated right. Week by... | Read more »

Price Scanner via MacPrices.net

13-inch 2.5GHz MacBook Pro (Apple refurbished...
Apple has Certified Refurbished 13″ 2.5GHz MacBook Pros available for $829, or $270 off the cost of new models. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz MacBook Pros... Read more
Save 30% on Camera Guard’s Secure Protection...
To celebrate the release of macOS Sierra, Miami-based security solutions company, ProtectStar has announced a special 30% discount on Camera Guard Professional for Mac 2016. This innovative security... Read more
DVDFab Special Deal – Get a 1-Year Free Licen...
Beijing, China based specialist in the field of DVD, Blu-ray and video backup solutions, Fengtao Software has launched its Autumn Special Deals 2016, giving a 1-year free license of a randomly picked... 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″ 3.1GHz iMac 4K: $1379 $120 off MSRP - 21″ 2.8GHz iMac: $1199.99 $100 off MSRP - 21″ 1... Read more
13-inch 2.7GHz/256GB Retina MacBook Pro on sa...
Amazon.com has the 13″ 2.7GHz/256GB Retina Apple MacBook Pro on sale for $151 off MSRP including free shipping: - 13″ 2.7GHz/256GB Retina MacBook Pro (sku MF840LL/A): $1348 $151 off MSRP Read more
Apple TVs on sale for up to $50 off MSRP
Best Buy has 32GB and 64GB Apple TVs on sale for $40-$50 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Sale prices for online orders only, in-store... Read more
Apple refurbished 13-inch Retina MacBook Pros...
Apple has Certified Refurbished 13″ Retina MacBook Pros available for up to $270 off the cost of new models. An Apple one-year warranty is included with each model, and shipping is free: - 13″ 2.7GHz... Read more
Duplicate Sweeper Free On Mac App Store For O...
To celebrate the launch of Apple’s latest macOS Sierra, Stafford, United Kingdom based Wide Angle Software has announced that its duplicate file finder software, Duplicate Sweeper, is now available... Read more
13-inch Retina MacBook Pros on sale for up to...
B&H Photo has 13″ Retina Apple MacBook Pros on sale for up to $150 off MSRP. Shipping is free, and B&H charges NY tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro: $1174.99 $125 off MSRP - 13... Read more
Evidence Surfaces Pointing To New A10X Chip F...
Citing a job description for a Project Lead position at Apple’s Austin, Texas engineering labs, Motley Fool’s Ashraf Eassa deduces that development is progressing well on Apple’s next-generation in-... Read more

Jobs Board

Sr. *Apple* Mac Engineer - Net2Source Inc....
…staffing, training and technology. We have following position open with our client. Sr. Apple Mac Engineer6+ Months CTH Start date : 19th Sept Travelling Job If Read more
*Apple* Retail - Multiple Positions-Norfolk,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Restaurant Manager (Neighborhood Captain) - A...
…in every aspect of daily operation. WHY YOU'LL LIKE IT: You'll be the Big Apple . You'll solve problems. You'll get to show your ability to handle the stress and Read more
Lead *Apple* Solutions Consultant - Apple (...
# Lead Apple Solutions Consultant Job Number: 51829230 Detroit, Michigan, United States Posted: Sep. 19, 2016 Weekly Hours: 40.00 **Job Summary** The Lead ASC is an Read more
US- *Apple* Store Leader Program - Apple (Un...
…Summary Learn and grow as you explore the art of leadership at the Apple Store. You'll master our retail business inside and out through training, hands-on Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.