— boreal-kiss.net

Archive
Tag "xcode"

Minimal Template for iOS 5

Minimal Template for iOS 5 part2

My project template for iOS working on Xcode 4 has been updated. I use a storyboard file (iOS 5 and later) rather than xib. Since all the source code including the content of the storyboard is not hard-coded in the template, You can easily modify their contents without having a catastrophe (adding/removing files needs some efforts though). If you are not familiar with storybords, the following guide will be helpful:

You can find the complete template at my repository:

Read More

[Note on 09.04.2011: This article will not be helpful unless you really need universal static libraries for distribution purposes etc. Instead, using workspace is a better way for daily development.]

Introduction

Creating static libraries universal for iPhone device and simulator is a little bit tricky. On Xcode 3.x, the major way takes something like the following steps:

  • Create a build for the device (the armv6 and armv7 architecture).
  • Create a build for the simulator (the i386 architecture).
  • Merge the above builds to create a universal build using lipo.

Since Xcode, 4 a new command called archiving (Product > Archive) is introduced as a way to distribute applications and/or static libraries. At glance this is suitable to creating a universal libraries but is not. One can not select this option for the simulator environment (you will notice it is always grayed out). As such we still have to rely on the traditional way to create universal libraries (1).

In this article I will show you how to create such a fat static library on Xcode 4. Because the place for product builds of each project are completely changed from those of Xcode 3.x, we have to make a slight effort tailoring it to the Xcode 4.

How to do

In the following example I will use my project called BKMovableVC. On your workspace you can use whatever name you want, of course.

Step 1

Create a new Cocoa Touch Static Library target (File > New > New Target > Framework & Library) for the simulator environment. Naming is arbitrary as long as you can recognize (I named here BKMovableVC-iphonesimulator). Add related source files to the Compile Source pane and headers to Copy Header pane. For headers you can choose three possible places to put in, Public , Private, and Project (default is Project). For example if you choose Public, all headers will be automatically copied to the build directory, which is easy for me to continue following works.

[Note on 04.05.2011: There is a bug on Xcode 4; when all panes (Public, Private, and Project) in the Copy Header pane are closed or never opened before, pushing the add button causes a crash. Open one of them before adding files.]

From the Edit Scheme pane (Product > Edit Scheme), change its build configuration to Release. This enables you to create a Release build product once the build operation is done. This build operation supposes to be done on the simulator architecture (i386).

Step 2

Create a new static library target for the iPhone device environment. Naming is arbitrary but must be different from that of the simulator (I named here BKMovableVC-iphoneos). Add related source files and headers and change its build configuration to Release. Every step is just the same as that of the simulator except for the build architecture; this build operation supposes to be done on the device architecture (armv6 and armv7).

Now we have two targets, one for the device and the other for the simulator. When you build a product, the product will be placed under the following directory:

~/Library/Developer/Xcode/DerivedData/

This place is shared by build products of all projects created on Xcode 4, which is quite different from the legacy place found on Xcode 3.x (each project has its own build directory). For example, if the name of the project is BKMovableVC, the Release build product for the simulator will be placed at

~/Library/Developer/Xcode/DerivedData/BKMovableVC-xxxxxxx/
	Build/Products/Release-iphonesimulator/
	libBKMovableVC-iphonesimulator.a

and that for the device will be found at

~/Library/Developer/Xcode/DerivedData/BKMovableVC-xxxxxxx/
	Build/Products/Release-iphoneos/
	libBKMovableVC-iphoneos.a

where BKMovableVC-xxxxxxx is a unique directory name automatically assigned by Xcode 4.

Step 3

Let’s merge them using the lipo command. Create a new Aggregate target (File > New > New Target > Other). I named it here BKMovableVC-ios4.3-0.9. On the Build Pheses pane select Add Run Script from the Add Build Phase button on the bottom-left corner.

Now we are about to run some scripts on the Run Script pane but here is a problem. How do we direct lipo to work with builds that are placed under the directory whose name is automatically assigned by Xcode 4 (e.g., BKMovableVC-xxxxxxx for the above case)? Fortunately it is easily solved by the Xcode 4 environment variable called ${BUILT_PRODUCTS_DIR}. This variable represents the path to the directory for a current build product. For example, when we create a Release build product for the simulator explained above, ${BUILT_PRODUCTS_DIR} corresponds to the following path:

~/Library/Developer/Xcode/DerivedData/BKMovableVC-xxxxxxx/
	Build/Products/Release-iphonesimulator/

Let’s continue. Write the following script on the Run Script pane. This lets lipo create a merged build product called libBKMovableVC-ios4.3-0.9.a (you can give it whatever name you want). If there is already the product with the same name lipo deletes it before the merge operation as shown in the first line.

rm -rf ${BUILT_PRODUCTS_DIR}/libBKMovableVC-ios4.3-0.9.a
 
lipo -create "${BUILT_PRODUCTS_DIR}/../${BUILD_STYLE}-iphonesimulator/libBKMovableVC-iphonesimulator.a" \
"${BUILT_PRODUCTS_DIR}/libBKMovableVC-iphoneos.a" -output \
"${BUILT_PRODUCTS_DIR}/libBKMovableVC-ios4.3-0.9.a"

Here is one trick. In this script the path representation to previously created build products such as libBKMovableVC-iphonesimulator.a looks odd because of “/../”. This is because the environment variable ${BUILT_PRODUCTS_DIR} depends on a current build phase (iPhone device, simulator, Debug, Release). For example, if this script runs for the Release build of iPhone device, the variable ${BUILT_PRODUCTS_DIR} will represent

~/Library/Developer/Xcode/DerivedData/BKMovableVC-xxxxxxx/
	Build/Products/Release-iphoneos/

However the build product for the simulator, libBKMovableVC-iphonesimulator.a, is not placed under this path, because it was created through a different build phase.

Implementation

Let’s do all the flows in order. Do the following:

  1. Build the target BKMovableVC-iphonesimulator on the simulator. The build phase must be Release.
  2. Build the target BKMovableVC-iphoneos on the device. The build phase must be Release.
  3. Build the target BKMovableVC-ios4.3-0.9. on the device. The build phase must be Release.

Then you will have a static library universal for the device and simulator in the following directory:

~/Library/Developer/Xcode/DerivedData/BKMovableVC-xxxxxxx/
	Build/Products/Release-iphoneos/
	BKMovableVC-ios4.3-0.9.a

You will also have header files depending upon your configuration (see the text above).

Footnotes

  1. Of course there could be a way to create a universal library on one scheme by tuning build settings but I have not found it by myself nor on the web. []
Read More

Introduction

Many people have their own project- and/or file-templates for practical or aesthetic reasons. For example I don’t like the naming convention provided by Apple such as XXXX-Info.plist, XXXX-Prefix.pch, and XXXXAppDelegate for the project XXXX. On Xcode 3.x. it was relatively easy to modify them. Since Xcode 4, however, Apple introduced a new template format that is no longer compatible with those of Xcode. 3.x. This has often become topics among Apple’s developer forums, since there is no official information provided. You can see how it changes from the Xcode 4 built-in templates. They are under

/Developer/Library/Xcode/Templates/

for Mac OS X stuffs and

/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/

for iOS. If you add your own templates, the place you should use is under the following path:

~/Library/Developer/Xcode/Templates/

The problem is that it is quite hard to create a custom template. For example, to copy and paste the built-in template to your place will not show up the template on Xcode 4 until you manually change its identifier in TemplateInfo.plist.

TemplateInfo.plist

TemplateInfo.plist is basically a setup file for a Xcode 4 project. When creating a project, Xcode 4 first reads this file to prepare all environment for you to get started. Each TemplateInfo.plist has own identifier for Xcode 4 to distinguish from others (and that’s why copy-and-pasting built-in template described above does not work as a user template). If you need your own templates, you should give them your own identifiers. For example, the Xcode 4 built-in template for window based iPhone application has the following identifier:

com.apple.dt.unit.windowBasedApplication

TemplateInfo.plist has something inheritance nature like classes of programming languages (and the identifier corresponds to the name of class). Xcode 4 reads a given TemplateInfo.plist and aggregates data from its ancestral files. For example, the following figure shows pedigree charts for the built-in window based iPhone application template.

com.apple.Templates

You can see that the TemplateInfo.plist for the window based iPhone application template is the sixth generation from the top-most base file (com.apple.dt.unit.base). This demonstrates that when you want to customize a given TemplateInfo.plist and the place you want to change within comes from the ancestral files, you have to manipulate multiple files, i.e., it could be error prone. Since TemplateInfo.plist is just an XML file, there is no compile errors. Moreover the inheritance nature of XML files has no readability at all. In fact it seems Apple creates them not by coding but by automatic generation tools.

A minimal project template

This was originally just for me but since it founds to be useful I will share this with someone who wants to have own templates on Xcode 4. This contains several templates within but only shows up one window based application template on Xcode 4 (the identifier is com.borealkiss.windowBasedApplication), because the others are not a concrete template (there are abstract templates not to be actually implemented). The following figure shows the contents (gray and orange ones are included):

om.borealkiss.Templates

This template enables you to manipulate in the old way as of Xcode 3.x, i.e., editing actual files and adding onto templates. Basically you only have to manipulate the TemplateInfo.plist of com.borealkiss.windowBasedApplication. You can add whatever files you want as long as you do the following edits. For example, if you want add a given file called SomeClass.m, you add the following two parts into the TemplateInfo.plist of com.borealkiss.windowBasedApplication:

These are the definition part of the file:

<key>Definitions</key>
<dict>
	<key>SomeClass.m</key>
	<dict>
		<key>Path</key>
		<string>SomeClass.m</string>
	</dict>
</dict>

and its actual implementation:

<key>Nodes</key>
<array>
	<string>SomeClass.m</string>
</array>

If you want to add the file but not for the target of Copy Bundle Resources (like Info.plist, Prefix.pch, and header files), change the definition as follows:

<key>Definitions</key>
<dict>
	<key>SomeClass.m</key>
	<dict>
		<key>Path</key>
		<string>SomeClass.m</string>
		<key>TargetIndices</key>
		<array/>
	</dict>
</dict>

You can add it inside a given folder. For example if you want to add the file inside a directory called MyClasses, change the definition as follows (note that the key name should be consistent with the actual file path, otherwise the file location in the project will be different from that seen in the Finder’s view):

<key>Definitions</key>
<dict>
	<key>MyClasses/SomeClass.m</key>
	<dict>
		<key>Group</key>
		<string>MyClasses</string>
		<key>Path</key>
		<string>MyClasses/SomeClass.m</string>
	</dict>
</dict>
<key>Nodes</key>
<array>
	<string>MyClasses/SomeClass.m</string>
</array>

[Update on 06.04.2011]

Some reader gave me a tip how to add files in a subgroup (i.e., the group inside a group). As an example consider the following situation; you are adding the SomeClass.m file that is in the location below and wanting to add it in the same directory.

Classes/SomeClass/SomeClass.m

In this case you can do this by changing a definition part:

<key>Definitions</key>
<dict>
	<key>Classes/SomeClass/SomeClass.m</key>
	<dict>
		<key>Group</key>
		<array>
			<string>Classes</string>
			<string>SomeClass</string>
		</array>
		<key>Path</key>
		<string>Classes/SomeClass/SomeClass.m</string>
	</dict>
</dict>

and its nodes part:

<key>Nodes</key>
<array>
	<string>Classes/SomeClass/SomeClass.m</string>
</array>

I also added these examples on my templates (link listed at the bottom).

Caution before editing

Keep in mind that TemplateInfo.plist is a setup file for Xcode 4 and any invalid manipulation would cause unexpected actions. For example, the following figure shows a normal behaviour of Xcode 4 during a new project creation, showing a product name and company identifier input (other options such as unit testing are disabled). And pushing the next button asks you which directory to create the project (as expected).

Normal behaviour of Xcode 4

The following wizard pane is abnormal one after some ill manipulation. No product name input is found. Fortunately you cannot go further by pushing the next button.

Abnormal behaviour of Xcode 4

However the worst case happens when you could go further. Even if you meet the situation, do NOT push the next button; Xcode 4 creates a project inside the directory you intend to place the project. For example the directory you are placing your project folder is Desktop, Desktop will become the project folder and other irrelevant files will be gone. I had two times desktop-sweeping during the try-and-error manipulation. Be careful.

Downloads

License

This template is provided under the terms of the MIT license for the reason above, i.e., feel free to use it but at your own risk.

Read More