Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-313
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 313
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 313] Mastering S...

WWDC11 • Session 313

Mastering Schemes in Xcode 4

Developer Tools • iOS, OS X • 56:38

Xcode 4 introduced schemes: a powerful new way to control how you build, debug, test, analyze, profile, and deploy your application. Discover how to use schemes to their fullest potential, learn in-depth details about the Xcode build system, and see how you can configure your project for maximum productivity.

Speakers: Rick Ballard, Chris Hanson

Unlisted on Apple Developer site

Downloads from Apple

HD Video (397.3 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

I'm Rick Ballard, and my associate Chris Hanson and I are engineers on the Xcode team. Today's presentation is going to give you the basics that you need to work in Xcode and go in-depth on some advanced ways to customize your workflow. Everything we talk about today is going to revolve around one central concept: schemes.

Whether your ambitions are world domination or just a polished product, you're going to need to use schemes to get there. In Xcode, Scheme is the object that you use to perform the five Scheme actions on your product: run, test, profile, analyze your source code, and archive for distribution.

When you choose one of these actions, Xcode will build the targets needed to produce your product, and then will perform the chosen action on your product. So, schemes are the tool that you use to configure and perform all your actions in Xcode, and that's why it's the central topic of today's presentation.

[Transcript missing]

Furthermore, a workspace allows implicit dependencies to be resolved between the targets in that workspace. What an implicit dependency is, is if you have one target which links against a product, and another target in a project in the same workspace produces that product, even if you haven't set up an explicit dependency from the first target to the second target, Xcode will notice that the first target does depend on the product of the second, and will create an implicit dependency for you. That means that whenever you build the first target, Xcode will automatically build the second target first to make sure that its product is available.

There's one more important thing to know about workspaces, and that's even if you don't create an explicit workspace document in Xcode, every time you open up a project and work with it, you still have a workspace. When you open up a standalone project, Xcode creates an implicit workspace for it behind the scenes and actually stashes a workspace file inside that project wrapper.

That means that when you work with a standalone project, you still have all the benefits of working with a workspace, and that includes a unique symbol index, a unique location for build products, and more. Today, whenever I talk about a workspace, you can assume that the same thing applies if you're working with a standalone project.

Let's talk a little bit about projects. A project contains references to your source files, targets which process those source files to produce your product, schemes which cause those targets to build and then perform actions on the products of those targets, and build configurations which collect and organize your build settings.

By default, projects come with debug and release build configurations, and all the build settings in the project and target are organized into those build configurations. If you need a new set of build settings for some specific purpose, you can always define a new build configuration. But for most of you, you'll be able to get away fine with just debug and release.

If you go to the project editor, which you can get at by selecting a project in the project navigator on the left, and then making sure that the project is selected in the middle, you can see the build configurations in your project and add new ones as needed. So let's talk about the targets in your project.

A target is fundamentally the instructions for building one product. It references some or all of the source files in your project, and it contains build phases, which are an ordered sequence of steps that the target takes in order to produce your product. There are a set of build rules that determine how the compile sources build phase processes the source files in the target. And you have a set of build settings which configure just about every aspect of the build process.

Finally, every target can depend on one or more other targets. And if it depends on another target, whenever the first target builds, the dependent target will build first. You can edit your target settings by going to the project editor and then selecting the target in the middle that you want to edit. The summary tab gives you some of the most frequently accessed settings that you want to change in your target.

If you select the Build Phases tab, you can see the ordered set of steps that the target is going to take to produce your product. So let's talk about a few of the tasks you might want to accomplish here. If you want to make your target depend on another target, you can do so in the Target Dependencies phase.

If you click the plus button here, you can add any dependent targets from among other targets in this target's project, and other targets in projects referenced by this target's project. If you don't see the target that you want to depend on here, make sure that this target's project references the project that contains the target you want to depend on.

If you want to set per-file compiler settings, you can do that in the compile sources build phase. This phase also shows you all the source files that your target is going to process in order to produce your product. If you want to make your product link against a library or framework, you do that in the link binaries with libraries phase.

When you click the plus button, you get to choose libraries to link from, from among three sources. First, you get all the libraries in the SDK that this target links against. Second, any libraries referenced by this target's project are available. And finally, any libraries in projects, or produced by targets in projects that this target's project references are also available.

If you're producing a framework or other library, you may have headers that you want to install into the product, and you can do that in the copy headers build phase. There are three build roles here, and by dragging your headers between these roles, you can configure what will happen with each of these headers. The public and private roles will export these headers to the public and private locations in your product, and the project role means that this header should not be exported in your product and is only there for the project when it's building.

If you have any resources, like artwork, you can put them in a copy bundle resources phase, and the target will copy them into the resources subdirectory of your product when it builds. If you need to copy any other files into your product as part of your build process, you can define as many copy files build phases as you want and configure them to put your resources wherever you want to put them.

Finally, if there's anything you want to do that isn't covered by these existing build phases, you can create a run script build phase and use that to do anything you can do with the script. All the target's environment or build settings are exported as environment variables to the script, which helps you configure powerful scripts that manipulate your products. And you can define as many of these script phases as you want and drag them around to reorder them.

The Build Rules tab shows you the set of built-in rules that tell Xcode how to compile the sources in your compile sources phase. If you have any special sort of source files that you need to compile in a special way, you can define a custom build rule here to do so.

Now let's talk about the build settings that control every aspect of your build process. In the Build Settings tab, you'll see all the build settings that are affecting the target. And you'll notice that for most of these build settings, there's just a single value listed. That means that all configurations in this project have the same value for this build setting.

Now some build settings list multiple values, one for each configuration. For example, your optimization level, well, you don't want to optimize when you're building for debug, but you do when you're building for release, so you have different values here. If you want to set a per configuration value instead of sharing a value across all configurations, you can hover over where the disclosure triangle is next to the build setting, and all your configurations become available.

Furthermore, if you hover over one of the buildings, you can see that the configuration level is set to the same value as the configuration level. If you want to set a per configuration value instead of sharing a value across all configurations, you can hover over where the disclosure triangle is next to the build setting, and all your configurations become available.

Furthermore, if you hover over one of those configurations, a plus button will show up, which you can click to add per SDK or per architecture build setting variants, so those values would be used specially only when building for, say, a specific SDK. There's another axis of configuration to your build settings that's important, and that's the build setting levels. If you select the levels bubble at the top, Xcode will show you a view that shows the hierarchy from which your build settings are being inherited.

On the left is the resolved column, and that shows you the final value for each build setting that will be used by this target when it builds. To the right of that are all the build setting values that you've explicitly set at the target level, and usually those will be the resolved values too. To the right of that are your project-level build settings. In the project editor, there's also a build settings tab, and any build settings you set there will be inherited by all targets in that same project, unless those targets override that build setting value.

Finally, on the right, Xcode shows you the default value for every build setting that will be used if neither the target nor the project overrides it. You'll also notice that there are some green bubbles in this view. Those green bubbles show you where each build setting's final value is being taken from, so you can quickly know where to go to edit it.

So that's targets. Let's talk a little bit more about what a scheme is. Schemes fundamentally have the instructions for building your targets and performing actions on them. So schemes contain actions for running your products, and that includes running them in the debugger, running your tests, profiling your product for performance, statically analyzing your source code, and archiving your products away, which allows you to distribute them later. For each of these actions, your scheme contains a specification of the targets that the scheme should build when performing that action.

You can get at your schemes in the upper left-hand corner menu, which is the Scheme pop-up. When you pop this up, you'll see a list of all the shown schemes in this workspace. And if you choose the Edit Scheme option from this pop-up, Xcode will bring down the Scheme Editing Sheet, which is where you go to configure all the aspects of your scheme.

In the upper left-hand corner, you can press the button to perform one of your selected scheme actions. And actually, handy tip: if you hold down the Option key and press this button, Xcode will bring down the scheme editing sheet for you, which is sometimes a little faster than choosing Edit Scheme from the menu. If you hold down on this button, you get four of the five scheme actions, so you can change that button to be the action that you're performing most often. All five scheme actions are also available in the Product menu.

Well, when you perform a scheme action, you also need to tell Xcode where to perform that action, and that's the run destination. Your run destination has three parts. It incorporates the platform and SDK that you want to build for, the device that you want to run on, and on the Mac only, what architecture you want to target. You can get at your run destinations on the right-hand side of the scheme pop-up. There you see all the run destinations that are available with the selected scheme.

What controls what run destinations we put in that pop-up? For the platform and SDK, you get to choose among those in platforms compatible with your target's base SDK build setting, supported platforms build setting, and deployment target build setting. For the device you want to run on, you can choose among all the plugged-in devices that are configured for development, all available simulators, and the local Mac. But you only get devices that are compatible with your selected SDK.

Finally, on the Mac, you can choose among architectures that are available in your target's architectures build setting, but again, only architectures that are compatible with the local Mac. For all these build settings, we actually look at every target that's set to build for the scheme and use the union of all run destinations that are available for the build settings for each target. So that's about it for the basic project concepts. I'm going to invite my colleague Chris up to go into depth with you on the five scheme actions. Thank you, Rick.

So as Rick described, schemes support five main actions. You can run your application to test it either without the debugger or under the debugger. You can run your unit tests. You can profile your application's performance. You can analyze its source code, and you can archive it for distribution.

But you'll notice that I didn't mention building. Why not? Well, a scheme builds targets, but building isn't an action in itself. Instead, it's a step that's typically performed before each action. You're always building with a specific purpose in mind. So the action to perform actually affects how you decide to build, how Xcode chooses which targets to build, and which configuration in which to build them.

Now, to preserve your muscle memory, we have kept a build command in the product menu, but that build command is really just an alias for "build for running." You configure building in the build pane of the scheme editor. And you can see here that in the bottom pane of the build pane, the bottom table of the build pane, I should say, You can set both the targets to build and what actions you wish to build them for. So, for example, if you have a unit test target, typically you won't want to build that for archiving because you're not going to distribute your unit tests on the Mac or iOS app store.

You can also configure implicit dependencies, which as Rick described, allows Xcode to figure out among all the projects in a workspace, all the targets in a workspace, which depend on each other without you explicitly telling it. And you can also tell Xcode to parallelize your build to maximize its use of your multi-core Mac Pro that I'm sure you all have. Now, in the build pane, you don't actually choose a configuration to build for. Instead, you choose which configuration to build for each action. Here we're looking at the test pane, and you can choose which configuration to build for the test action. Let's dive right into running.

When you run, you can choose which executable you want to run. Now, by default, Xcode will create your scheme actions for you, pre-configured for your application. But if you're building a different type of product, like a plug-in for another application, you'll want to actually choose which application to use when running. And similarly, you might actually want to debug somebody else's command line tool or something that you've built from the command line. And here this would allow you to create a scheme and choose that to debug.

You can, of course, choose which configuration you want to build for debugging. By default, Xcode will build for debug. And you can choose which debugger you actually want to use. You can use the traditional GDB debugger, you can use our new LLDB low-level debugger, or you can choose not to run under the debugger at all, which can be useful if you need to run your new plugin for an application that, say, you can't attach to with the debugger.

You also can choose which arguments to supply to your application or command line tool that you're running. Now, you'll typically want to do this to supply sample data, to set user defaults, and generally to supply additional information to your application while testing it. And to help prevent you from hard coding all sorts of things in your schemes, you can choose which target in your scheme you want to take build settings from.

Now you can actually refer to build settings in your arguments and environment variables that you supply when you run your application by using their all caps raw names. And you just reference them using a simple shell-like syntax with a dollar sign and the all caps raw name in curly braces or in parentheses as if you were in a make file.

Now to see what the actual all caps raw name is, you can control click on the build setting in the build setting editor and choose show raw names, or you can highlight it and just show the utility area and look at the quick look, quick look, I'm sorry, quick help inspector.

That quick help inspector in the upper right will show you some documentation about the build setting, as well as its all caps raw name that you can use both in shell script build phases, like Rick described, and in your arguments and environment variables. And here we've got one argument to our application that turns on some debug logging, and I've just decided to supply some sample data to this application too for it to run with. And that sample data is located in my build.

And I'm going to use the build products directory. So rather than hard code the path into the scheme for everybody who's working on this project to see, I'm using a build setting reference so that it follows wherever my build products happen to go. And Rick will describe a little bit more about that in a bit.

There are some options you can set when running your application. For Mac OS X, new and Lion, you can choose whether or not to run your application with its persistent state. So if you have the production version of your application on your system. And you're actually doing work with it.

Lion is saving persistent state about that application. Well, you're probably not going to want to use that when you're debugging the new version of the application. So you can enable this and Xcode will tell the application that while it's being debugged, it should just ignore its persistent state.

Now on iOS, new in iOS 5 with Xcode 4.2, we have a couple of additional options. You can choose which location or location track you want to use when you're testing your application. You can just do this using the locations pop-up, which is pre-populated with some common locations, and which will also show any GPX files that you have in your project. And you can also pull some sample data straight from an application on a device out using the organizer, put it in your project, and then use it when you're testing your application again, simply by choosing it from this pop-up.

And finally, we have some diagnostics that we have shortcuts for in the run pane, because we don't want you to have to remember whether it's NSZombieEnable or NSZombieEnabled, or what the command line argument for memory debugging is, or how to turn on and off DYLD framework and library loading information. So you can just turn all these things on and off with simple check boxes. Xcode will supply the right command line arguments and the right environment variables to your application when it runs it.

Now let's go into Xcode 4's new unit testing support. Xcode natively supports the OC unit, Objective-C unit testing framework. So this means your tests are written in Objective-C. That doesn't mean you can't test C++ code, too. You can get the best of both worlds just by writing your unit tests in Objective-C++. Use the Objective-C side to interface with the unit testing framework, and you can use the C++ side to test your C++ code.

And new in Xcode 4, your unit tests are actually run right under the debugger automatically. This means that if you enable breakpoints, your unit tests will actually hit breakpoints in the debugger while they're being run, so you can debug them much more easily. There's no setup to do. And finally, your test failures, in addition to showing up in a test log, will show up right as issues in the issue navigator.

Of course, there's a little bit of configuration you can do with the test action. In addition to choosing which configuration you want to build for your tests and which debugger you want to run your tests under, you can also choose which tests to run. This can be really useful if you only want to run one or two of your tests in your, I'm sure, enormous unit testing suites while you're getting them up and working.

And of course, you might want to supply some arguments, too. By default, Xcode will actually use the command line arguments that you've set for the run action, rather than making you specify them all over again for the test action. However, if you do want to supply different arguments for unit testing, you can do so simply by turning off that checkbox. So let me show you a demo of unit testing in Xcode 4.

So here I have a simple project. It's just a Zip browser application for Mac OS X. It's based on the Zip browser sample code. And I have some unit tests here in my new Zipkit library. So to run my unit tests, I'm just going to go to the product menu and choose Test.

Xcode 4 builds my Zipkit library and my Zip browser application, and also my Zip tests. And I can see that I have a test failure right here in the issues navigator. If I click on that test failure, I go right to the source code, and I see what test failed. So let me see exactly what was going on in this test that caused it to fail. I'm just going to set a breakpoint. and retest. No more setting up a custom executable.

Here I'm stopped in the debugger, and let me just take a look at what root entry child entries actually is. This is a little odd. I'm saying that it should be nil, but that it should have children. So if I look in self, root entry, child entries, oh, it's an array with zero objects. Maybe I actually meant that it should not be nil here, and this is just a typo. I'm going to stop my tests. Oops.

Say st assert not nil, get rid of my breakpoint here, rerun my tests, and all my tests succeeded. And now if I go and edit my scheme, I can see in my test scheme here, under my tests, I have two tests, and these were automatically discovered by Xcode's indexing. I didn't have to tell Xcode about my tests, it just knew about them. So now, let's talk a little more about profiling. And let's go back to slides.

Let's talk a little bit more about profiling your application for performance. Obviously, there's a little bit that you'll want to configure when you're profiling your application straight from Xcode. And that includes, of course, the build configuration that you want to profile. Now here, Xcode will default to profiling your release configuration, because typically, you don't want to check the performance of your debug code, because you've put in all sorts of logging and assertions, and you're just, you're really making sure that your code is correct when you're debugging, not that it's fast. So you really want to do your, you really want to do your profiling using the release configuration.

And as a shortcut, Xcode lets you select from among your instrument templates right in the profile action. This means that when you choose profile from the product menu in Xcode, Xcode will go straight to instruments and start running your application, so there's no break in your workflow. You can just decide to profile and go straight into profiling without having to configure instruments in between. And of course, you might want to supply some sample data or some environment variables when you are profiling as well. And again, by default, Xcode will just take those from the run action, but you can choose to override what Xcode has decided for you.

Now, we all use the LLVM static analyzer on our code to make sure that our memory management is correct and that we're not making any other mistakes with respect to Cocoa or core foundation idioms. And we provide you a little bit of control over the analyze action as well, because you'll sometimes want to analyze a build configuration other than debug.

For example, you might want to occasionally analyze your release build configuration just to make sure that you haven't done something silly like fix a memory leak as a side effect of implementing some logging, rather than actually fixing it in the version of your code that's going to be released to users.

And of course, in Xcode 4, just as in Xcode 3, when you actually encounter an analysis issue, You'll wind up with both an annotation in your source code and an entry in the issues navigator to make it easy to find what you need to fix. Now the final scheme action is archiving, and this is how you distribute your application, whether you're distributing it to end users or to testers.

And archiving is not just for iOS. It's how you distribute your application, whether it's for Mac OS X or iOS, whether it's for the Mac App Store, or whether it's something that you're going to make available on your website. It's how you share with testers, and it's also how you can verify your application prior to submission to the iOS or Mac App Store, and how you actually submit your application.

So an archive itself is an XeArchive bundle on disk that contains an install-style build of your application. What this means is that it's a fully stripped version of your application with no debugging symbols or anything else. Instead, those symbols are off to the side in another DSIM file. So they're still around, they're still in that archive, and they can still be used to match your application as it's deployed in the field with your source code that generated that application.

So when you get crash reports, you can actually see what line of code Each entry in your call stack actually corresponds to, instead of trying to puzzle it out from memory addresses and things like that. Your archive is also associated with the verification status and submission status of your application, and you can supply your own comments too, so you know what you were thinking when you made that archive.

So to configure the archive action, of course, there's a pane in the scheme editor. And by default, Xcode is set up to archive your release configuration. We don't really do a release versus a distribution configuration anymore because the choices that were different between release and distribution, those can actually all be handled in the archives organizer now. And we have a checkbox that will automatically take you straight to the new archive that was produced in the Archives Organizer when you perform an archive.

To manage your archives, you use the Archives Organizer, which, as I said, was brought up by this checkbox. And here you can see I have a few different versions of my Zip browser application that I've archived. But why did I do that? Well, just like with your code, use comments. I've put in some comments to say that I had, okay, I have my first version of my application, it's the first draft, I've got a couple of intermediate versions, and now I have the version for the conference.

And then if I were going to submit this to the App Store or send it out for testing, I would use the buttons at the right to do that. I would validate for submission, I would share my application, and I would submit it to the App Store. Now, when you go to share your application, you have a choice of how you want to share it, as long as it's an application archive.

For iOS, you have the choice of making an iOS IPA archive, which you can use for ad hoc or enterprise distribution, and you can choose which signing certificate you want to use to actually generate that IPA. And you can sort of do the same for the Mac OS X side.

You can choose to make a macOS-- a Mac App Store distribution package, or you can choose to just extract the raw application from the archive and pass that around, or you can choose to pass around the archive itself. And again, you have a choice of which signing certificate to use when you produce that archive.

Now, if you're going to produce an application, That's going to have to come from an application archive. An application archive is an archive that only contains a single application. It doesn't contain any extraneous libraries, frameworks, static libraries, or anything else. And this is really important because an application archive is the only kind of archive that can be submitted to the Mac or iOS app store. You can't submit an archive that has anything else in it.

And to do that, if you are using any libraries or frameworks, whether you're doing so for iOS or the Mac, you'll want to turn on the skip install build setting for those library and framework targets. Instead, your application should just embed the library or framework in itself when it builds. Now, that's really easy for static libraries because that happens automatically. There's nothing for you to configure. Simply by using a static library, it's incorporated into your application.

But for frameworks and dynamic libraries on the Mac side, you'll need to use a copy files build phase to put them in the right place in your application bundle. Now, I'll bring back Rick, and he'll tell you a little bit more about how Xcode decides what build locations to use.

Thanks, Chris. So let's go over how to find your build products and how to configure where they go. By default, every workspace, as I told you before, gets its own location for build products, and that's in its derived data directory. The derived data directory contains all the derived artifacts from your workspace. So that's the symbol index, your saved logs, and your build products.

This means, since every workspace has its own derived data directory, that by default, your build products from different workspaces don't get mixed together. And that's really helpful because it keeps each workspace from clobbering each other's build products. And in fact, if you open a project in the context of one workspace versus in another, its build products will go in different places. So again, you maintain the build products that you're using in one specific workspace without it getting clobbered by another one.

Now, we distinguish workspaces by path when deciding which derived data directory they should have. That means if you say, "Check out two copies of the same workspace from different revisions in your source control," since each of those copies has to live at a slightly different path, each of them is going to get its own derived data directory.

So those different versions of your project aren't going to stomp on each other. If you look in your derived data location, you'll see a set of folders with funny names in them. Those are the derived data directories that you have. Each derived data directory starts with the name of the workspace that it belongs to, and is then followed by a hash of the path that that workspace lives at. So if you move the workspace, it'll get a new derived data directory.

If you want to, if these are building up, you can delete these folders. But if you do, and then open up one of the workspaces that corresponded to a deleted derived data directory, it'll have to re-index all its symbols again. It won't have any built products and so forth.

So I'm going to give you a quick demo now that shows you how easy it is to find your build products, even though they're off in this derived data location now. So there are three quick ways to do this. The first way is if you go to the project navigator and disclose one of the products groups, and you've built your product, you'll see references to your built products. And you can just right-click on those, choose Show in Finder, and your built product is going to come right up in Finder.

The second way is to go to the File menu and choose the Workspace Settings option. Or, if you're working with a standalone project, this option is called Project Settings. This brings down the Workspace Settings sheet, and this gives you control over where the derived data directory for this workspace lives on a per workspace basis, if you want to change that, and where its build products go. In addition, when it lists the derived data directory, there's a little arrow, and if you just press this arrow button, your derived data location will come up in Finder.

The third way to get at your derived data directory is to go to the Window menu, choose the Organizer, Bring up the Projects Organizer, which will list all open projects and workspaces, and all projects and workspaces that Xcode knows about by seeing their derived data directory in the derived data location. And here it lists this project's derived data, or this workspace's derived data folder, and again there's a little arrow. I can press it, and there's my derived data directory for this workspace. So that's how easy this is. Let's go back to slides.

If you open Xcode's preferences and go to the Locations preference pane, you get some control over where your derived data goes. There's a derived data location you can set, in addition to being able to set where your snapshots go and your archives go. And there's also an advanced button here, which gives you control over exactly where your build products go, if maybe you don't want them going in the derived data directory.

You'll notice this pref pane looks a little different, and the workspace settings sheet I'm about to show you a screenshot of looks a little different than what you have in the 4.1 and 4.2 seeds. That's because this is the new look for the Locations pref pane and the workspace settings sheet, and it's coming soon.

In the workspace settings sheet, as I said, you can change your derived data directory on a per-workspace basis. This is useful if, say, you're a contractor and you're working with some source code that has some particular security requirements. You need all artifacts from this project to go in a particular secure location.

Well, you can set that workspace's derived data directory to be in that secure location, and everything will be taken care of. The Advanced button here-- oh, actually, there's also a pop-up here, which allows you to choose to make your derived data location project relative if you want. And that's useful if you like having your build products and other derived data in next to your source code.

The Advanced button here lets you configure exactly where your build products go. And there are a few different scenarios I'm going to step through that should dictate when you'd want to use this.

[Transcript missing]

You can also do this in Xcode's location preferences if you want, if you want every project you ever work with, by default, to place its build products in the same build products directory.

The third scenario is the few of you who may have a complex external build system that requires your build products to go in very specific locations on disk. Those locations may be controlled by the build settings in your target. There's a build products path and a build intermediate files path that lets you set, on a per target basis, exactly where your build products go. And if you need to use these settings, you can change your build location to locations specified by targets.

That makes Xcode respect these build settings. And that means that your products aren't going to go in your derived data directory at all. They're going to go in some location specified on a per target basis. Most of you don't need this, but for those of you who do, it's important to know where to find this.

There's one more thing I'm going to tell you about before we move past build locations, and that's one reason many people go and find their build products in Finder today is because they like to delete their build products folder outright in Finder instead of using the clean command, both because the clean command can take a little longer than just deleting the folder and because you want to make absolutely sure that you've deleted all your build products and haven't left any cruft behind.

Well, we've made this a lot easier in Xcode 4. In Xcode 4, if you have the products menu up and you hold the option key, the clean command turns into a clean build folder command, and if you select this, Xcode will just instantly delete your build folder for you.

So that's about all there is to configuring your build locations. Let's dive now into how to manage your schemes effectively and share them with your coworkers. First thing you need to know about schemes is when they're created. Well, you can manually create them yourself whenever you want, but Xcode will actually create them for you automatically under a couple of situations. First of all, whenever you create a new target or a new project that contains targets, Xcode will create a scheme for every new target. And that scheme will be per user owned by the user that created the targets.

Second of all, the first time you open a project or workspace, or if you open a project in workspace or workspace and new targets have been added by someone else since you last opened it, Xcode will look at each of those new targets and create a scheme for every one of them. And again, that scheme will be per user owned by you.

Now, I said that you get a scheme for every target, every new target, but that's not quite right. Xcode will create a new scheme for most types of targets, like framework targets, library targets, application targets. But if you have any unit test targets, and if those unit tests can identifiably test some other target's product, like say you have a test bundle that tests your application, instead of creating a separate scheme for your unit test target, Xcode will add that unit test target to the test action of the scheme that contains the target that the tests test. So, for example, to the test action of the scheme that contains your application target.

Now, if you create a new unit test target, it won't be configured yet to test some other target's product, so you will get a new scheme just for that test target. That's probably not what you want. You probably want to delete that scheme for the test target, and instead add the test target to the test action of another scheme that you want to run the tests with.

If you have a lot of targets in your workspace, you may see that the scheme pop-up is pretty full, lots of stuff in there. You don't necessarily have to keep them all. For example, if you have an application target that links against a framework target, Xcode will have given you a scheme for both the framework and the application.

But maybe you never need to build the framework just by itself. In that case, you can delete the scheme for the framework target and just keep the one for the application target. Whenever you build the application scheme, it'll automatically build the framework too because of that target dependency.

You can manage your schemes by going to the Scheme pop-up and choosing the Manage Schemes option from the menu. This brings down the Manage Schemes sheet, which shows you all the schemes in the workspace and lets you create new ones, delete them, and configure them. First of all, you'll notice that there's an "Auto Create Schemes" checkbox in the upper left. Most of you want to leave this on, but if you turn it off, Xcode will never automatically create schemes for this workspace. This setting is actually shared among all users of the workspace.

This is useful if you've got a large, complicated workspace, and you've specifically authored some complicated schemes that you want to share with all your teammates. You don't want new teammates opening the workspace and getting all these auto-created schemes, one for each target. Instead, you want your teammates to use the shared schemes that you've carefully authored. So if you turn this off, nobody will get the auto-created schemes, and it'll be easy for them to just work with the shared schemes that you've created, or create new schemes themselves when they actually need them.

The "Autocreate Schemes Now" button does let you trigger autocreation if you have this off and want to autocreate schemes after all, but it also serves another important purpose. If Xcode autocreates a scheme for you and you delete it, Xcode will remember that you've deleted that autocreated scheme and won't recreate it for you. And that prevents you from having to play whack-a-mole with autocreated schemes every time you open up a workspace.

Now, if you've deleted some autocreated schemes, but you decide, "Hey, actually, I want to get those autocreated schemes back," if you press this button, Xcode will actually autocreate schemes for every target in the workspace that doesn't already have a scheme, even including targets which it had autocreated schemes in the past for that you deleted. It can be kind of useful.

Now, you may find when working with shared schemes that some of your teammates have set up some schemes that you don't really care about. They're just for their use or shared among them, and you don't want them cluttering up your scheme popup. If you uncheck the show checkbox on the left, you can hide those schemes for you so they don't show up in the scheme popup, but that won't affect anyone else. That's a per user setting. Since you can't delete the shared schemes, or it would delete them for everyone since they're shared, You just hide them for you.

If you want to share a scheme, you just check the Shared checkbox on the right. And that will move the scheme file to the shared data location so that everybody who's using your project in Workspace can use that scheme together. Now, one thing you may find often when working with shared schemes is you want to add some argument temporarily for debugging purposes. But if you edit that shared scheme, it'll show up for everybody because that scheme is shared. And you don't want to accidentally check that in and share your temporary argument with everyone.

The workflow we recommend in that case is to select the scheme here, choose Duplicate from the gear menu, and create your own personal one-off copy of the scheme. You can tweak that to your heart's content and then delete it when you're done with it. And next time you need to do the same thing, just duplicate a new copy of the scheme and tweak it as needed.

You'll notice that there's a containers pop-up here, and that controls exactly where your scheme is stored. Every scheme is stored inside a project or workspace bundle, and you can choose which project or workspace it's stored in by changing that in the container pop-up. If you've got a scheme that you want all users of your project to see, you should store it in that project. But if you've got a scheme that you only want to use when you're working in a particular workspace, you can just store it in that workspace.

Let's talk a little bit more about exactly where your schemes go. Inside your project or workspace bundle, Xcode puts an XC user data folder, which contains all your per user data, and an XC shared data folder, which contains your shared data. Inside the XC shared data folder is an XC schemes folder, and inside that is all of your shared schemes that are in this project or workspace.

In your XE User Data folder, you'll see that there's a separate folder for every user of this project or workspace, named after that user's username. Inside your Username folder, there's an XE Schemes folder again, and inside that, there's both all your per-user schemes and a Scheme Management Property List.

The Scheme Management Property List stores information for you about which schemes you've chosen to hide, what order you want the schemes to show up in, and you can change that by dragging them around in the Schemes Management Per User, and what schemes Xcode has auto-created for you in the past so it knows not to auto-create them for you again after you delete them.

Now, when working with schemes, you probably want to check them in. When you bring up the commit sheet, you'll see this hierarchy I just showed you represented on the left. Shared schemes, you usually want to check in to share them with your coworkers. You may want to check in your personal schemes and your scheme management property list, too, just so that you don't lose that data.

By default, unlike source files, when you create a scheme, it's not added to your source control. So if you want to add a new scheme, you just need to check the checkbox on the left, and Xcode will commit it to your source control the next time you commit, or when you close the sheet is when you commit. So that's about all there is to managing your schemes effectively. To close out today's presentation, I'd like to invite Chris back up to show you what you can do with the power of custom scheme actions.

Thanks, Rick. So we've seen what you can do with schemes and scheme actions so far, but what if you want to do something before or after one of those actions? Well, we have the ability in Xcode 4 to let you create custom pre- and post-actions for all of the scheme actions, as well as for building.

Now, this is really simple to do. All you need to do is open the scheme editor and then click that disclosure triangle next to the action you want to add a pre- or post-action to. And you'll see that there's a section for pre-actions and a section for post-actions, and if you select one of them, You'll get a nice blank canvas.

Now, we allow you to create run script scheme actions, which are very similar to run script build phases as Rick already described. And these actions not only can run arbitrary shell scripts, or any kind of script really, because you can specify which scripting engine to use, but they can also be supplied with information from a target that's in the scheme, just like you have for arguments and environment variables. So it'll be supplied with an environment containing all of the build settings for whatever target you select. It'll also be passed some other information about the action and about the workspace using the environment variables as well.

Now, if you want to send some email after a build is done, say because you've archived something, you've had a script uploaded to a server, and now you want to tell your team about it, we also have a post action or a pre-action, if you really want to send email before an archive, that lets you specify the name and the subject and the content of an email to send, and it'll just use mail.app to send that email.

Now, why would you use a custom scheme action instead of a run script build phase like Rick described earlier? Well, the key thing to remember is that build phases really help produce a product from a target. So if something is inherent to your product, don't do it in a scheme action, do it in a run script build phase. Conversely, a custom scheme action really helps you prepare for or follow up on the rest of the action. So for example, producing an archive and then having it uploaded to a server automatically.

We've got a handy table here to just give you some examples. So if you're generating art assets for your game, you'll want to do that in a run script build phase because chances are those art assets are really inherent to your game. You don't want them to be a side effect of whatever action the user chose while using the IDE.

On the other hand, if you need to prepare some test data for your unit tests, that's probably something you want to do in a pre-action script. And similarly, as I've been saying, uploading an archive to a server is probably something you want to do in a post-action script. Now let's see these in action.

Let's say I'm working on my Zip browser application, and I want to distribute it to testers. Of course, the way I'm going to prepare it for distribution is to use the archive action, but I don't want to constantly use the IDE, produce an archive, extract an application from it, upload that to a server manually. So instead, I'm going to go to Edit Scheme and disclose my archive action, and I'm just going to delete something quickly here.

And I will add a new run script action because I'd like to automate this process. Now because I'm actually going to be archiving the Zip browser application, I'm going to choose to provide build settings as environment variables from the Zip browser application target. And rather than type a bunch of shell script at you, I have a text snippet here with some script that I'm just going to paste in. And let me paste that in.

So you can see here on the very first line, what I'm doing is invoking a command on an environment variable called workspace_path. This is passed to your run_script scheme actions, and it contains the path to the workspace file itself. So what I'm doing is I'm getting the directory that contains the workspace file, and then I'm running some other shell scripts from within that directory.

And the reason I'm doing this is so I don't have to hard code the directory that those scripts are in on my system. I don't need to install them in user_local_bin or any other hard-coded location. They can just live with my workspace. And my first script just generates a disk image. And one of the arguments I'm passing to it is the contents of my archive. Specifically, I'm using the archive product's path environment variable, which is also supplied to the run script action.

And that points into the content of the products directory of the archive, which is what contains an applications directory, which will contain my Zip browser app. And after I've generated a disk image, I have a script that simulates uploading it to a server. And rather than actually uploading it to a server, it's just going to copy it to a directory and then open that directory in the finder.

So I'm going to click OK to add this script. But instead of invoking archive from the IDE, I think I really want to make sure this is something that can be automated. If I'm producing builds nightly or continuously on a server, I'm not going to want to just send things to the tester from the IDE. I'm going to want that to do it automatically.

So, I'm going to switch to the terminal. I'm just going to push D into my directory here with my source code. And I can see that I have my workspace in here. And now I'm just going to use the Xcode build command. And this command now has workspace and scheme arguments.

So I'm going to specify a zip browser, .xc workspace for the workspace argument. I'm going to specify scheme zip browser for the scheme argument to tell it to build that scheme in that workspace and build all of the targets, no matter what projects they're in, for that scheme. And I'm going to, instead of just telling Xcode build to build, I'm going to tell it to do the new command archive. And that's going to generate my archive and then perform my post archive actions. And we can see Xcode build is busy here.

And now it's paused a little bit, and that means it's generating my disk image. It's created my disk image and opened the location containing it in the finder, just as my second script does. Now if I double-click my Zip Browser disk image, and it mounts, I can see that it has my applications directory in it, and that has my Zip Browser application ready for my testers. Rick Ballard, Chris Hanson So now let's return to slides.

Rick Ballard, Chris Hanson And if you'd like more information about Xcode 4, the person to get in touch with is our developer evangelist, our developer tools evangelist, Mike Jurowicz. We also have a ton of great documentation in the Xcode 4 User Guide at developer.apple.com and on your systems when you install the latest documentation sets.

And if you have questions, in addition to the labs, we have the Apple Developer Forums. They're a great resource where developers can help developers, and we're also on there. We have a bunch of related sessions this week. Some have already happened, and some are still coming up. So, go forth, and I hope your schemes come to fruition.