<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cocoa Is My Girlfriend &#187; microISV</title>
	<atom:link href="http://www.cimgf.com/category/microisv/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cimgf.com</link>
	<description>Taglines are for Windows programmers</description>
	<lastBuildDate>Thu, 15 Jul 2010 21:20:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Why version control is important for solo developers</title>
		<link>http://www.cimgf.com/2009/11/07/why-version-control-is-important-for-solo-developers/</link>
		<comments>http://www.cimgf.com/2009/11/07/why-version-control-is-important-for-solo-developers/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 15:22:28 +0000</pubDate>
		<dc:creator>Fraser Hess</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Rants]]></category>
		<category><![CDATA[Version Control]]></category>
		<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=786</guid>
		<description><![CDATA[It&#8217;s common practice for any software project with multiple coders to use some version control mechanism. CVS or Subversion used to be popular. These days distributed systems like git and Mercurial are the quickly replacing the old standards. But what about the cases when you&#8217;re the only coder? Let me tell you. Whatever the initial [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s common practice for any software project with multiple coders to use some version control mechanism. CVS or Subversion used to be popular. These days distributed systems like git and Mercurial are the quickly replacing the old standards. But what about the cases when you&#8217;re the only coder?
<span id="more-786"></span>
Let me tell you.  Whatever the initial setup cost, coding is much easier with version control than without it.</p>

<p>Firstly, if you think that you only work with yourself and you can handle yourself, have a quick look at the <strong>I Am A Moron</strong> section of <a href="http://www.cimgf.com/2009/03/26/dont-blindly-trust-debb/">this post</a> or <a href="http://twitter.com/kevinhoctor/status/5376014212">this recent tweet</a> by Kevin Hoctor.</p>

<p>Now a few years ago, I started work on a helpdesk ticketing system called tina. In the early days of tina development, I&#8217;d didn&#8217;t use any version control. I was frequently confused by my own code. I&#8217;d look at a piece of code and wonder, &#8220;What was I trying to do here?&#8221; or &#8220;When did I change this? Wait, did I change this?&#8221;. Occasionally, I&#8217;d tar-up my code for a historical record and I&#8217;m not sure now if I ever referred to those tarballs. When I eventually put the tina code into a Subversion repository I was much happier because of it.</p>

<p>With another project, that I wanted to put under version control, I found I had no less that 3 different versions of the code lying around on my hard drive. It look some investigation with <code>diff</code> in order to find out which one was the most current. Fortunately I didn&#8217;t have some files more recent in one copy and others more recent in another copy, but that could have easily happened.</p>

<p>With version control, it&#8217;s easy to find out what changed in my code, especially if I write useful commit messages. The most unexpected (and incredibly positive) side effect was that once I started using version control, the quality of my code went up dramatically. By tracking exactly what was changing between revisions, unwanted changes and debug code did not slip into the shipping code.</p>

<p>It&#8217;s worth noting that this approach goes hand-in-hand with unit testing.  Version control lets you know what is changing and unit testing lets you know that your changes don&#8217;t result in regressions.  As solo developers without QA teams or even a QA person, using these best practices seriously improves our ability to complete with larger organizations.</p>

<p>So, I recommend version control for any coding project bigger than a few lines of code. I used Subversion for a while and have now moved onto git.</p>

<p>My tips for version control success:</p>

<ul>
<li><strong>Make small commits</strong> &#8211; don&#8217;t commit a whole day&#8217;s work if you wrote 2 features and fixed 8 bugs. That should be at least 10 commits. For sure, commit every-time you complete something &#8211; a bugfix, a feature, fixing a typo, a formatting change. It&#8217;s makes it much easier to find regressions and other issues later. Oh, and try not to work on many things at once especially if the changes overlap in the code.
<li><strong>Compile before commit</strong> &#8211; each commit represents a known state of your code, so make sure the code compiles correctly without warnings or errors before committing.
<li><strong>Diff before commit</strong> &#8211; before each commit, look over the diff of your current code compared with the last commit.  Then you&#8217;ll know for sure what you are committing. If you don&#8217;t like part of the proposed commit, change it, diff it again, repeat until you like it and then commit.
<li><strong>Write useful messages</strong> &#8211; When you commit a message is required is usually. Make sure it makes sense to you and to others looking at your repository.
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2009/11/07/why-version-control-is-important-for-solo-developers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>From Hacker to microISV: Tagging, Building and Releasing</title>
		<link>http://www.cimgf.com/2009/07/06/from-hacker-to-microisv-tagging-building-and-releasing/</link>
		<comments>http://www.cimgf.com/2009/07/06/from-hacker-to-microisv-tagging-building-and-releasing/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 22:34:11 +0000</pubDate>
		<dc:creator>Fraser Hess</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[Version Control]]></category>
		<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=671</guid>
		<description><![CDATA[It is important to develop a consistent build process for your applications. I have written a couple of bash scripts to help me with this process. I use git for version control and also the services of github. Now in another post on this site Marcus covered how to put git commit checksums in your [...]]]></description>
			<content:encoded><![CDATA[<p>It is important to develop a consistent build process for your applications.  I have written a couple of bash scripts to help me with this process.</p>

<p>I use git for version control and also the services of <a href="http://github.com">github</a>.  Now in <a href="http://www.cimgf.com/2008/04/13/git-and-xcode-a-git-build-number-script/">another post</a> on this site Marcus covered how to put git commit checksums in your Info.plist&#8217;s CFBundleVersion.  I have opted to use Apple Generic Versioning (or agv for short) instead as it has an easy to read incrementing build number and is super  easy to script. It&#8217;s also great for use with Sparkle since Sparkle uses the CFBundleVersion to see if the appcast has a newer version.
<span id="more-671"></span>
Chris Hanson wrote a <a href="http://chanson.livejournal.com/125568.html">great piece</a> a few years back about getting agv setup in your XCode project.  I followed his instructions for that.  I also set the <strong>CFBundleShortVersionString</strong> in Info.plist to <strong>__VERSION__</strong>.  You&#8217;ll see why I do that later.</p>

<p>When it comes time to build my app for shipping, either privately or publicly, I run <code>tag.sh</code>.  This bash script increments the agv version and creates a git tag.  The script takes one parameter which is the marketing version of your build (1.0, 2.0.4fc1, 2.5b6 etc).</p>

<p>Before running <code>tag.sh</code>, the state of the git repo should be clean- there should be no other staged files or uncommitted edits.  It&#8217;s also a good idea to close the XCode project since <code>agvtool</code> will modify the XCode project file.</p>

<p><code>tag.sh</code> also takes care of committing the changed CFBundleVersion for you.  Here is it&#8217;s code:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/sh</span>
<span style="color: #007800;">tag</span>=$<span style="color: #000000;">1</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$tag</span>&quot;</span> == <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;No tag specified&quot;</span>
	<span style="color: #7a0874; font-weight: bold;">exit</span>
<span style="color: #000000; font-weight: bold;">fi</span>
agvtool next-version <span style="color: #660033;">-all</span>
git commit <span style="color: #660033;">-a</span> <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;Increment CFBundleVersion for <span style="color: #007800;">$tag</span>&quot;</span>
git tag <span style="color: #660033;">-m</span> <span style="color: #ff0000;">&quot;Tag for <span style="color: #007800;">$tag</span>&quot;</span> <span style="color: #660033;">-a</span> <span style="color: #007800;">$tag</span>
git push origin master
git push <span style="color: #660033;">--tags</span></pre></td></tr></table></div>


<p>So having run <code>tag.sh</code> I have created a git tag for my build so I can always go back and see that version of the code either in github or using <code>git checkout &lt;tag name&gt;</code> at the command line.</p>

<p>After this I use a jumbo script that checks out the tag I just created, builds it, zips it up, uploads it to my web server, outputs an <code>&lt;item&gt;</code> for your Sparkle Appcast (including signing the update) and maybe tweets about it. Phew. It&#8217;s a heavily modified version of <a href="http://code.google.com/p/flycode/source/browse/trunk/buildapp/bin/babuild.sh">Gus Mueller&#8217;s build script</a>.  Here&#8217;s the usage:</p>

<p><code>build.sh -p ProjectName -t tag [-u [-w tweet]]</code></p>

<p>The two required parameters are a project name and a tag.  Optionally you can upload and then tweet about the newly available build.  I do all of my public builds in a separate clone of my git repo that never gets edited or otherwise messed with (~/Development/building/).  There&#8217;s a whole lot going on in this script that could be explained, but for now I&#8217;ll just leave you with the code to walk through, and if something needs clarified, post a comment and I&#8217;ll do my best.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
</pre></td><td class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#!/bin/bash</span>
&nbsp;
<span style="color: #007800;">upload</span>=<span style="color: #000000;">0</span>
<span style="color: #007800;">tweet</span>=<span style="color: #ff0000;">&quot;&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">while</span> <span style="color: #7a0874; font-weight: bold;">getopts</span> <span style="color: #ff0000;">&quot;:t:up:w:&quot;</span> Option
<span style="color: #000000; font-weight: bold;">do</span>
  <span style="color: #000000; font-weight: bold;">case</span> <span style="color: #007800;">$Option</span> <span style="color: #000000; font-weight: bold;">in</span>
    <span style="color: #c20cb9; font-weight: bold;">w</span> <span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">tweet</span>=<span style="color: #007800;">$OPTARG</span><span style="color: #000000; font-weight: bold;">;;</span>
    u <span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">upload</span>=<span style="color: #000000;">1</span><span style="color: #000000; font-weight: bold;">;;</span>
    p <span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">project</span>=<span style="color: #007800;">$OPTARG</span><span style="color: #000000; font-weight: bold;">;;</span>
    t <span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #007800;">tag</span>=<span style="color: #007800;">$OPTARG</span><span style="color: #000000; font-weight: bold;">;;</span>
  <span style="color: #000000; font-weight: bold;">esac</span>
<span style="color: #000000; font-weight: bold;">done</span>
<span style="color: #7a0874; font-weight: bold;">shift</span> $<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">$OPTIND</span> - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$project</span>&quot;</span> == <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;No project specified&quot;</span>
	<span style="color: #7a0874; font-weight: bold;">exit</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$tag</span>&quot;</span> == <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;No tag specified&quot;</span>
	<span style="color: #7a0874; font-weight: bold;">exit</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Configuration</span>
<span style="color: #007800;">final_builds</span>=~<span style="color: #000000; font-weight: bold;">/</span>Development<span style="color: #000000; font-weight: bold;">/</span>release_builds
<span style="color: #007800;">code_folder</span>=~<span style="color: #000000; font-weight: bold;">/</span>Development<span style="color: #000000; font-weight: bold;">/</span>building<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$project</span>
<span style="color: #007800;">build_folder</span>=<span style="color: #007800;">$code_folder</span><span style="color: #000000; font-weight: bold;">/</span>build
<span style="color: #007800;">keys_folder</span>=~<span style="color: #000000; font-weight: bold;">/</span>Development<span style="color: #000000; font-weight: bold;">/</span>keys
<span style="color: #007800;">upload_destination</span>=user<span style="color: #000000; font-weight: bold;">@</span>yourcompany.com:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>apache2<span style="color: #000000; font-weight: bold;">/</span>htdocs<span style="color: #000000; font-weight: bold;">/</span>downloads<span style="color: #000000; font-weight: bold;">/</span>
<span style="color: #007800;">release_notes_webfolder</span>=http:<span style="color: #000000; font-weight: bold;">//</span>yourcompany.com<span style="color: #000000; font-weight: bold;">/</span>releasenotes
<span style="color: #007800;">downloads_webfolder</span>=http:<span style="color: #000000; font-weight: bold;">//</span>yourcompany.com<span style="color: #000000; font-weight: bold;">/</span>downloads
<span style="color: #007800;">twitter_uname</span>=someone<span style="color: #000000; font-weight: bold;">@</span>somewhere.com
<span style="color: #007800;">twitter_pword</span>=password
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #000000; font-weight: bold;">!</span> <span style="color: #660033;">-d</span>  <span style="color: #007800;">$final_builds</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #007800;">$final_builds</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># clean up</span>
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-d</span> <span style="color: #007800;">$build_folder</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #007800;">$build_folder</span>
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$code_folder</span>
&nbsp;
git pull origin master
git pull <span style="color: #660033;">--tags</span>
git checkout <span style="color: #007800;">$tag</span>
&nbsp;
<span style="color: #c20cb9; font-weight: bold;">sed</span> <span style="color: #660033;">-i</span> <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #ff0000;">'s/__VERSION__/'</span><span style="color: #007800;">$tag</span><span style="color: #ff0000;">'/g'</span> Info.plist
&nbsp;
<span style="color: #7a0874; font-weight: bold;">echo</span> building project
xcodebuild <span style="color: #660033;">-target</span> <span style="color: #007800;">$project</span> <span style="color: #660033;">-configuration</span> Release <span style="color: #007800;">OBJROOT</span>=<span style="color: #007800;">$build_folder</span> <span style="color: #007800;">SYMROOT</span>=<span style="color: #007800;">$build_folder</span> <span style="color: #007800;">OTHER_CFLAGS</span>=<span style="color: #ff0000;">&quot;&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$?</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Bad build for <span style="color: #007800;">$project</span>&quot;</span>
	say <span style="color: #ff0000;">&quot;bad build!&quot;</span>
<span style="color: #000000; font-weight: bold;">else</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">#ok, let's index the documentation if we've got it.</span>
	<span style="color: #666666; font-style: italic;">#/Developer/Applications/Utilities/Help\ Indexer.app/Contents/MacOS/Help\ Indexer &quot;/tmp/buildapp/build/Release/BuildApp.app/Contents/Resources/English.lproj/BuildAppHelp&quot;</span>
&nbsp;
	<span style="color: #c20cb9; font-weight: bold;">mv</span> <span style="color: #007800;">$build_folder</span><span style="color: #000000; font-weight: bold;">/</span>Release<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$project</span>.app <span style="color: #007800;">$final_builds</span>
&nbsp;
	<span style="color: #666666; font-style: italic;"># make the zip file</span>
	<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$final_builds</span>
	<span style="color: #c20cb9; font-weight: bold;">zip</span> <span style="color: #660033;">-r</span> <span style="color: #007800;">$project</span>-<span style="color: #007800;">$tag</span>.zip <span style="color: #007800;">$project</span>.app
&nbsp;
	<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #007800;">$project</span>.app
&nbsp;
	<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #007800;">$upload</span> == <span style="color: #000000;">1</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
&nbsp;
		<span style="color: #7a0874; font-weight: bold;">echo</span> uploading to server...
		<span style="color: #666666; font-style: italic;"># upload</span>
		<span style="color: #c20cb9; font-weight: bold;">scp</span> <span style="color: #007800;">$project</span>-<span style="color: #007800;">$tag</span>.zip <span style="color: #007800;">$upload_destination</span>
&nbsp;
		<span style="color: #666666; font-style: italic;"># get values for appcast</span>
		<span style="color: #007800;">dsasignature</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #007800;">$keys_folder</span><span style="color: #000000; font-weight: bold;">/</span>sign_update.rb <span style="color: #007800;">$final_builds</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$project</span>-<span style="color: #007800;">$tag</span>.zip <span style="color: #007800;">$keys_folder</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$project</span>\_dsa_priv.pem<span style="color: #000000; font-weight: bold;">`</span>
		<span style="color: #007800;">filesize</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">stat</span> <span style="color: #660033;">-f</span> <span style="color: #000000; font-weight: bold;">%</span>z <span style="color: #007800;">$final_builds</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$project</span>-<span style="color: #007800;">$tag</span>.zip<span style="color: #000000; font-weight: bold;">`</span>
		<span style="color: #007800;">pubdate</span>=<span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">date</span> <span style="color: #ff0000;">&quot;+%a, %d %h %Y %T %z&quot;</span><span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
		<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$code_folder</span>
&nbsp;
		<span style="color: #007800;">cfbundleversion</span>=<span style="color: #000000; font-weight: bold;">`</span>agvtool what-version -terse<span style="color: #000000; font-weight: bold;">`</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">#output appcast item</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> Put the following text <span style="color: #000000; font-weight: bold;">in</span> your appcast
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;item&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;title&gt;Version <span style="color: #007800;">$tag</span>&lt;/title&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;sparkle:releaseNotesLink&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$release_notes_webfolder</span>/<span style="color: #007800;">$project</span>.html&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;/sparkle:releaseNotesLink&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;pubDate&gt;<span style="color: #007800;">$pubdate</span>&lt;/pubDate&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;enclosure url=<span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$downloads_webfolder</span>/<span style="color: #007800;">$project</span>-<span style="color: #007800;">$tag</span>.zip<span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;sparkle:version=<span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$cfbundleversion</span><span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;sparkle:shortVersionString=<span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$tag</span><span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;sparkle:dsaSignature=<span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$dsasignature</span><span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;length=<span style="color: #000099; font-weight: bold;">\&quot;</span><span style="color: #007800;">$filesize</span><span style="color: #000099; font-weight: bold;">\&quot;</span>&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;type=<span style="color: #000099; font-weight: bold;">\&quot;</span>application/octet-stream<span style="color: #000099; font-weight: bold;">\&quot;</span> /&gt;&quot;</span>
		<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;&lt;/item&gt;&quot;</span>
		<span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #ff0000;">&quot;<span style="color: #007800;">$tweet</span>&quot;</span> <span style="color: #000000; font-weight: bold;">!</span>= <span style="color: #ff0000;">&quot;&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
			<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Calling twitter: <span style="color: #007800;">$tweet</span>&quot;</span>
			curl <span style="color: #660033;">-u</span> <span style="color: #007800;">$twitter_uname</span>:<span style="color: #007800;">$twitter_pword</span> <span style="color: #660033;">-d</span> <span style="color: #007800;">status</span>=<span style="color: #ff0000;">&quot;<span style="color: #007800;">$project</span> <span style="color: #007800;">$tag</span> is up. <span style="color: #007800;">$tweet</span>&quot;</span> http:<span style="color: #000000; font-weight: bold;">//</span>twitter.com<span style="color: #000000; font-weight: bold;">/</span>statuses<span style="color: #000000; font-weight: bold;">/</span>update.xml
		<span style="color: #000000; font-weight: bold;">fi</span>
	<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
	open <span style="color: #007800;">$final_builds</span>
	say <span style="color: #ff0000;">&quot;done building&quot;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">fi</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">cd</span> <span style="color: #007800;">$code_folder</span>
git checkout Info.plist
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> <span style="color: #007800;">$build_folder</span></pre></td></tr></table></div>


<p><b>Other References</b></p>

<p><a href="http://github.com/guides/push-tags-to-github">Push tags to github</a>
<a href="http://sparkle.andymatuschak.org/documentation/pmwiki.php/Documentation/BasicSetup">Sparkle Basic Setup</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2009/07/06/from-hacker-to-microisv-tagging-building-and-releasing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Launching: If it ain&#8217;t broke, don&#8217;t fix it</title>
		<link>http://www.cimgf.com/2009/06/24/launching-if-it-aint-broke-dont-fix-it/</link>
		<comments>http://www.cimgf.com/2009/06/24/launching-if-it-aint-broke-dont-fix-it/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 22:54:13 +0000</pubDate>
		<dc:creator>Fraser Hess</dc:creator>
				<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=580</guid>
		<description><![CDATA[This is the first in a short series on my adventures getting my software out the door. Rather than this first lesson be a lesson in what to do, here&#8217;s what not to do. Don&#8217;t order a DSL upgrade 7 days before your ship date. Yes, indeed. Last Wednesday morning, Qwest &#8220;upgraded&#8221; our DSL to [...]]]></description>
			<content:encoded><![CDATA[<p>This is the first in a short series on my adventures getting my software out the door.  Rather than this first lesson be a lesson in what to do, here&#8217;s what not to do.
<span id="more-580"></span>
<strong>Don&#8217;t order a DSL upgrade 7 days before your ship date.</strong></p>

<p>Yes, indeed.  Last Wednesday morning, Qwest &#8220;upgraded&#8221; our DSL to 7Mbps.  From then until Saturday lunchtime, I had 13 hours of solid connectivity, most of which I was asleep for.  It did indeed get resolved and I am enjoying the new speed but it certainly wasn&#8217;t worth stress of trying to find connectivity while trying to ship.  I went to Barnes and Noble, Krispy Kreme and the seminary library in search of the uplink.  I also wasted a trip to Best Buy to get a new DSL modem which didn&#8217;t solve the issue, despite the Qwest tech&#8217;s assurances that it would. (That reminds me, I need to return it and get my $75 back.)</p>

<p>Thinking about it, my rule should be generalized as:</p>

<p><strong>Don&#8217;t replace/upgrade/otherwise mess with any of your critical infrastructure within two weeks of your ship date unless it&#8217;s broke.</strong></p>

<p>After being burned by the DSL outage, I left well alone newly released updates to XCode, PHP, Safari and Java.  I&#8217;ll get to those at a less critical moment.</p>

<p>Well, lesson learned.  I won&#8217;t be doing that again.  Now if you&#8217;ll excuse me, I&#8217;m gonna download a movie from Netflix.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2009/06/24/launching-if-it-aint-broke-dont-fix-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t treat your customers like thieves</title>
		<link>http://www.cimgf.com/2009/01/28/dont-treat-your-customers-like-thieves/</link>
		<comments>http://www.cimgf.com/2009/01/28/dont-treat-your-customers-like-thieves/#comments</comments>
		<pubDate>Wed, 28 Jan 2009 17:14:26 +0000</pubDate>
		<dc:creator>Marcus Zarra</dc:creator>
				<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=423</guid>
		<description><![CDATA[Every once in a while I run across a situation that just amazes me. While this topic is not strictly about software development it is about the subject of the business of software. Our customers give us money for something we have already written. This is an important point to grasp. We write software once [...]]]></description>
			<content:encoded><![CDATA[<p>Every once in a while I run across a situation that just amazes me.  While this topic is not strictly about software development it is about the subject of the business of software.</p>

<h2>Our customers give us money for something we have already written.</h2>

<p>This is an important point to grasp.  We write software once and sell it many times over with no production costs other than initial development.  Unlike almost every other industry in the world we only have to write the software once!  We do not have to produce something new every time a customer wants to purchase something from us.</p>

<p><span id="more-423"></span></p>

<p>Yes we need to maintain the code and provide updates to our customers.  However we do not need to create something new out of whole cloth every time a customer wants to buy it.  It is about as close to printing money as you are going to get &#8212; legally.</p>

<p>I am not saying this is easy!  I would argue that software development is one of the most mentally challenging career choices out there.</p>

<h2>Do not steal from your customers</h2>

<p>Your customer has already given you money for your software that you wrote.  Do not try and go back to that customer again unless you have written something significantly new.  If your software has gone from v1.0 to v2.0 then absolutely charge them an upgrade fee.  However, do not force your customers to purchase another license just because you do not like the way that they are using your software.</p>

<p>I own several Macintosh computers.  Those who know me claim I buy Macs like other people buy lattÃ©s.  That might be an exaggeration but I do tend to buy the new shiny.  I normally have two machines running at once, sometimes I am using even more at the same time while I do software development and testing.</p>

<p>However, when I purchase a piece of software I expect to buy <strong>ONE</strong> license for my personal use.  If my wife likes it she gets her own license. If my son likes it he also gets a license.  I do not expect to, nor will I, purchase one license per machine that I am currently using.  That is  gouging your customers.</p>

<h2>Do not pretend to be a lawyer</h2>

<p>As you can guess, this blog post was prompted by a piece of software putting in a stealth change which blocked me from using it on two of my machines.  I immediately contacted the author of the software and expressed my displeasure with this change.  The author wrote me back and told me that I had been using their software <em>illegally</em>.</p>

<p>Guess what, you are not a lawyer.  Neither am I.  We also are not a government body.  What that means is that we have no authority or ability to make something <em>illegal</em>.  Violating a software license, whether it is a valid license or not, does not illegal make.  Stabbing someone is illegal; there is a law against that.  Purchasing software and using it outside of the scope of the EULA is not illegal; at most it is a civil disagreement.  When talking to your customers do not claim that something is illegal.  It makes you sound like a moron.</p>

<p>If you want to sound like a lawyer, either hire one to handle customer support or go to law school.  Don&#8217;t use legalese to sound impressive or try and scare your customers.  Scared customers do not give you more money.</p>

<h2>Customers want to like you</h2>

<p>You solved a problem for them.  They <strong><em>like</em></strong> you.  They want to be your friend and shower you with affection.  However that can quickly be turned into hate.  When you treat your customers poorly they will become your worst nightmare.  They will tell their friends not to buy your software and perhaps even start writing nasty blog posts about your software.</p>

<p>Word of mouth is a powerful thing.  Most people when they are happy tend to keep quiet about it.  However when they are upset they want to share their frustration.  Guess which kind of customer is going to be vociferous; the one you made happy or the one you screwed over?</p>

<h2>Piracy</h2>

<blockquote>I learned long ago, never to wrestle with a pig. You get dirty, and besides, the pig likes it. &#8211;George Bernard Shaw</blockquote>

<p>I learned long ago to never fight pirates.  They enjoy it more than you do.  From their point of view it is a challenge just to see if they can outsmart you.  They enjoy it so much that they will do it for free!  You, however, like to get paid for your work.  No one is going to pay you for adding code to your software that is targeted at pirates.  However you have a good chance of losing money if your customers get caught in your anti-piracy code and can&#8217;t use their software that they purchased.  </p>

<p>Assume your customers are doing the right thing.  Put in a serial number to keep your customers honest and then stop.  Do not put in authorization checks to your server.  Do not put in network checks on the license.  Do not waste your time with junk that can cause problems for your customer if you made a programming mistake.  Just like the lock on your front door is not going to stop a determined thief, your serial number is not going to stop a pirate.  However both of them are going to stop an honest person from being tempted.  <strong>That is your goal.</strong></p>

<p>Spend that time making your software better and you will gain far more than you <em>might</em> lose to pirates.  Your <strong>paying</strong> customers will be happier for it.</p>

<h2>Conclusion</h2>

<p>As with everything on this blog, this is the opinion of the author.  But it is an opinion born out of experience and I practice what I preach.  There are no network checks in my software.  There is no authorization check to my server to stop a license from being used more than once.</p>

<p>Guess what happened with the software that prompted this article.  I removed their software from my second machine, rolled back to the previous version on the remaining machine and I will be replacing it with their competitor&#8217;s software as soon as possible.  They will not be seeing any more money from me.  When someone asks my advice for a piece of software that solves that particular problem; guess who I am going to recommend.</p>

<p>I could have set up a rule to block their network check and continued to use their software.  It would have been trivial and taken a lot less of my time than this article or writing the software author.  However I have no interest in working with a developer who treats his customers like thieves.</p>

<p>Don&#8217;t treat me like a thief and I will give you money for your software.  It is that simple.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2009/01/28/dont-treat-your-customers-like-thieves/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>From Hacker to microISV: Custom File Formats</title>
		<link>http://www.cimgf.com/2008/05/13/from-hacker-to-microisv-custom-file-formats/</link>
		<comments>http://www.cimgf.com/2008/05/13/from-hacker-to-microisv-custom-file-formats/#comments</comments>
		<pubDate>Wed, 14 May 2008 03:30:52 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=114</guid>
		<description><![CDATA[In this continuing series on my own transition from a Mac application hacker to microISV (Independent Software Vendor), I am going to demonstrate how to create your own file format for your application. You&#8217;ve probably seen these types of files in popular applications such as iMovie HD (06&#8242;) or GarageBand or even xcode in which [...]]]></description>
			<content:encoded><![CDATA[<p>In this continuing series on my own transition from a Mac application hacker to microISV (Independent Software Vendor), I am going to demonstrate how to create your own file format for your application. You&#8217;ve probably seen these types of files in popular applications such as <strong>iMovie HD (06&#8242;)</strong> or <strong>GarageBand</strong> or even <strong>xcode</strong> in which the actual files used are, behind the scenes, folders that the operating system treats as regular files. These folders/files have a special bit set on them that tell OS X how to deal with them. The goal of this post is to demonstrate how you can do the following:</p>

<ul>
<li>Create your own file format with your own file extension</li>
<br />
<li>Register your file format with the operating system</li>
<br />
<li>Provide application loading of your file that&#8217;s been double clicked in the <em>Finder</em></li>
<br />
<li>Write data and preferences back out to your application file</li>
<br />
<li>Add resources such as media files to your application file</li>
</ul>

<p><span id="more-114"></span></p>

<p>You can download the demo application here: <a href='http://www.cimgf.com/wp-content/uploads/2008/05/pdfkeeper.zip'>PDF Keeper Demo Application</a></p>

<h2>A Brief Discussion On Files and Folders</h2>

<p>If you&#8217;ve ever come across a file in your file system that when control-clicked gives you an option in the pop-up menu to <em>Show Package Contents</em> then you are familiar with the type of file we are looking to create. What you may not know, however, is that this file is actually a directory. The choice to show the package contents is the OS allowing you to treat the file as a folder, which it actually is behind the scenes. When you create a custom file format in this manner, you are simply storing your project data and files under a sub directory.</p>

<p>You can verify that a special bit is set on these types of files by opening Terminal.app, navigating to the directory where such a file resides and running <strong>ls -al</strong> to get a detailed file list. When I do that on my directory where some of my custom files types are stored, I get a listing that looks like this.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/05/pdfkeeperterminal.png" alt="PDF Keeper Project Files in Terminal" title="PDF Keeper Project Files in Terminal" width="500" height="30" class="alignleft size-full wp-image-122" /></p>

<p>Notice the at symbol (@) in the file listing. This is the visual indicator that this directory has extended information&#8211;which in our case means that the directory is being treated as a package. If you want to set this bit through the command line, just run the following command:
<pre>
SetFile -a B &lt;directory_name&gt;
</pre>
Where &lt;directory_name&gt; is the name of the directory on which you would like to set this bit.</p>

<h2>PDF Keeper Demo Application</h2>

<p>For this post, I&#8217;ve included a demo application I&#8217;ve named <strong>PDF Keeper</strong>. <strong>PDF Keeper</strong> isn&#8217;t terribly practical as an application, but it effectively demonstrates the principles I&#8217;m wanting to convey. It simply opens our custom file type and loads in properties and data specified in the <em>Info.plist</em> file that each custom file contains. When you first run the application, you will be prompted to create a new <strong>PDF Keeper</strong> file. You will then see a list view that displays a list of PDF files stored within our custom file type. When you first create the file, the list veiw will be blank, so you will need to add some PDF files by selecting <strong>File | Add PDF File&#8230;</strong>. It then allows you to double-click any of the files in the list to view them in a <em>PDFView</em>.</p>

<p>If you were to look at one of the <strong>PDF Keeper</strong> file contents by selecting <em>Show Package Contents</em> from the context menu in the finder, you would see file hierarchy similar to the one below.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/05/pdfkeeperhierarchy.png" alt="PDF Keeper Hierarchy" title="PDF Keeper Hierarchy" width="299" height="121" class="alignleft size-full wp-image-121" /></p>

<blockquote><strong>Note:</strong> Keep in mind that you will have different PDF files in the <em>Resources</em> directory than I have.</blockquote>

<p>The <em>Info.plist</em> file inside the <em>Contents</em> directory is a property list file in XML format that keeps track of the PDF files we are storing. The <em>Resources</em> directory is where all of the PDF files are actually stored when we add one in <strong>PDF Keeper</strong>. Download, build and run the demo application to see it in action.</p>

<p>The path to your <em>Info.plist</em> file is important. It should be located inside of the <em>Contents</em> directory and be named <em>Info.plist</em>. That way, when we call, <strong>-[NSBundle bundleWithPath:]</strong>, we will receive back an <strong>NSBundle</strong> whose <em>infoDictionary</em> member variable is an NSDictionary populated with the contents of the <em>Info.plist</em> file.</p>

<p>You can see how we do this in the call to <strong>-setupProject</strong>.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setupProject<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>projectPath;
<span style="color: #002200;">&#123;</span>
  currentProjectFilepath <span style="color: #002200;">=</span> projectPath;
&nbsp;
  <span style="color: #11740a; font-style: italic;">// Load the file bundle to obtain the bundle dictionary</span>
  <span style="color: #400080;">NSBundle</span> <span style="color: #002200;">*</span>contextBundle <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBundle</span> bundleWithPath<span style="color: #002200;">:</span>projectPath<span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>contextBundle infoDictionary<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span> <span style="color: #a61390;">return</span>;
&nbsp;
  <span style="color: #11740a; font-style: italic;">// The infoDictionary represents the Info.plist file. We load it</span>
  <span style="color: #11740a; font-style: italic;">// and grab the array of files using the key &quot;Files&quot;</span>
  <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>files <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>contextBundle infoDictionary<span style="color: #002200;">&#93;</span> objectForKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Files&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #11740a; font-style: italic;">// If we have a list of files, we initialize our array model with them.</span>
  <span style="color: #11740a; font-style: italic;">// Otherwise we initialize the array with a capacity of 10</span>
  <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> files <span style="color: #002200;">!=</span> <span style="color: #a61390;">nil</span> <span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#123;</span>
      pdfFiles <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> alloc<span style="color: #002200;">&#93;</span> initWithArray<span style="color: #002200;">:</span>files<span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#125;</span>
  <span style="color: #a61390;">else</span>
  <span style="color: #002200;">&#123;</span>
      pdfFiles <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableArray</span> alloc<span style="color: #002200;">&#93;</span> initWithCapacity<span style="color: #002200;">:</span><span style="color: #2400d9;">10</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#125;</span>
&nbsp;
  <span style="color: #11740a; font-style: italic;">// Reload the table view</span>
  <span style="color: #002200;">&#91;</span>tableView reloadData<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Create Your Own File Format</h2>

<p>This is probably the most tedious aspect of the custom file format task as you have to decide what data you want your file to contain. I suggest that you code up a sample property list file in xcode and manually edit it to represent what you want. Then you can tweak it as you go. You won&#8217;t think of everything you want to save at first, so you do this loosely, however, you do need to start somewhere. This property list file is what will be stored inside the Contents folder of your custom file. Here is what a <em>Info.plist</em> file looks like in a <strong>PDF Keeper</strong> custom file.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
</pre></td><td class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">encoding</span>=<span style="color: #ff0000;">&quot;UTF-8&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #00bbdd;">&lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;plist</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Files<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;array<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>About Stacks.pdf<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>8051 Microcontroller.pdf<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/array<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/dict<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/plist<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<h2>Register Your Custom File Format</h2>

<p>This part is actually quite simple. You will, however, want to have your own custom icon ready to use for your custom format file. To register your file format, which is what enables you to double click your file in the <em>Finder</em> and have it properly load your application, with your project loaded in <em>xcode</em>, select <strong>Project | Edit Active Target &#8220;&lt;Project Name&gt;&#8221;</strong> where &lt;Project Name&gt; is the name of your project. In the ensuing window, select the <strong>Properties</strong> tab. You will see at the bottom a list view labeled <strong>Document Types:</strong>. This is where you will specify your document name, extension, and icon file. Below is a screenshot of the <strong>Document Type</strong> specified in <strong>PDF Keeper</strong>.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/05/pdfkeeperdoctypes.png' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/05/pdfkeeperdoctypes-300x184.png" alt="PDF Keeper Doc Types" title="PDF Keeper Doc Types" width="300" height="184" class="alignleft size-medium wp-image-123" /></a></p>

<p>Notice that the <strong>Package</strong> checkbox is checked. This is what tells Finder that your file, though a directory, should look like a single file to the end user. You should also make note that the file extension field does not have a dot (.) in it. I learned that one the hard way.</p>

<h2>Hiding/Showing File Extensions</h2>

<p>Some applications that use this technique for custom file formats hide the file extension while others show it. <strong>Garageband</strong>, the entry level music recording application from Apple, for example, hides its file extension which is <em>.band</em> while our beloved <strong>xcode</strong> shows its file extension which is <em>.xcodeproj</em>.</p>

<p>Hiding and showing file extensions is handled in the Finder through the <strong>Get Info&#8230;</strong> window. If you select a <strong>Garageband</strong> file in the finder and press <strong>Command-I</strong> you will notice under the <strong>Name &amp; Extension</strong> section the <strong>Hide extension</strong> checkbox is checked.</p>

<p>Here is a screenshot of a <strong>Garageband</strong> file&#8217;s <strong>Get Info&#8230;</strong> information.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/05/garagebandgetinfo.png' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/05/garagebandgetinfo-150x150.png" alt="Garageband File Info" title="Garageband File Info" width="150" height="150" class="alignleft size-thumbnail wp-image-124" /></a></p>

<blockquote><strong>Note:</strong> If you don&#8217;t have any <strong>Garageband</strong> files to look at, just run the demo app, <strong>PDF Keeper</strong> and create a new file. You can then <strong>Get Info&#8230;</strong> by pressing <strong>Command-I</strong> with that file selected in the finder to see the same thing.</blockquote>

<p>You can do the same with an <strong>xcode</strong> project and you will notice that its <strong>Hide extension</strong> checkbox is not checked.</p>

<p>So the question becomes, how do we handle this in the code. When you create a new file of your custom format, you&#8217;ll want to control this, so how do we do so? It is a simple attribute you specify in an NSDictionary before calling NSFileManager&#8217;s <em>createDirectoryAtPath</em> called <em>NSFileExtensionHidden</em>. The code looks like this in <strong>PDF Keeper</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span>num <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
<span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>attribs <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>num, NSFileExtensionHidden, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
<span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> fileExistsAtPath<span style="color: #002200;">:</span>filepath<span style="color: #002200;">&#93;</span> <span style="color: #002200;">&#41;</span>
<span style="color: #002200;">&#123;</span>
  <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> createDirectoryAtPath<span style="color: #002200;">:</span>filepath attributes<span style="color: #002200;">:</span>attribs<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Keep in mind that you will also want to control whether or not file extensions can be seen in your NSSavePanel and whether or not the OS should treat file packages as directories. The following code is how we do this in <strong>PDF Keeper</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>savePanel setCanSelectHiddenExtension<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>savePanel setTreatsFilePackagesAsDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<p>If <em>canSelectHiddenExtension</em> is set to <em>YES</em>, the user would have the option to select/deselect a checkbox in the save file panel to show or hide the extension. We simply hide it for <strong>PDF Keeper</strong> as it reduces confusion and makes it easier to manage everything behind the scenes.</p>

<p>If <em>treatsFilePackagesAsDirectories</em> is set to <em>YES</em>, the file system would allow the user to drill down into the custom file as if it were a regular directory. We don&#8217;t want the user to be able to do that as we are treating the custom file as a normal file rather than a directory.</p>

<h2>Loading Your Custom File From the Finder</h2>

<p>You will likely want to enable your users to double click a file in the Finder that will then automatically load into your application. If you added a document type to your project as specified in the <strong>Register Your Custom File Format</strong> section above, then you are already part of the way there as on the first run of your application, the file/document type is automatically registered with the OS so that double clicks of your file type will be handed to your application without any further effort on your part.</p>

<p>Now you just need your application to be able to respond when it gets notified that the Finder wants you to load your files type. Fortunately, there is a very simple way to handle this scenario. All you need to do is implement the delegate</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>application<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSApplication</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>theApplication openFile<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>filename</pre></div></div>


<p>in your app delegate. The <em>filename</em> parameter contains the path to the file that was double-clicked in the Finder. You simply do all of your file loading/initialization when this method gets called. You may also implement</p>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>application<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSApplication</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>sender openFiles<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>filenames</pre></div></div>


<p>if you want to handle multiple files being passed to your application. The following code snippet shows how these two delegate methods are implemented in <strong>PDF Keeper</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>application<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSApplication</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>theApplication openFile<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>filename
<span style="color: #002200;">&#123;</span>
  <span style="color: #11740a; font-style: italic;">// This gets called when the user double-clicks a project file in the Finder.</span>
  <span style="color: #002200;">&#91;</span>self openProject<span style="color: #002200;">:</span>filename<span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>self setupProject<span style="color: #002200;">:</span>filename<span style="color: #002200;">&#93;</span>;
  <span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>application<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSApplication</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>sender openFiles<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>filenames
<span style="color: #002200;">&#123;</span>
  <span style="color: #11740a; font-style: italic;">// This gets called when the user opens multiple files from the Finder.</span>
&nbsp;
  <span style="color: #11740a; font-style: italic;">// We only take the first file.</span>
  <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span>filenames count<span style="color: #002200;">&#93;</span> &gt; <span style="color: #2400d9;">0</span> <span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#123;</span>
      <span style="color: #002200;">&#91;</span>self application<span style="color: #002200;">:</span>sender openFile<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>filenames objectAtIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">0</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<h2>Importing Resource Files</h2>

<p>In the <strong>PDF Keeper</strong> demo application, we are only concerned with PDF files. When users select <strong>File | Add PDF File&#8230;</strong> they are prompted to select a PDF file that is then imported into the custom file type. This importing procedure is really just a simple file copy. Remember that our custom file is really just a directory that is being treated as a regular file by the OS. The file import just copies the file from the place where it was selected by the user into the <em>Resources</em> directory of our custom file. Here is the code to add a PDF file to our project file.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>addPDFFile<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #002200;">&#123;</span>
  <span style="color: #400080;">NSOpenPanel</span> <span style="color: #002200;">*</span>openPanel;
&nbsp;
  openPanel <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSOpenPanel</span> openPanel<span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>openPanel setCanChooseDirectories<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>openPanel setAllowsMultipleSelection<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>openPanel setResolvesAliases<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
  <span style="color: #002200;">&#91;</span>openPanel setCanChooseFiles<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #400080;">NSArray</span> <span style="color: #002200;">*</span>fileTypes <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSArray</span> arrayWithObjects<span style="color: #002200;">:</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;pdf&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
  <span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>openPanel runModalForTypes<span style="color: #002200;">:</span>fileTypes<span style="color: #002200;">&#93;</span> <span style="color: #002200;">==</span> NSOKButton<span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#123;</span>
      <span style="color: #11740a; font-style: italic;">// Build our destination filename based upon the current project</span>
      <span style="color: #11740a; font-style: italic;">// file path and the Contents/Resources path below it.</span>
      <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>filename <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>openPanel filename<span style="color: #002200;">&#93;</span>;
      <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>displayName <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> displayNameAtPath<span style="color: #002200;">:</span>filename<span style="color: #002200;">&#93;</span>;
      <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>destFile <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>currentProjectFilepath stringByAppendingPathComponent<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Contents&quot;</span><span style="color: #002200;">&#93;</span>;
      destFile <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>destFile stringByAppendingPathComponent<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Resources&quot;</span><span style="color: #002200;">&#93;</span>;
      destFile <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>destFile stringByAppendingPathComponent<span style="color: #002200;">:</span>displayName<span style="color: #002200;">&#93;</span>;
&nbsp;
      <span style="color: #11740a; font-style: italic;">// Use the NSFileManager to copy the file</span>
      <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> copyPath<span style="color: #002200;">:</span>filename toPath<span style="color: #002200;">:</span>destFile handler<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
      <span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> pdfFiles <span style="color: #002200;">!=</span> <span style="color: #a61390;">nil</span> <span style="color: #002200;">&#41;</span>
      <span style="color: #002200;">&#123;</span>
          <span style="color: #11740a; font-style: italic;">// Add the filename to our list of files.</span>
          <span style="color: #002200;">&#91;</span>pdfFiles addObject<span style="color: #002200;">:</span>displayName<span style="color: #002200;">&#93;</span>;
          <span style="color: #11740a; font-style: italic;">// Save the project.</span>
          <span style="color: #002200;">&#91;</span>self saveProject<span style="color: #002200;">:</span>currentProjectFilepath<span style="color: #002200;">&#93;</span>;
          <span style="color: #11740a; font-style: italic;">// Reload the table view</span>
          <span style="color: #002200;">&#91;</span>tableView reloadData<span style="color: #002200;">&#93;</span>;
      <span style="color: #002200;">&#125;</span>
  <span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<blockquote><strong>Note:</strong> When you import the file you are simply copying it. If the file is large, though, you will want to provide a progress indicator so the user isn&#8217;t wondering if the app is hung or has crashed. This is non-trivial and will require you to use Carbon APIs to accomplish. In our demo app, I am simply calling NSFileManager&#8217;s <em>copyTo:</em> method which will copy the file, but will block until the copy is completed. If you want to implement a file copy using a progress indicator, see my previous post called <a href="http://www.cimgf.com/2008/05/03/cocoa-tutorial-file-copy-with-progress-indicator/"> Cocoa Tutorial: File Copy With Progress Indicator</a></blockquote>

<h2>Updating Info.plist Property List File</h2>

<p>Whenever your user selects <strong>File | Save</strong> you want to update your <em>Info.plist</em> file with the contents of the <em>pdfFiles</em> NSDictionary that is used as the model for the table view control. To do so, we simply get the full path to the <em>Info.plist</em> file, delete the current file, and then save a new file to the same path. Here is the code we use to do so in <strong>PDF Keeper</strong></p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">// Set the path for our property list file.</span>
<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>plistFile <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>contentsPath stringByAppendingPathComponent<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Info.plist&quot;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">// If it already exists in the project, delete it.</span>
<span style="color: #a61390;">if</span><span style="color: #002200;">&#40;</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> fileExistsAtPath<span style="color: #002200;">:</span>plistFile<span style="color: #002200;">&#93;</span> <span style="color: #002200;">&#41;</span>
  <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSFileManager</span> defaultManager<span style="color: #002200;">&#93;</span> removeFileAtPath<span style="color: #002200;">:</span>plistFile handler<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">// Create a dictionary to use to write out our property list file.</span>
<span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>output;
output <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDictionary</span> dictionaryWithObjectsAndKeys<span style="color: #002200;">:</span>pdfFiles, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Files&quot;</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">// Write the file.</span>
<span style="color: #002200;">&#91;</span>output writeToFile<span style="color: #002200;">:</span>plistFile atomically<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;</pre></td></tr></table></div>


<h2>Conclusion</h2>

<p>Your custom file format can be as simple or complex as you would like to make it. You simply decide on all of the information you would like to store in your <em>Info.plist</em> file and then create sub-directories under your <em>Contents</em> directory where you will store your data. The concepts are simple. You are storing data and information about the data inside of a directory that the filesystem treats as a single file. It&#8217;s a very elegant way to create and manage your own custom file formats. Until next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/05/13/from-hacker-to-microisv-custom-file-formats/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>From Hacker to microISV: Dynamic About Box Version and Copyright, and Text Formatting</title>
		<link>http://www.cimgf.com/2008/04/28/from-hacker-to-microisv-dynamic-about-box-version-and-copyright-and-text-formatting/</link>
		<comments>http://www.cimgf.com/2008/04/28/from-hacker-to-microisv-dynamic-about-box-version-and-copyright-and-text-formatting/#comments</comments>
		<pubDate>Mon, 28 Apr 2008 21:12:43 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[microISV]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=98</guid>
		<description><![CDATA[In this post I continue to address topics of relevance to Macintosh programmers who are, like me, moving from being hackers to becoming independent software vendors (micro ISV). Today I am going to address adding copyright and version information to your about dialog and show you how you can update these dynamically. I also cover [...]]]></description>
			<content:encoded><![CDATA[<p>In this post I continue to address topics of relevance to Macintosh programmers who are, like me, moving from being hackers to becoming independent software vendors (micro ISV). Today I am going to address adding copyright and version information to your about dialog and show you how you can update these dynamically. I also cover a few tips on formatting the text in your about dialog. There is more than one way to achieve these things, but my hope is to help others out there who need to accomplish these things and have no prior experience doing them on the Mac.
<span id="more-98"></span></p>

<blockquote>
<strong>Note:</strong> I have to break here for a moment to give credit where it is due. Marcus Zarra, my cohort on this site has an incredible ability to retain information&#8211;especially as it relates to developing applications for the Mac and this has really benefited me greatly. He is a tremendous mentor and teacher and so I felt I needed to just break for a moment and mention that the content of this post is really from his wealth of knowledge. I am writing this post as I am now aware of how to do these things, but it is all thanks to Marcus&#8217; own experience and willingness to share. He&#8217;s a true asset to the Mac development community.

Ok. Enough of that. Marcus&#8217; head may start to swell. ;-)
</blockquote>

<p>Here is the demo application for this post. <a href='http://www.cimgf.com/wp-content/uploads/2008/04/aboutboxapp.zip'>Download About Box App</a>.</p>

<h2>Text Formatting</h2>

<p>If you, like me, don&#8217;t want to mess with fonts, but you would like to have some control over the formatting of the text in your About Box, then this is the tip for you.</p>

<p>When you first create your application, a default about box is already hooked up for you. You can simply <em>Build and Go</em> and select <strong>Application Menu | About Application</strong> to see what it looks like. I&#8217;m not sure about you, but I&#8217;ve never seen a commercial application with the default about box look and style. I doubt you want to leave yours as the default either.</p>

<p>Coming from the Windows world of programming where standards are really just whatever you make them, it may seem unnatural to stick to using the standard fonts, but in the Mac world, if you don&#8217;t make your app conform to the standards that are there, you run the risk of making your application the red-headed step child. People will notice and make comments about it. They might even taunt you. :-D</p>

<p><a href="http://www.red-sweater.com/blog/215/build-your-own-damn-hig">There are some passionate opinions on the topic of the HIG (Human Interfaces Guidlines)</a> and I don&#8217;t claim to know much about it, but the bottom line is that your best bet it likely to try to conform to the standards even though many people violate them.</p>

<p>My about box, started out looking something like this:</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/default_about_box.png" alt="Default About Box" title="default_about_box" width="284" height="174" class="alignnone size-medium wp-image-99" /></p>

<p>Most about boxes are pretty boring, but you can&#8217;t get too much worse than this one. Instead, I created a new window in Interface Builder and hooked it up to the About menu item. When you create your about box window, make sure your window settings are correct.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/window_attributes-215x300.png" alt="About Box Window Attributes" title="window_attributes" width="215" height="300" class="alignnone size-medium wp-image-100" /></p>

<blockquote>
<strong>Note:</strong> If you don&#8217;t ensure that <strong>Release When Closed</strong> is unchecked, your about box will crash your application. Also, make sure that <strong>Visible At Launch</strong> is not checked so that your about box doesn&#8217;t show up with your application runs.
</blockquote>

<p>Then add your various labels etc. so that it looks something like this:</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/new_about_box.png" alt="New About Box" title="new_about_box" width="298" height="294" class="alignnone size-full wp-image-101" /></p>

<p>Yeah, yeah. I know. Still boring, but we&#8217;ll add a couple of features that will help make it more interesting.</p>

<p>Making fonts smaller in a label is easy. Simply select a smaller size in the <strong>Size</strong> attribute drop down.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/text_field_attributes.png" alt="Text Field Attributes" title="text_field_attributes" width="255" height="375" class="alignnone size-full wp-image-102" /></p>

<p>You can do this for your version and copyright labels. To make the text larger, however, takes a little more effort. In this case you&#8217;ll need to bind the font size attribute to a value in your app delegate.</p>

<p>Add a function to your app delegate that returns a float value representing the size of the font you want:</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>appNameLabelFontSize;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">return</span> <span style="color: #2400d9;">24.0</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Then, in interface builder, select your application name label and set the <strong>Font size</strong> binding to use your <strong>AppDelegate</strong>&#8216;s <em>appNameLabelFontSize</em> field.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/04/text_field_bindings.png' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/04/text_field_bindings-121x300.png" alt="Text Field Bindings" title="text_field_bindings" width="121" height="300" class="alignnone size-medium wp-image-103" /></a></p>

<p>Build and run your application in xcode and you should see the new font size in your about box.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/new_about_box2.png" alt="New About Box Bold Name" title="new_about_box2" width="298" height="294" class="alignnone size-full wp-image-104" /></p>

<p>The final change we want to make to our about box is to make the font bold for our application name. We could create another field in our app delegate to return YES that we could bind the <strong>Font bold</strong> binding, however, there&#8217;s an easier, cooler way that doesn&#8217;t require us to do anything but set the <strong>Font bold</strong> field to something that is already true. In this case we&#8217;ll just use the app delegate&#8217;s reference to self and then set the <em>Value Transformer</em> to <strong>NSIsNotNil</strong>.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/04/text_field_bold_bindings.png' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/04/text_field_bold_bindings-121x300.png" alt="Text Field Bold Bindings" title="text_field_bold_bindings" width="121" height="300" class="alignnone size-medium wp-image-105" /></a></p>

<p>Since <strong>self</strong> is always true, this will suffice to tell our label to display in bold.</p>

<p>That&#8217;s it for formatting. Now we need to add some features to keep our version and copyright up to date.</p>

<h2>Dynamic Version and Copyright</h2>

<p>First let&#8217;s look at keeping our copyright data up to date as doing so is very similar to the way we set our font size for the app name in the about box. We simply add another field to the app delegate that we can bind to in Interface Builder. Here is the field.</p>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>copyrightString;
<span style="color: #002200;">&#123;</span>
    <span style="color: #a61390;">return</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Copyright Â© 2008 My Company, Inc.<span style="color: #2400d9;">\n</span>All Rights Reserved.&quot;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>


<p>Just as before, you hook up your field using bindings in Interface Builder. So go back into Interface Builder and select the copyright label placeholder and set the <strong>Value</strong> binding to <em>copyrightString</em> as shown in the screenshot below.</p>

<p><a href='http://www.cimgf.com/wp-content/uploads/2008/04/copyright_field_bindings.png' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/04/copyright_field_bindings-121x300.png" alt="Copyright Field Bindings" title="copyright_field_bindings" width="121" height="300" class="alignleft size-medium wp-image-107" /></a></p>

<p>Now, if you want to change your copyright information, you can simply specify it in your <em>copyrightString</em> field in xcode and it will be up to date in your about box.</p>

<p>Finally, you can also use a similar technique to update your version number. This, however, is dependent upon adding a user defined setting to your project build and fiddling with your project <em>Info.plist</em> file. To add a user defined setting to your project build, complete these steps:</p>

<ol>
<li>Double click your project in the project tree view and click on the <strong>Build</strong> tab.</li><br />
<li>At the bottom of the ensuing window, click the drop down and select <strong>Add User-Defined Setting</strong> as shown.

<img src="http://www.cimgf.com/wp-content/uploads/2008/04/add_user_defined_setting.png" alt="Add User Defined Setting" title="add_user_defined_setting" width="263" height="209" class="alignleft size-full wp-image-108" /></li><br />

<li>A new setting will be created in the list. Name it <em>APPLICATION_VERSION</em> and give it a value of <em>1.0</em>. Close the project settings.<br /></li>

<li>Back in your project tree view, open the <strong>Resources</strong> sub-directory and select your <em>Info.plist</em> file to edit.</il><br />

<li>Look for the key value pair for <em>CFBundleVersion</em> and add a new entry as follows:


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CFBundleVersion<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Alpha 0.35<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CFBundleShortVersionString<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>${APPLICATION_VERSION}<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></td></tr></table></div>


<br />

<li>As with our copyright version string, we create another field in the <em>AppDelegate</em> as shown.


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
</pre></td><td class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>versionString;
<span style="color: #002200;">&#123;</span>
    <span style="color: #400080;">NSBundle</span> <span style="color: #002200;">*</span>mainBundle <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSBundle</span> mainBundle<span style="color: #002200;">&#93;</span>;
    <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>infoDict <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>mainBundle infoDictionary<span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>mainString <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>infoDict valueForKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;CFBundleShortVersionString&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>subString <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>infoDict valueForKey<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;CFBundleVersion&quot;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Version %@ (%@)&quot;</span>, mainString, subString<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></td></tr></table></div>




The <strong>NSDictionary</strong> we grab from the main bundle provides the data in our <em>Info.plist</em> file. We simply plug in the values for the keys we&#8217;ve found for <em>CFBundleVersion</em> and <em>CFBundleShortVersionString</em>.
</il><br />

<li>Finally, back in Interface Builder, connect the value of the version label to the <em>versionString</em> field of the AppDelegate.

<a href='http://www.cimgf.com/wp-content/uploads/2008/04/version_string_binding.jpg' rel='lightbox'><img src="http://www.cimgf.com/wp-content/uploads/2008/04/version_string_binding-121x300.jpg" alt="Version String Bindings" title="version_string_binding" width="121" height="300" class="alignleft size-medium wp-image-110" /></a>
</ul><br />
</ol>

<p>Now, rebuild and run your project and open your about box. You should now see your version information up to date.</p>

<p><img src="http://www.cimgf.com/wp-content/uploads/2008/04/about_box_final.png" alt="About Box Final" title="about_box_final" width="298" height="294" class="alignnone size-full wp-image-109" /></p>

<h2>Conclusion</h2>

<p>It seems like there is always more to do to get your application finished, but these are the aspects of developing your app that will give it polish. It will look good and will make your life easier. If you start to place build numbers into your version information, it will help you when you get crash reports from your users. This will allow you to know exactly which version of the code caused the problem. And if you are using version control like Git, you can automate this process even further. Take a look at Marcus&#8217;s post on <a href="http://www.cimgf.com/2008/04/13/git-and-xcode-a-git-build-number-script/">Git and XCode: A git build number script</a> for more information. Until next time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/04/28/from-hacker-to-microisv-dynamic-about-box-version-and-copyright-and-text-formatting/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>From Hacker To microISV: App Names And Icons</title>
		<link>http://www.cimgf.com/2008/04/19/from-hacker-to-microisv-app-names-and-icons/</link>
		<comments>http://www.cimgf.com/2008/04/19/from-hacker-to-microisv-app-names-and-icons/#comments</comments>
		<pubDate>Sat, 19 Apr 2008 21:06:10 +0000</pubDate>
		<dc:creator>Matt Long</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[microISV]]></category>
		<category><![CDATA[article series]]></category>
		<category><![CDATA[set application icon]]></category>
		<category><![CDATA[set application name]]></category>

		<guid isPermaLink="false">http://www.cimgf.com/?p=97</guid>
		<description><![CDATA[For the past five or six months, I have been developing an application for the Mac that I intend to release for sale in the near future. Though you could probably call me a switcher, to my credit I was a Mac user all through college and would have remained so had the job market [...]]]></description>
			<content:encoded><![CDATA[<p>For the past five or six months, I have been developing an application for the Mac that I intend to release for sale in the near future. Though you could probably call me a switcher, to my credit I was a Mac user all through college and would have remained so had the job market been a bit more supportive of that desire when I finished school, but all along I&#8217;ve wanted to become a Macintosh developer. That time has finally come.
<span id="more-97"></span></p>

<p>In June of 2007, I was in a position both financially and career wise to buy my MacBook Pro with this long intended, not yet realized pursuit of becoming a Macintosh developer.</p>

<p>Since that time I have been hacking my way through example after example trying to learn Objective-C and the Cocoa framework. I&#8217;ve been watching and contributing on the different Apple mailing lists, and I&#8217;ve been writing what I&#8217;ve been learning here at <em>Cocoa Is My Girlfriend</em>. If everything goes right, I will have my application in the wild within the next few months. The ambition will finally pay off and become realized.</p>

<p>As I am finishing the application, I am faced with the stark reality that the work of building the app is a small fraction of the entire work load. Once the code is finished, the list of what is left to do before being able to release the application seems to be growing rather than shrinking. In this series of posts, I intend to examine these hurdles and provide information not only about my experiences, but how I&#8217;ve overcome these hurdles and turned them into success.</p>

<h2>(Re) Naming Your Application</h2>

<p>I won&#8217;t go into any long dissertation on how to choose an application name. Frankly, you can probably name it whatever you want. Just make a quality app and I don&#8217;t think that will matter so much. You can use everything from the practical such as <em>Movie Maker</em> (nice little gem from Microsoft) down to the nonsensical Web 2.0 names that lack vowels like <em>flckr</em> or <em>meebo</em>. You can even give the <a href="http://www.lightsphere.com/dev/web20.html">Web 2.0 Name Generator</a> a try if you can&#8217;t think of anything cool on your own. You make the call.</p>

<p>Sometimes, maybe even often, the first name you think of isn&#8217;t the one you end up using, or, as in my case, you decide you want to put a space in between two words of the app name. If you go into Interface Builder with your MainMenu.nib, you&#8217;ll try to change the name of the application that shows up there and then build the app again only to find that the changes didn&#8217;t take. That&#8217;s because the application name is stored elsewhere. If you need to change your application name in your project, use the following steps.</p>

<ol>
<li>With your application project open in xcode, click on <strong>Project | Edit Active Target &#8220;App Name&#8221;</strong> (where App Name is the name of your application).</li>
<br />
<li>In the ensuing window, select the <strong>Build</strong> tab.</li>
<br />
<li>In the search field, type <strong>Product Name</strong>. This is the name you will see when your application runs. Make changes to the Product Name by double clicking the value. Once you are finished, click ok.</li>
<br />
<li>Rebuild your application and run it again. You should see the application name as you specified in the Product Name field.</li>
</ol>

<h2>Lickable Application Icons</h2>

<p>I&#8217;m no graphic artist. This has always been the case and probably always will be. One of the first keys to being successful with any venture is to realize your limitations and weaknesses and be prepared to pay the professionals who can do the work and provide what you need.</p>

<p>While watching the <a href="http://tech.groups.yahoo.com/group/macsb/">macsb</a> mailing list, the name Jordan Langille came up several times as a graphic artist who could provide the shiny candy coated Macintosh icons and logos that people expecct. I contacted Jordan at <a href="http://onetoad.com/">One Toad Design</a> and within a couple of weeks he provided me with this icon for my application.</p>

<p><br />
<img src='http://www.cimgf.com/wp-content/uploads/2008/04/512.png' alt='Icon' class='alignleft' />
<br /></p>

<p>You can see Jordan&#8217;s portfolio at his site. I&#8217;m quite pleased with the results and highly recommend his work. This is not a paid endorsement. I just like to see good work rewarded, so send him your business. You won&#8217;t be disappointed.</p>

<p>As a first time Macintosh application developer, I was thrilled when I received the <em>.icns</em> file from Jordan and the first thing I wanted to do was plug it into my application. How do you do that? Is it obvious in the project settings? This should be easy, but I don&#8217;t see where to do it in Interface Builder. What is going on?? Help!!</p>

<p>Oh Google&#8230;.</p>

<p>After a quick search, I found that adding the icon to my app was as simple as the following steps.</p>

<ol>
<li>Right-click the <strong>Resources</strong> folder in your project tree and select <strong>Add Existing Files&#8230;</strong>.</li>
<br />
<li>In the ensuing dialog box, navigate to the <em>.icns</em> file that holds your icon and select it. When prompted, select the checkbox labeled <strong>Copy items into destination group&#8217;s folder (if needed)</strong>.<br /><br />This will add the file to your project.</li>
<br />
<li>Look in your <strong>Resource</strong> folder in your project tree for the file <strong>Info.plist</strong>. Open this file</li>
<br />
<li>Look through the file for the key called <strong>CFBundleTypeIconFile</strong>. Simply specify the name of the <em>.icns</em> file you just added to the project like this:


<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>CFBundleTypeIconFile<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/key<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>MyIcon.icns<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/string<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>



</ol>

<p>Save the Info.plist file. Clean, re-build, and run your application and you should now see your icon display in the Dock. Pretty cool.</p>

<h2>Conclusion</h2>

<p>As I finish my application, I continue to learn new aspects of becoming a microISV for the Macintosh. It has frustrating and challenging aspects, but I hope that with my experiences I can document those things and help others who also aspire to become Macintosh software developers. Watch this site for more of my experiences.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cimgf.com/2008/04/19/from-hacker-to-microisv-app-names-and-icons/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
