Hour 14. Planning for Reuse: Frameworks and Libraries


What You’ll Learn in This Hour:

The purpose of libraries and frameworks

The difference between libraries, frameworks, and just plain code

How to build static libraries and frameworks

How to deploy a framework so that it can be shared with other programmers or applications

How to adapt library code from other sources


This hour begins a series of four lessons that put everything you have learned together into common development tasks in Xcode 4. Hold tight. These hours might take a bit longer than an hour because you can put the pieces together in so many different ways. In the end, you want to make sure you have chosen the best combination for the development project you have planned.

This hour starts by introducing the role of libraries and frameworks in development, walks you through building a static library and a reusable framework, and then illustrates how you can adopt library code from libraries developed on other platforms into Xcode.

Understanding Frameworks

Frameworks and libraries are both ways of packaging compiled copies of reusable code so that it can be used in multiple projects. Frameworks are primarily used for dynamic components—that is, components that are not built in to the software when it is compiled, but rather are loaded in each time it is run. Libraries can be either dynamic (loaded at runtime) or static (included in the compiled application when it is built), though Apple discourages the use of bare dynamic libraries, and instead prefers them to be packaged into frameworks.


By the Way

If you’re already familiar with the idea of dynamic libraries, you can think of frameworks as a more completely featured version of the dynamic library idea. Whereas dynamic libraries package only executable routines and associated symbols, and are instantiated as a single versioned file, a single framework can encapsulate any number of independent dynamic library files, all the header files that define the routines for the dynamic libraries, and also associated resource files such as images, documentation files, or other data used by the libraries.

If you are not familiar with dynamic libraries, you probably do not really need to worry about writing your own frameworks for a while anyway. You’re welcome to keep reading, but if this reusable components business is confusing, don’t worry; when you need it, it’ll all make sense.


Static libraries are used to dump their object contents directly into your project, as though the source is there, when you build your project. The necessary objects are linked, the necessary executable modules are copied into your application, and it all gets collected together in a single executable file where all the necessary pieces (and if your compiler is good, none of the unnecessary pieces) are included.

You can think of the difference between static and dynamic libraries as much like the difference between DVDs and streaming copies of a movie. You link the static library at compile time, which includes its executable object code into your application. You buy the DVD, which becomes part of your personal collection. If you move the application, the compiled-in executable components copy with it. If you move apartments, you take the DVD with you. If you copy the application, you duplicate the compiled-in executable components, thereby using disk space to store the same thing twice. If your friend wants to own a copy of the DVD, he buys his own copy, and the two of you now have two physical copies between you. If the static library gets updated and a new version becomes available with new features, your application doesn’t know anything about this and keeps on using the compiled-in code it has always been using. If you want the new features, you recompile the application. If the studio releases a new version of the DVD, you’re stuck with the old one you already own. If you want the new one, you buy another copy.

However, if you bought a streaming copy of the movie from the iTunes Store, you do not get a copy of the movie until (and only while) you’re watching it. This is like using a dynamic library. Your application knows that it can use the library, but it doesn’t actually have the executable code on hand. When you launch the application, it has to load the content, just like you have to download the movie to watch it. When you move apartments, you do not take a copy of the movie; you just download it again when you want to watch it again. When you run your application a second time, it has to load the dynamic library all over again. When your friend wants a copy of the movie, she gets pointed to the very same downloadable content that you use. When you duplicate your program, it doesn’t duplicate the dynamic library, the new copy just also knows where to ask to use the library at runtime. When the studio updates the movie in iTunes to correct some damaged footage, you see the updated version automatically the next time you watch it. When the dynamic library is updated to fix a bug or function more efficiently, those changes are automatically available to your application when it loads the updated dynamic library the next time it runs.

Making the Choice

If a routine in your project could also be useful in some other project, placing that routine in either a framework or a static library is a way to let you maintain the reusable routine independent of either project, while making sure that it can be used in both.

If the routines that you’re considering putting into a framework really do not have any use outside your current project, it is often pointless, and usually actually counterproductive, to put them into libraries or frameworks.

If the reusable bits are going to be completely finished and never need updated, putting them into a static library makes sense.

If the reusable bits might need to be updated often, especially if they need to be updated without recompiling the entire application project, a framework is appropriate—this is even true if the bits are not really all that reusable.

If the code has a significant memory footprint, and multiple programs might need to use that code at the same time (multiple different programs or multiple running copies of the same program), a framework is appropriate because every running program shares access to the same loaded instance of a framework.

However, if you want to use the same reusable code bits in both a Mac OS X application and an iOS application, you may want to target a static library. Apple doesn’t allow the use of third-party frameworks on iOS devices yet, so if you use framework-specific features when building the OS X version, you’ll have additional work to do when adapting those routines to a static library for your iOS deployment.


Did You Know?

There is also a new automagic way to deal with code/data reusability with Xcode 4. Workspaces, covered in Hour 20, “Keeping Things Organized: Shared Workspaces,” promise to automatically address issues of code and data reuse across multiple projects, simply by maintaining those projects within a single shared workspace environment.



Did You Know?

Unfortunately, although this will undoubtedly become a much more streamlined and convenient way to handle reusable components as Xcode continues to mature, a) some of the workspace features are not quite ready for prime time, and b) workspaces are an Xcode-specific feature. In contrast, libraries and frameworks are uses and adaptations of standard software development/distribution mechanisms that are almost universal. So, the workspace-specific mechanisms limit your ability to share your work with users of other development environments on OS X or on other platforms such as Linux.


For example, consider developing a video game. If your game uses physics, it is probably important to you that your game and its physics run as fast as possible. If you’re just developing one video game, forget libraries; compiling the physics code directly into your game makes the most sense. It’ll start faster, and the optimizer will be able to reject unused portions of the code, appropriately defer execution, unwrap loops, and so on more efficiently.

If you’re developing a suite of games all based around the same physics engine, consider using a static library that gets linked with all your games. You lose a little bit of efficiency because some optimizer tricks cannot be applied to the library when it is compiled independent of the final applications, but the linker will still do its best to eliminate unused bits. If your physics code is finished, though, and you’re never going to touch it again, and no one else will need to either, a single static library that just gets linked to each of the games makes life easy and nearly maximizes performance.

However, if you’re developing a game or a suite of games, all of which use the same communication engine to facilitate network play, and you’re continuously updating the communication engine as you think of new tricks to optimize the communications stream, using a dynamic library in a framework makes good sense. You lose a bit of efficiency because each time the game starts it has to load the dynamic library, figure out what symbols are where, and coordinate all of that with your existing program, and optimization cannot make nearly as much an improvement in execution speed. However, you get the significant benefit of being able to tweak the communications code and deploy new variations on it under your game, or all of your games, just by recompiling the framework, without having to rebuild your game or games.


By the Way

An amazing amount of bad advice exists on the Internet regarding using frameworks. In addition to everyone and his brother recommending that you put oodles of code that has no business being in a framework into frameworks, Internet programming mavens have another favorite chestnut that many of them seem quite eager to offer: embedded frameworks.

They just love embedded frameworks. Embedded frameworks are frameworks that you build and then include inside your application bundle so that your application always uses its own, self-contained private copy of the framework that is always exactly the version it expects and is always exactly where it expects it to be. This provides quite a lot of convenience, and in fact you learn how to set up a framework for this purpose in this hour of the book.

Stop and think about this for a minute, though. If the purpose of a framework is to encapsulate reusable, independently updatable routines, is it really a big advantage to hide it privately inside an application bundle, where it cannot be reused and where it cannot be updated? Usually, the answer is no. In fact, usually the answer is that if an embedded framework will work, linking the code directly as a part of your application works better.

Embedded frameworks are really best used for situations where you either want to distribute the framework conveniently bundled inside your application and then let the application install it for systemwide usage or when it’s impossible to properly install the framework in /Library/Frameworks/ because of system security issues. They also prove useful when you are co-developing a piece of software and a support framework for it, because embedded frameworks limit the amount of trouble that errors or test code in the framework can cause for the rest of the system (because their effect is limited to the application bundle that contains them). Other than those situations, however, embedded frameworks are usually the lazy way of accomplishing something that could better be done some other way.


Making a Static Library

Making a static library is much like making most other projects in Xcode. In short, you tell Xcode that you want to build a project, select Static Library as the type of project to build, add some code, and build away. You can then include the result as a component in other projects that need to use the routines you have built within the library. The only real trick to this process is that you also need to specify the parts of the library that should be exposed to programs that want to use the library. Internal parts of the library (bits that the library requires for functionality but that the applications that use the library shouldn’t be fiddling with) need to be declared to be private to the library (peculiarly, Apple uses the term project for these), and bits that need to be available for the external application’s use need to be declared public. The following section walks you through the process of building a static library for a simple library that provides a doubly linked list class.

To build a static library, follow these steps:

1. Tell Xcode that you want to create a new project by selecting File, New, New Project from the menu.

2. Select the Framework & Library collection from the left pane and the Cocoa Library item from the right pane, as shown in Figure 14.1.

Image

Figure 14.1. Creating a new Cocoa Library project.

3. Decide on a product name and provide a company identifier.

You should decide on a uniform company identifier and use it for all of your work, but it doesn’t much matter what that identifier is as long as it is likely to be unique. As mentioned previously, Apple recommends a reverse-domain-name string for your company specifier. For your own personal use, any arbitrary string is fine.

4. For the project name, choose something meaningful related to the functionality of the library you’re building.

We are building a doubly linked list library, so I am calling my project Lists. The value you supply here also gets used for the default class name in the generated project files, so it is probably best to avoid spaces, although you can modify this value in the files if it turns out you prefer to have your classes named something else.

5. Unless you have a good reason to do otherwise, fill in the rest of the dialog box as shown in Figure 14.2.

Image

Figure 14.2. Choosing options for your project.

6. Select Static for the type. After all, although you can build a dynamic library this way, there’s little point; frameworks do it better.

7. Turn on Use Automatic Reference Counting.

Unless you really want to manage freeing all allocated memory yourself, just let Automatic Reference Counting deal with freeing memory whenever the last reference to an object is removed.

8. Turn on Include Unit Tests.

This is up to you. I prefer to include them in case I want to use them later. You might consider them as extraneous to the project.

9. Finally, navigate to where you want to store the project and create it.

Leave the Source Control box checked, as shown in Figure 14.3, to create a local version-control repository for the project, unless you want to exclusively connect the project to a remote version control server. If you leave it on, you can enable both local and remote version control. So unless disk space is seriously tight, leaving local version control turned on does not hurt.

Image

Figure 14.3. Navigating to where you would like to store your project.

Xcode populates your project with a collection of directories and likely culprits that your project may depend on. You land in a full Xcode project window, as shown in Figure 14.4, with two targets in the Navigator panel (your library and its test suite), several tabs of useful details (some of which you might want to customize in the main Editor area), and compact interfaces to some likely utility functions you might need in the Utilities.

Image

Figure 14.4. Your Xcode project window.

Note that you have a library (starting with lib and ending in .a) and a test suite that appear under Products in the Navigator panel. They are both red because neither has been successfully built yet. Under the Build Settings tab, you can modify the intended deployment directory (although this value is overridden by another setting in the Xcode Preferences Locations tab, discussed in more detail later in this hour), as well as numerous other configurable settings that affect details of the way that your target is built.

Under the Build Settings tab are more configuration options for your project. In this panel, shown in Figure 14.5, you can configure deployments for other versions of the operating system, set up multi-architecture builds, and adjust several features of the debugging system.

Image

Figure 14.5. The Build Settings panel.

Pay attention to the Optimization Level setting. Setting this to more optimized levels can make a significant difference in how fast your program runs. It is not uncommon to see speedups of 3x or more when optimization is turned on. However, optimizing compilers are tricky things. In addition to just eliminating wasted space in your executable, they can also figure out certain situations where your code would have been more efficient if written somewhat differently, and they’ll use their more efficient version for building if optimization is turned on. This can lead to quite bizarre effects when debugging because what you see in the debugger is your code, but what is running is the optimized version.

When debugging optimized software, you will often see the program seemingly ignoring simple explicit statements and internally producing values that are entirely inconsistent with the logic of the code as you have written it. This is not an error, but rather an instance of the compiler recognizing, for example, that it would have been much more efficient if you had compared i to 6 instead of incrementing i and comparing it to 7. This behavior is doubly confusing when you’re building libraries because they are often dissociated from the code that will eventually use them, which makes debugging more difficult.

Listing 14.1 shows the prepopulated contents of the .h file.

Listing 14.1. Prepopulated Contents of a default .h File


//
// Lists.h
// Lists
//
// Created by William Ray on 1/28/12.
// Copyright (c) 2012 SGF. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Lists : NSObject

@end


Listing 14.2 shows the prepopulated contents of the .m file.

Listing 14.2. Prepopulated Contents of a default .m File


//
//  Lists.m
//  Lists
//
//  Created by William Ray on 1/28/12. 
//  Copyright (c) 2012 SGF. All rights reserved.
//

#import "Lists.h"

@implementation Lists

- (id)init
{

    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}

@end


Add your header code to the .h file by clicking in the Navigator and editing it in the Editor (in my case, that’s Lists.h) and add your implementation code into the .m file (my Lists.m). Click the Run button, and you should be rewarded with a successful build, as shown in Figure 14.6. Note that my libLists.a product has now turned black, indicating a clean build.

Image

Figure 14.6. A successful build.

Select the library (*.a) product and look at the File Inspector in the Utilities. You’ll see, under Identity and Type, shown in Figure 14.7, that the build has placed your library in a fairly bizarre directory. This library is what you need to distribute to other people to let them use your code or to place in your /usr/local/lib directory if you want other projects of yours to be able to link against it. You can click the small arrow next to the path to reveal the file in the finder and then copy it somewhere more obvious, or you can change your Xcode preferences to control this behavior.

Image

Figure 14.7. Identity and Type in the Utilities panel shows where your library has been placed.

Open your Xcode preferences and go to the Locations tab. On the pane that appears, shown in Figure 14.8, you’ll see that derived data (things like the .a file you built) is going to go into the Default directory, which is buried in ~/Library/Developer/Xcode/DerivedData/. You can change that Default value to Relative, in which case it switches to using a DerivedData directory within your Project directory, or you can change the value to Custom, which lets you specify an explicit path. The Relative setting is a bit more sane than the Default setting.

Image

Figure 14.8. Under the Locations tab in the Xcode preferences, you can change the default locations for the derived data, as well as for snapshots and archives.

You have another option, too, hidden under the Advanced button. This button brings up another dialog, shown in Figure 14.9, where you can set the build location to either the default or the locations specified by targets. The Locations Specified by Targets setting generates a behavior that is probably more like what you were expecting. It creates Debug (or other appropriate target) directories within the Project directory and puts the output files there, as shown in Figure 14.10. This is essentially the behavior you have come to expect from earlier versions of Xcode.

Image

Figure 14.9. Clicking the Advanced button for the derived data brings up this dialog to set the build location to either the default or locations specified by targets.

Image

Figure 14.10. After you select Locations Specified by Targets, the output files are stored in directories within the Project directory.


By the Way

Consider this an Xcode bug. If you change the Build Location option to Locations Specified by Targets in the dialog shown in Figure 14.9, and then look at the dialog shown in Figure 14.8, it’ll look exactly the same. This dialog does not update to reflect the fact that the files now are not going to land in the Default directory.


If you want to validate that your library does what its supposed to do, and do a bit of debugging without writing a proper application around it, you can use the Unit Test testing suite that Xcode has already begun to populate for you. Under the Tests directory, you have another .h file and .m file. These are supposed to be used for building unit tests so that you can continually monitor the functionality of your code as you build it (as covered in detail in Hour 18, “Test Early, Test Often”), but they are also useful for quick-and-dirty debugging.

As shown in Figure 14.11, add some simple calls to your library functions and add diagnostics with NSLog(). Select Test from the Product menu, and the code you have added will be run, linked against your library. This can give you a rapid readout of functionality without you ever needing to write a main() routine.

Image

Figure 14.11. Showing a successful test run generated by adding some simple calls to the library, adding diagnostics with NSLog() and running Test from the Product menu.

Making a Framework

To make a framework, you follow much the same process as when making a static library. The biggest difference, other than telling Xcode that you are building a framework, is that you can include noncode components inside frameworks. Because frameworks are really directory structures like any other bundle, they can contain not just the compiled executable code, but also the header files defining the routine interfaces, image files, and other components that the library, or applications using the library, might need. Setting up these additional components requires a few steps beyond what a static library requires.

To build a framework, follow these steps:

1. Tell Xcode that you want to create a new project by selecting File, New, New Project from menu.

2. Select the Framework & Library collection from the left pane and the Cocoa Framework item from the right pane, as shown in Figure 14.12.

Image

Figure 14.12. Selecting the Cocoa Framework item to start a framework project.

3. Fill in your project name and company identifier as was done for a library and leave the Automatic Reference Counting and Unit Tests options turned on.

4. Pick a place to put it.

5. Again, leave the Git repository turned on.

You are then presented with a prepopulated Navigator panel with much the same content as was present for your library, and similar build options in the main Editor panel.

6. Fill in your .m and .h files.

7. The same content as you used for your library will do, although you probably want to use a different class name, just to reduce confusion.


Did You Know?

Here comes a big difference between frameworks and libraries.

If additional resources would be convenient for your code to carry around with it, such as images it will use in NIB files, you can drag them into the Navigator and drop them in the Supporting Files folder that’s with your framework implementation and header files now. Any data files that would be good to keep with your code after it has been distributed can be included here, either directly in the Supporting Files folder or in a directory structure of your choosing beneath it.

After you drop the items, tell the resulting dialog that you want to copy the items and to create groups for Folders. Make sure that any target that might need access to the files is selected before clicking Finish.

With the library, all you got was the output .a file and the header .h file that you wrote for it. Frameworks are bundles of related resources, and the files you add are included in your framework when it is built.


8. Fill in your test suite, too.

9. Build your project by selecting Build from the Product menu, and then test it by selecting Test from the Product menu.

If you have your build configuration set to Debug in your build scheme (see Hour 19), everything will probably work just fine. However, if you have your build configuration set to Release, you are likely to get an error when your test suite tries to #import your framework header file. This is due to a subtle difference in how the compiler looks for header files when it is using frameworks as compared to when it is using libraries. Specifically, frameworks are supposed to carry their headers around with them, and for some reason, Xcode does not default to copying the headers into the build directory.


By the Way

Consider this another Xcode bug. Sometimes, for reasons I don’t understand, Xcode will produce correct output from your test routine, as shown in Figure 14.13, and simultaneously complain that it cannot find the header file that it needs to compile.


Image

Figure 14.13. Sometimes Xcode produces correct output from your test routine even while complaining that it cannot find the header files that it needs to compile.

When you look in the Build directory, shown in Figure 14.14, you see the source of the trouble. Under the ListsToo.framework directory, there are proper Versions and Resources directories, but no Headers directory. Things trying to use this framework cannot find them because the directory and the headers it is supposed to contain are missing.

Image

Figure 14.14. The Build directory for this framework is missing the Headers directory.

To fix this, follow these steps:

1. Select your project in the Navigator.

2. Display the Build Phases tab in the main Editor panel.

Here, you find a section called Copy Headers, conveniently denoted as having no items.

3. Open the Copy Headers section so that you can see the Public, Private, and Project headers subsections and the + button beneath them, as shown in Figure 14.15.

Image

Figure 14.15. Under the Build Phases tab of the Navigator panel, you can copy the missing header files.

4. Click the + button.

You are then presented with a dialog like that in Figure 14.16.

Image

Figure 14.16. Select the header file that you want to copy from this dialog that appears after clicking the + button.

5. Select your .h header file and click Add.

Annoyingly, you’ll find that the .h file lands in the Project headers section, as shown in Figure 14.17. This is not helpful. Project headers are, semi-intuitively, private to the project and are not exported. Private headers are, counterintuitively, private to the project but will be exported, although they cannot be used by external applications. Public headers are exported and are available for use by external code. This is where you want your .h file to go.

Image

Figure 14.17. The header file gets copied to the Projects section.

6. Select your header .h file where it has landed in the Projects section and drag it to the Public section so that your configuration looks like Figure 14.18.

Image

Figure 14.18. The header file has now been moved from the Projects section to the Public section.

7. Select your framework in the Navigator again and use the Project menu to build it.

Your Build directory should change to include a Headers directory within the Versions section and a link to it from the top level of the Framework directory, as shown in Figure 14.19. Now if you go back and run your tests, they can find your header files correctly.

Image

Figure 14.19. After building, the Build directory includes a Headers directory within the Versions section and a link to it from the top level of the Framework directory.

Deploying a Framework

You learn how to include your framework in applications that you write in Hour 15, “Putting It All Together: Building a Mac OS Application,” but sometimes the point of a framework is just to have the framework. If you need to share the framework, or test it in place in /Libraries/Frameworks/, the easiest way to do this is to archive your framework project, as follows:

1. Under the Product menu, select Archive. This creates an archive of your project and opens the Organizer.

2. Select your project from the archives, as shown in Figure 14.20, and then click the Share button. A dialog like that in Figure 14.21 opens.

Image

Figure 14.20. Selecting your project from the Archives in the Organizer.

Image

Figure 14.21. Clicking the Share button brings up this dialog, where you can select the Built Products option.

3. Select the Built Products option, click Next, and give it some place to save the archive.

It creates a folder in that location, and if you check the contents of the folder, you’ll see that it is a complete copy of your framework, ready to be copied into /Library/Frameworks/ or ~/Library/Frameworks/.

Reusing Code from Existing C/C++ Libraries

Most existing C and C++ libraries can be built using Xcode with little difficulty. These traditional libraries are simply collections of concatenated object files, and Xcode can compile and concatenate them using simple project templates designed for this task. Figure 14.22 shows the result of attempting to build a simple C program that is trying to call three functions (libfunc1(), 2, and 3) that are not defined within it. Not only does the Editor window flag the implicit declarations of these functions when the program tries to call them, but the error messages highlight the fact that there are no definitions that it can find for libfunc1(), lib-func2(), and libfunc3().

Image

Figure 14.22. Showing what happens when trying to build a simple C program that calls functions that are not defined in it.

To remedy this, follow these steps:

1. Create a new project, selecting the C/C++ Library project template.

2. Add C language files and define your functions in them.

3. Add a header file with prototypes for your functions.

Listings 14.3 and 14.4 show a very simple header file defining libfunc1(), libfunc2(), and libfunc3(), and the entire contents of the C file defining libfunc1(). There are two additional, almost identical C files defining libfunc2() and libfunc3() that are not shown.

Listing 14.3. Header File Defining libfunc1(), libfunc2(), and libfunc3()


//
// libstaticC.h
// StaticC
//
// Created by William Ray on 1/28/12.
// Copyright (c) 2012 SGF. All rights reserved.
//

#ifndef StaticC_libstaticC_h
#define StaticC_libstaticC_h

int libfunc1(int);
int libfunc2(int);
int libfunc3(int);

#endif


Listing 14.4. Contents of the C File Defining libfunc1()


//
// libfile1.c
// StaticC
//
// Created by William Ray on 1/28/12.
// Copyright (c) 2012 SGF. All rights reserved.
//

#include “libstaticC.h”

int libfunc1(int inval)
{
    return inval * 3;
}


The libfile2.c and libfile3.c files contain essentially identical code, with the appropriate function definitions.

4. Build the project by selecting Build under the Product menu. The three.c files are compiled into .o files and aggregated into a single .a file. This .a file is your C language library.

5. Open the project that failed in Figure 14.22 and position its Xcode window behind the project where you built the static library.

6. Then drag the .a file and the .h file over into the Project directory of the failed application, as shown in Figure 14.23.

Image

Figure 14.23. Adding the static library containing functions that the failed C project needs.


By the Way

Non-Xcode build systems usually aggregate object files using a program called ar, called from within a file named Makefile. Use a text editor (the Xcode Editor will do) to look in the Makefile for a line that starts with ar. It should contain a bunch of files ending in .o, and one that starts with lib and ends with .a. That line is responsible for creating the library archive. Collect all the .c files that correspond to those .o files and add them to your C/C++ library project. The output from the build will be an equivalent .a file to that built by the Makefile.


7. In the dialog that opens after you drop the .h and .a files, select the option to copy items into the destination group’s folder.

Copying the files does require you to copy the library again if you update it, but if you do not tell it to copy the files, Xcode instead inserts dependencies on the full paths to the library and header. With full paths, if you move between machines or otherwise try to build in a new location, Xcode cannot locate the files at that full path, and your build will fail.

After you have copied the library and header file over, you should get a clean build from your C language application.


Did You Know?

Although it is quite easy to compile C and C++ libraries using Xcode, and quite easy to use them in C and C++ programs written in Xcode, it is a bit of a trick to call C++ library functions in application code written in Objective-C. The most straightforward solution is to write C language interface code to sit between the Objective-C application and the C++ library. Objective-C can speak to a C library easily enough, and the C++ code can be induced to generate a C-compatible calling interface by including extern C in front of function declarations. A more elegant but somewhat more involved solution is discussed at http://www.philjordan.eu/article/strategies-for-using-c++-in-objective-c-projects.


Summary

Libraries and frameworks are an excellent way to both compartmentalize your code and facilitate reusing it for other projects. In this hour, you learned the differences between libraries, which are single-file collections of compiled code, and frameworks, which are special bundles that can contain libraries and additional resources such as image or data files, localization strings, and documentation. You learned how to make the decision between building a library or a framework or just compiling your code straight into your application. You also learned how to build your reusable code into a library and into a framework and how to test the results without writing a large application to use the functions and how to package the library up to deploy on other systems or share with other users and programmers. You also learned how to construct and use Xcode library targets for building C and C++ libraries out of code that others provide for libraries in these languages.

Q&A

Q. What runs faster, bare code in an application, that code in a library, or that code in a framework?

A. Everything else being the same, code compiled directly in an application is at least fractionally faster than any of the other options.

Q. I’m looking at some open source software, and it builds and then uses a dynamic library. Should I use a dynamic Cocoa library or a framework?

A. Really, you can do either, although the framework option is cleaner if you are willing to do the little bit of extra work to set it up, beyond the “just drag in the files” procedure necessary for the plain dynamic library.

Q. Is passing around void pointers like you did in your linked list really kosher?

A. Well, it’s cheap. If you’re comfortable with C-style typecasting, it is a convenient way to abstract a library interface, such as for a linked list, so that it doesn’t matter what data type it is actually working with. If you are not comfortable with C-style typecasting, this way lie monsters.

Workshop

Quiz

1. Is there ever a good reason to use an embedded framework?

2. Where does Xcode store by default the components that it is building for your project?

3. Why does software that you’re trying to build, using your new framework complain that it cannot find the header files?

Answers

1. Yes, there are several, although most of them are fairly specific cases where, for example, you need to be able to rebuild part of your application without rebuilding it all (such as for a plug-in system). Where frameworks really shine, though, is for sharing your libraries with others by putting it in /Library/Frameworks/.

2. In a DerivedData directory buried in ~/Library/Developer/Xcode/.

3. Because you still need to add a Copy Headers build phase to your project and tell it which headers to add to the framework Headers directory.

Activities

1. Download the project for the Doubly Linked List Framework from http://teachyourselfxcode.com/ and build it.

2. Add the code necessary to implement the rest of the doubly linked list functionality. Add error checking on returned values.

3. Add testing code to the test suite to make sure that your new functionality produces the expected results.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.146.152