Developing Cocoa Frameworks Using Xcode 4′s Workspace Feature
Frameworks provide a convenient method for segregating reusable code from your application development. On the most basic level, a framework is just a collection of classes, functions, resources, etc. that you would like to share between multiple applications or develop separately from your application specific code. For example, if you wanted to build a custom implementation of certain GUI elements for the Mac OS or a library of generic classes, a framework would allow you to reuse this code between multiple applications without having to worry about updating the methods in each application every time you wanted to modify source code. You would only need to update the framework bundle in your application to take advantage of any new implimentations.
In this tutorial, I will walk through the steps for setting up a private framework in Xcode and show you how to use the new workspace feature in Xcode 4 to ease testing and development.
Development Environment
- Mac OS 10.7.2 Lion
- Xcode 4.2
Step 1: Create the project files and workspace
Open Xcode and create a new project (File > New > New Project). In the left sidebar select Framework & Library under Mac OS X and choose Cocoa Framework from the list of available templates, click next to proceed.
Give your framework a unique name, in this case I’ve named it MyPrivateFramework. Also be sure to give it a unique identifier name if you don’t have a company identifier filled in for you. Automatic reference counting (ARC) and unit tests are optional parameters, however if you plan on using this framework in an application that does not use ARC, then you must disable ARC and manage the memory manually as would in any non-ARC application. Save the project to disk and close the project, we are done with it for now.
Create a second Xcode project (File > New > New Project), but this time select Application under Mac OS X in the left sidebar and choose Cocoa Application from the list of available templates. We will use this application as a way of testing our private framework. Again give your application a name and select the appropriate options. Save the project to disk and close it.
Now that we have our two project files, one for our private framework and one for our sample application, we are going to combine them in a single project called a workspace that will allow us to work on both the projects simultaneously. The workspace will also allow us to tell Xcode to build the framework and link it against our application every time we build our sample application (more on this later).
From Xcode’s File menu, select New > New Workspace. Give the workspace a unique name, in this case I named it MyWorkspace, and save it to disk preferably in the same location as the other two project folders but this is not a requirement. You should be presented with a blank workspace.
The next step is to add our project files to the workspace, right click (control + click) in the source list on the left and select “Add Files to MyWorkspace…” from the drop down menu. Navigate to the directory where you stored your sample application project and open the project folder. In the project folder select the Xcode project file (.xcodeproj), be sure to uncheck copy items into destination group’s folder if it is selected, and then click add in the bottom right to add the project to the workspace. Repeat these steps to add the framework project to the workspace. Alternatively, you can also drag the Xcode project files to the source list to add the projects.
Once you have finished adding the projects you should be presented with an Xcode workspace that has the two projects listed in the left sidebar. Expand the projects and you will see that you have access to all the files in either project.
Step 2: Configure the build settings for the framework and application
Now that we have our workspace setup, we need to configure the build settings of the framework and application so that Xcode knows how to include the private framework with our sample application.
For this tutorial we will configure Xcode to embed the framework inside the sample application bundle. What this means is that instead of installing the framework in a central location on the user’s system like /Library/Frameworks or ~/Library/Frameworks, Xcode will make a copy of the framework and store it inside the application bundle. This gives us a number of advantages over the more traditional usage model of frameworks.
- Embeded frameworks do not require a package installer, the user can just use the traditional method of drag and drop to install the application without any additional steps. This also makes the application compliant with Mac App Store’s sandboxing and installation requirements.
- Since the framework is copied into our application bundle, we are guaranteed to be using the correct version of the framework that was supplied when the application was built. Furthermore, we don’t have to worry about other applications overwriting, deleting, or modifying the framework. If you think it is redundant to include a copy of a framework with your application, look up Window’s DLL hell where applications would often delete, overwrite, and/or modify shared libraries, causing other applications to break in the process.
My recommendation when using a 3rd party or private framework, embed it into your application bundle whenever possible and save yourself a lot of trouble. For more information on Framework installation or configuration refer to Apple’s Framework Programming Guide.
Modify the framework build settings
Since we are embedding our framework inside the application bundle, we need to modify the frameworks installation directory to reflect this fact. In the workspace select the framework project in the left sidebar, and navigate to the build settings for the framework target. You should see “Info”, “Build Phases”, and “Build Rules” listed along with “Build Settings” if you have the right object selected. Scroll down through the options and find the Installation Directory option listed under Deployment and change the path from the default value to @executable_path/../Frameworks and click done. This will tell Xcode that the framework will be embedded in an application.
Modify the application build settings
Now we need to configure our application build settings to tell Xcode that it needs to build and copy the framework project into the application bundle every time we want to build the application. To do this, we first need to expose the framework project to the application project, do this by clicking on the framework project and dragging it underneath the application project. Click finish when prompted, it should now appear as though a copy of the framework project exists under the application project within the workspace.
Next modify the application build settings so that Xcode will build the framework at the same time it builds the application. Click on the application bundle and navigate to the “Build Phases” of the application target. Expand the Target Dependencies option and click the add (“+”) button, you should see the framework listed among the options, select it and click add.
Next we need to link our application against the framework, expand the “Link Binary With Libraries” option and click the add (“+”) button. Select our private framework from the list, should be listed under Workspace in this case, and click add. From the list, drag our newly added framework over to the application project in the left sidebar and place it under the Frameworks group, uncheck copy items into destination group if selected and click finish. The framework should now appear with the other frameworks listed in the application project.
Also, if you expand the “Copy Bundle Resources” option in the build phases, you should notice that Xcode has added the framework to the list of items to copy into the Resource folder of your application bundle. Since we are only interested in developing the framework at this point, copying the framework into the resource folder is perfectably acceptable. However, when you are ready to release your application and framework, its more common to have frameworks reside in a seperate Frameworks folder inside your application bundle. Also you should notice that Xcode is pulling the framework from the Debug build at this point. When you are ready to Release your framework, you must also tell your application project to copy in the release version of your framework instead of the Debug version. I will go through the steps for doing this later in the tutorial.
Step 3: Adding classes and exposing headers in the framework
Now that we have our workspace setup and all the project files configured we can start adding classes to our framework and testing them with our sample application.
Let’s go ahead and add a sample class to our framework, for this tutorial I am going to add a subclass of NSView and modify it’s drawRect method to fill the background with red.
Here is the implimentation file for my custom subclass of NSView:
#import "drawRedSquare.h"
@implementation drawRedSquare
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[[NSColor redColor] setFill];
[NSBezierPath fillRect:self.bounds];
}
@end
The next step is to copy the NSView subclass header into the Public directory of the framework so that it is visible to our application. Click on the framework project and navigate to build phases, expand “Copy Headers”. The header file should be listed under “Project”, move the header file from “Project” to “Public”. Make sure to repeat this step for any classes that you want to make visible outside the framework.
Go ahead and hit the run button in workspace toolbar to make sure everything builds correctly. Afterwards, if you expand the framework listed in the source list under the sample application, you should see that it now lists a Header folder containing the header file for the class we just added to the framework.
For the final phase of this tutorial I add a custom view to the NIB file of my sample application and change the class to my framework’s custom NSView subclass.
Hitting the run button in the workspace should produce a window with a red background.
Step 4: Testing the Release version of your framework
When you are ready to build the Release version of your framework, you will need to modify the “Build Phases” of your sample application to pull in the correct version. After changing your framework build scheme from Debug to Release, navigate to the “Build Phases” of your sample application. Go ahead and remove the framework from the list under “Copy Bundle Resources” using the remove (“-”) button.
Next click on “Add Build Phase” in the lower right of the window and select “Add Copy Files”. A new build phase with the title “Copy Files” should now be available. Expand the new build phase and change the destination to Frameworks. Click the add (“+”) button and select the private framework as you have done in previous steps. Click add and the framework should now be listed under the “Copy Files” build phase using the Release build of the framework.
Hit Run in the workspace toolbar to confirm that everything is building correctly.











