<?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>Karl Kraft &#187; Karl Kraft</title>
	<atom:link href="http://www.karlkraft.com/index.php/author/admin/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.karlkraft.com</link>
	<description>Just a 2 bit programmer in a 64 bit world</description>
	<lastBuildDate>Thu, 24 Jun 2010 14:20:17 +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>How to Panic people in line for the iPhone 4G</title>
		<link>http://www.karlkraft.com/index.php/2010/06/24/how-to-panic-people-in-line-for-the-iphone-4g/</link>
		<comments>http://www.karlkraft.com/index.php/2010/06/24/how-to-panic-people-in-line-for-the-iphone-4g/#comments</comments>
		<pubDate>Thu, 24 Jun 2010 14:20:16 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[Flotsam and Jetsam]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=145</guid>
		<description><![CDATA[I arrived at the Apple store at The Domain in Austin this morning about 6:30.  The lines were so long there was no point in trying to get into line quickly, so I decided to spend a few minutes counting the number of people in line. As I went down the lines counting, I could [...]]]></description>
			<content:encoded><![CDATA[<p>I arrived at the Apple store at The Domain in Austin this morning about 6:30.  The lines were so long there was no point in trying to get into line quickly, so I decided to spend a few minutes counting the number of people in line.</p>
<p><span id="more-145"></span>
<p>As I went down the lines counting, I could not believe the amount of stress that I induced in those being counted.  People quickly began to worry about whether they were too far back in line to get a phone, or even if they were in the right line.  I was stopped about every 25 people asking what their number in line was. I had to explain over and over that I wasn&#8217;t counting for any purpose.</p>
<p>For the record, by the time 7 AM rolled around there were 700 total people in the two lines.  During that time I&#8217;m sure the line grew, because I started with the no-reservation line first, and then proceeded to the reserved line, which wound around the building in a different direction.  Between 7AM and 7:20, another 82 people showed up in the reserved line behind me.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2010/06/24/how-to-panic-people-in-line-for-the-iphone-4g/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mysql and Objective-C</title>
		<link>http://www.karlkraft.com/index.php/2010/06/02/mysql-and-objective-c/</link>
		<comments>http://www.karlkraft.com/index.php/2010/06/02/mysql-and-objective-c/#comments</comments>
		<pubDate>Thu, 03 Jun 2010 02:02:15 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[MySQL]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=137</guid>
		<description><![CDATA[In honor of Objective-C becoming a top-ten language, I&#8217;ve decided to share a library of source code I created to access MySQL. Over the past 2 years I&#8217;ve worked on a small bit of glue to make selects, updates, inserts and deletes work easily from Objective-C.  This includes support for converting MySQL types to Cocoa [...]]]></description>
			<content:encoded><![CDATA[<p>In honor of <a href="http://apple.slashdot.org/story/10/06/02/1930209/Objective-C-Enters-Top-Ten-In-Language-Popularity">Objective-C becoming a top-ten language</a>, I&#8217;ve decided to share a library of source code I created to access MySQL.</p>
<p><span id="more-137"></span>
<p>Over the past 2 years I&#8217;ve worked on a small bit of glue to make selects, updates, inserts and deletes work easily from Objective-C.  This includes support for converting MySQL types to Cocoa types, working correctly with garbage collection, and support for reading and writing large blobs.</p>
<p>It is possible to do all these things with the generic MySQL C connector, and if your needs are simple that can be a quick way to access a MySQL databases, since all C libraries can easily be called from Objective-C.  However, once you start dealing with more advanced topics, the C connector can become burdensome.</p>
<p>If you are working on intel platforms only, you should grab the intel only version.  This supports both 32 and 64 bit intel platforms, using version 6.0.2 of the MySQL C Connector.</p>
<p><a href="http://www.karlkraft.com/wp-content/uploads/2010/06/ObjC_mysql_intel.zip">ObjC_mysql_intel.zip﻿</a> 5.5 MB &#8211; 32/64 bit</p>
<p>I still have some client programs running on PPC boxes, but MySQL has dropped support for PPC based OSX﻿ in the most recent versions of the mysql_connector.  So I have an older version that I occasionally update, although not as often as the intel only version.  This version uses an older version (5.0.51a) of the MySQL C connector, and supports both 32 bit PPC and Intel platforms.</p>
<p><a title="ObjC_mysql_ppc.zip" href="http://www.karlkraft.com/wp-content/uploads/2010/06/ObjC_mysql_ppc.zip">ObjC_mysql_ppc.zip</a> ﻿2.3 MB &#8211; 32 bit intel and PPC.</p>
<p>Both versions use an identical syntax and are for the most part interchangeable.</p>
<p>﻿Both require that garbage collection be enabled in your application.  This means this version won&#8217;t support versions of iPhone OS that don&#8217;t include garbage collection. Which is pretty much all of them, as of the writing of this post.</p>
<p>Both include the headers and a static library for the MySQL C connector.</p>
<p>While I have used these libraries to process well over half a billion rows of MySQL data, they are not by any means guaranteed to be free of bugs.  The most recent fix was a leak in MysqlUpdate.  If you are interested in getting updates, subscribe to the <a href="http://www.karlkraft.com/index.php/category/mysql/feed/">MySQL Category Feed</a>, or <a href="mailto:karl@karlkraft.com?subject=MySQL SVN Access Request">email me</a> for access to the subversion repository for the project.</p>
<h1 style="font-size: 2em;">Adding to Your Project</h1>
<p>Once you have extracted the zip, add everything inside to your project.  The static mysql library will be linked into your application, and the headers and all the necessary bits to compile should just fall into place.</p>
<h3>Forming the connection</h3>
<p>You connect by creating an instance of MysqlConnection.  The best method for starting is</p>
<p> </p>
<pre>+ (MysqlConnection *)connectToHost:(NSString *)host
                              user:(NSString *)user
                          password:(NSString *)password
                            schema:(NSString *)schema
                             flags:(unsigned long)flags;
</pre>
<p>The best option for flags is MYSQL_DEFAULT_CONNECTION_FLAGS﻿</p>
<p>If you are connecting to a MySQL server that will kick you if inactive, call the method</p>
<pre>-[MysqlConnection startIdle]</pre>
<p>to start a low impact periodic select that will run once every 60 seconds.  Four additional methods add support for transactions</p>
<h3>Performing Selects</h3>
<p>Selects are pretty straight forward. Use MysqlFetch, and pass a SQL select command.  You can then look at the results property to get an array of dictionaries.  Each dictionary represents a single row.  They key will be the name of each column, and the value will be the Objective-C type that matches the column. If you aren&#8217;t sure of the names of the fields, you can look at the fields an fieldNames properties for more details.</p>
<pre>Example:
MysqlConnection *connection = [MysqlConnection connectToHost:@"serverName"
                                                        user:@"aUserName"
                                                    password:@"aPassword"
                                                      schema:@"myForumName"
                                                       flags:MYSQL_DEFAULT_CONNECTION_FLAGS];
MysqlFetch *userFetch = [MysqlFetch fetchWithCommand:@"select U_Number,U_Username from w3t_Users"
                                        onConnection:connection];
QLog(@"There are %d members",[userFetch.results count]);
for (NSDictionary *userRow in userFetch.results) {
  NSNumber *userNumber = [userRow objectForKey:@"U_Number"];
  NSString *userName = [userRow objectForKey:U_Username"];
  NSLog("%@ %@",userNumber,userName);
}
</pre>
<h3>Performing Deletes</h3>
<p>Deletes, inserts, and updates are very similar.  To perform a delete:</p>
<pre>
MysqlDelete *deleteCommand = [MysqlDelete deleteWithConnection:connection];
delete.tableName=@"w3t_Users";
delete.qualifier=[NSDictionary dictionaryWithObject:@"3" andKey:@"U_Number"];
[deleteCommand execute];
</pre>
<p>You can then look at the affectedRows property to find out how many rows were deleted.</p>
<h3>Performing Inserts</h3>
<p>Inserts allow you to insert NSString, NSNumber, NSData, and NSNull.  All other classes are converted using their -description method.  The insert code uses bindings instead of composing a SQL string, so you don&#8217;t need to worry about escaping special characters, or filtering user input.</p>
<pre>
MysqlInsert *insertCommand = [MysqlInsert insertWithConnection:connection];
insertCommand.table =@"w3t_Users";
NSData *picture = [NSData dataWithContentsOfFile:@"sample.png"];
NSString *password=@";'!#";
insertCommand.rowData=[NSDictionary dictionaryWithObjectsAndKeys:@"Karl Kraft",@"U_Username",
                                                          picture,@"U_UserImage"
                                                          password,@"UserPassword"
                                                          nil];
[insertCommand execute];
</pre>
<p>After the insert, you can get the auto increment rowid by using the rowid property on your MysqlInsert instance.</p>
<h3>Performing Updates</h3>
<p>Once you have mastered delete and insert, updates are a simple cross of the two.  Specify a qualifier, like you would for deletion, but rowData like you would use for an insert.  Only the specified fields in the rowData are modified.  Again you can pass NSString, NSNumber, NSData, and NSNull, and the values are inserted using bindings so that you don&#8217;t need to provide odd escapes.
<pre>
MysqlUpdate *updateCommand = [MysqlInsert insertWithConnection:connection];
updateCommand.table =@"w3t_Users";
updateCommand.qualifier=[NSDictionary dictionaryWithObject:@"3" andKey:@"U_Number"];
NSData *picture = [NSData dataWithContentsOfFile:@"sample.png"];
NSString *password=@";'!#";
updateCommand.rowData=[NSDictionary dictionaryWithObjectsAndKeys:@"Karl Kraft",@"U_Username",
                                                          picture,@"U_UserImage"
                                                          password,@"UserPassword"
                                                          nil];
[updateCommand execute];
</pre>
<p>Like delete you can query the affectedRows property to find out how many records were updated.</p>
<h3>Catching exceptions</h3>
<p>Any exceptions while performing the mysql commands are thrown as MysqlException or a subclass of MysqlException.  Common reasons for exceptions being throw are:</p>
<ul>
<li>Unable to connect to the database, or wrong username / password
<li>Commit or rollback fails
<li>Unsupported field type in a MysqlFetch
<li>Unqualified delete or update commands
<li>Any underlying mysql error
</ul>
<h3>MYSQL_LOGGING</h3>
<p>As a final useful trick you can define MYSQL_LOGGING in the CFLAGS of your project, or in a common header file, and useful debugging information will be generated.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2010/06/02/mysql-and-objective-c/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>iPad day one?</title>
		<link>http://www.karlkraft.com/index.php/2010/02/02/ipad-day-one/</link>
		<comments>http://www.karlkraft.com/index.php/2010/02/02/ipad-day-one/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 16:08:20 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[Flotsam and Jetsam]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=134</guid>
		<description><![CDATA[In a recent blog post, Marco Arment asked about the timing of iPad deployment. This is my response. Either I’m missing something, the initial iPad apps are going to suck, or we haven’t yet been told that iPad-native apps won’t be available for some period of time after the iPad’s launch. You are missing something. [...]]]></description>
			<content:encoded><![CDATA[<p>In a <a href="http://www.marco.org/366130089">recent blog post</a>, Marco Arment asked about the timing of iPad deployment.  This is my response.</p>
<p><em>Either I’m missing something, the initial iPad apps are going to suck, or we haven’t yet been told that iPad-native apps won’t be available for some period of time after the iPad’s launch.</em></p>
<p>You are missing something.</p>
<p><span id="more-134"></span><em>The problem, of course, is that before day one, we won’t have iPads ourselves for development and testing. This wasn’t a problem for iPhone development: by the time the SDK was released, we had all been using iPhones for many months. We knew how iPhone apps should look and behave, and we could test our apps on our iPhones during development for three months before anyone could sell apps to customers.</em></p>
<p>No, <strong>we</strong> didn&#8217;t.  You might have, but thousands of others were left out in the cold, unwelcome to develop for the iPhone.  Apple tightly controlled who they allowed in, and many didn&#8217;t get developer keys until months after the App Store was opened for business.  Yes, <strong>we</strong> could develop on the simulator, but not on the phone itself.  This preferential treatment continued with the release of later beta SDKs and Firmwares. The entire time this was going on Apple was very coy about what they were doing.</p>
<p>You have based your 3 possibilities on a bed of false assumptions.</p>
<p><strong>You have assumed that you can go to the local Apple Retail store, buy an iPad and install software.</strong></p>
<p>This is not supported in the current SDK.  At this point you can&#8217;t even compile code to the A4.</p>
<p>Apple hasn&#8217;t said when it will be supported.</p>
<p>Most importantly there is no guarantee that your current developer certificate will allow you to cryptographically sign and install software on the iPad at all.</p>
<p>Your certificate may work for iPhone and iPod touch only.</p>
<p>Apple may require a separate enrollment fee to get a iPad certificate.</p>
<p>Apple may limit iPad certificates to a select few developers.  This limitation may be temporary or permanent.</p>
<p><strong>You have assumed that Apple will accept iPad apps from you sometime on or before &#8220;day 1&#8243;.</strong></p>
<p>Apple has made no such commitment.  </p>
<p>They have committed to their future iPad users that iPad specific apps will be ready on day 1, but they haven&#8217;t committed to any developers (AFAIK) that they can submit them.  </p>
<p>When it comes to the AppStore, Apple is not a matchmaker helping developers connect to users in a frictionless manner.  It sure seems that way and as an indie developer I like the AppStore, but it is what it is, which is Apples playground.</p>
<p><strong>You have assumed that there is a submission queue.</strong></p>
<p>Developers like data structures like FIFO, and lots of them refer to the &#8220;submission queue&#8221; but I have never seen documentation from Apple that submissions are handled in a first come first served manner.  Anecdotal evidence seems to indicate that the are several submission piles, and they are serviced at different rates.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2010/02/02/ipad-day-one/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>The iSlate</title>
		<link>http://www.karlkraft.com/index.php/2010/01/13/the-islate/</link>
		<comments>http://www.karlkraft.com/index.php/2010/01/13/the-islate/#comments</comments>
		<pubDate>Wed, 13 Jan 2010 21:42:08 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[Flotsam and Jetsam]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=130</guid>
		<description><![CDATA[Been very busy with a new iPhone App, that and thinking about what the iSlate will be and how it will work. Rumor is that it will be an oversized iPhone, and run iPhone software. I&#8217;ve decided to run a contest to give one away. You can enter at http://www.relada.com/]]></description>
			<content:encoded><![CDATA[<p>Been very busy with a new iPhone App, that and thinking about what the iSlate will be and how it will work.  Rumor is that it will be an oversized iPhone, and run iPhone software.  I&#8217;ve decided to run a contest to give one away.  You can enter at <a href="http://www.relada.com/">http://www.relada.com/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2010/01/13/the-islate/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A tool for splitting app sales</title>
		<link>http://www.karlkraft.com/index.php/2009/10/29/a-tool-for-splitting-app-sales/</link>
		<comments>http://www.karlkraft.com/index.php/2009/10/29/a-tool-for-splitting-app-sales/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 16:02:44 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=119</guid>
		<description><![CDATA[For the past few months I have been using MyAppSales to track my day to day sales volume of my iPhone applications. In a recent update the developer, Oliver Drobnik aka Dr. Touch, added the ability to see your total sales. I have kept all the weekly sales reports going back to when my applications [...]]]></description>
			<content:encoded><![CDATA[<p>For the past few months I have been using <a href="http://www.drobnik.com/touch/my-app-sales/">MyAppSales</a> to track my day to day sales volume of my iPhone applications.  In a  recent update the developer, Oliver Drobnik aka Dr. Touch, added the ability to see your total sales. </p>
<p>I have kept all the weekly sales reports going back to when my applications were first available.  So I was hoping I would finally be able to see my grand total for each app.  The only problem is that the grand total is based on daily reports, not weekly reports.<br />
<span id="more-119"></span>So I created a small command line tool called <a href="http://www.karlkraft.com/wp-content/uploads/2009/10/SplitWeek.zip" title="SplitWeek.zip">SplitWeek</a> that would break each week file into 7 daily files.</p>
<p>Each sale is assigned randomly to one of the seven days in the weekly period, so there are no rounding errors.</p>
<p>Operation is simple.  Just run the command from Terminal, passing the path to the weekly file as the first argument:</p>
<pre>
<b>./build/Debug/SplitWeek reports/S_W_20080825.txt</b>
</pre>
<p>The 7 files will then be generated and saved to the current working directory.</p>
<pre>
2009-10-29 11:05:36.933 SplitWeek[53735:903] S_D_20080825.txt
2009-10-29 11:05:36.934 SplitWeek[53735:903] S_D_20080826.txt
2009-10-29 11:05:36.935 SplitWeek[53735:903] S_D_20080827.txt
2009-10-29 11:05:36.935 SplitWeek[53735:903] S_D_20080828.txt
2009-10-29 11:05:36.936 SplitWeek[53735:903] S_D_20080829.txt
2009-10-29 11:05:36.937 SplitWeek[53735:903] S_D_20080830.txt
2009-10-29 11:05:36.937 SplitWeek[53735:903] S_D_20080831.txt
</pre>
<p>Once you have created all your daily files, zip them up, and upload them to MyAppSales using the web server built in to the application.</p>
<p>And speaking of the built in web server, here is a quick tip on how to connect to it.  When you enable the server, it will show the IP and port you need to enter into Safari to connect.  In the screen shot here, I&#8217;m using the simulator, so it doesn&#8217;t even give an IP.</p>
<p><img src="http://www.karlkraft.com/wp-content/uploads/2009/10/MyAppSales_1.png" alt="MyAppSales_1.png" border="0" width="339" height="154" /></p>
<p>Instead of entering the IP and port, just use the Safari Bonjour support, and you will find it listed under Webpages.</p>
<p><img src="http://www.karlkraft.com/wp-content/uploads/2009/10/MyAppSales_2.png" alt="MyAppSales_2.png" border="0" width="175" height="248" /></p>
<p><img src="http://www.karlkraft.com/wp-content/uploads/2009/10/MyAppSales_3.png" alt="MyAppSales_3.png" border="0" width="307" height="178" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2009/10/29/a-tool-for-splitting-app-sales/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t use non mutable objects to understand leak detection</title>
		<link>http://www.karlkraft.com/index.php/2009/04/22/dont-use-non-mutable-objects-to-understand-leak-detection/</link>
		<comments>http://www.karlkraft.com/index.php/2009/04/22/dont-use-non-mutable-objects-to-understand-leak-detection/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 04:11:27 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[Debugging]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=116</guid>
		<description><![CDATA[This is a replay of a post I recently submitted to iPhoneSDK to explain why using non-mutable objects like NSString to learn leak detection is a bad idea. The original post by Robert Scott complained that this code wasn&#8217;t showing Leaks in instruments even though it should be leaking a NSString with every pass. Robert [...]]]></description>
			<content:encoded><![CDATA[<p>This is a replay of a post I recently submitted to iPhoneSDK to explain why using non-mutable objects like NSString to learn leak detection is a bad idea.</p>
<p>The original post by Robert Scott complained that this code wasn&#8217;t showing Leaks in instruments even though it should be leaking a NSString with every pass.</p>
<p><span id="more-116"></span><br />
Robert wrote:<br />
<em>So I guess there must be<br />
something fundamental I don&#8217;t understand about leaks because I don&#8217;t<br />
see why your examples cause leaks and this code does not:<br />
</em><br />
<code>
<pre>
  static int k;
  NSString *leakyString = [[NSString alloc]  initWithFormat:@"%1d", ++k] ;
  myLabel.text = leakyString;
</pre>
<p></code></p>
<p>The answer:</p>
<p>Because they aren&#8217;t leaks.  If you try to use NSString to learn about<br />
Objective-C memory management you will get burned over and over again,<br />
because it uses tons of behind the scene tricks. NSString is not a<br />
good place to learn to leak detection.</p>
<p>You are not the only one with references to those objects.  This is<br />
going to be long and involved, so get a cup of your favorite beverage,<br />
download the <a href="http://www.karlkraft.com/wp-content/uploads/2009/04/leaksampler.zip">example code</a> and cuddle up with Xcode:</p>
<p>First off make sure you are using Xcode 3.1.2 for this demo, with the simulator set for 2.2.1.  Effects may vary by platform and by version.</p>
<p><code>
<pre>
- (IBAction)pushMe:(id)sender;
{
  static int k;
  NSString *leakyString = [[NSString alloc]  initWithFormat:@"%1d", ++k] ;
//	myLabel.text = leakyString;
  NSLog(@"%@ %p %p",leakyString,leakyString,myLabel.text);
}
</pre>
<p></code></p>
<p>This code adds the printing of the pointers to leakyString and<br />
myLabel.text  For now the assignment to myLabel.text is commented<br />
out.  Run the code and watch the output of the debugger console.  You<br />
should get something like this:</p>
<p><code>
<pre>
2009-04-22 22:17:11.443 LeakSampler[27569:20b] 1 0xa03ca9f0 0x508540
2009-04-22 22:17:11.583 LeakSampler[27569:20b] 2 0xa03c3640 0x508540
2009-04-22 22:17:11.732 LeakSampler[27569:20b] 3 0xa03c9820 0x508540
2009-04-22 22:17:11.873 LeakSampler[27569:20b] 4 0xa03c8e20 0x508540
2009-04-22 22:17:12.013 LeakSampler[27569:20b] 5 0xa03c9dc0 0x508540
2009-04-22 22:17:12.153 LeakSampler[27569:20b] 6 0xa03ca520 0x508540
2009-04-22 22:17:12.294 LeakSampler[27569:20b] 7 0xa03c92a0 0x508540
</pre>
<p></code></p>
<p>Keep pushing until you get to:</p>
<p><code>
<pre>
2009-04-22 22:17:29.193 LeakSampler[27569:20b] 48 0xa03c9cd0 0x508540
2009-04-22 22:17:29.357 LeakSampler[27569:20b] 49 0x53e040 0x508540
2009-04-22 22:17:29.505 LeakSampler[27569:20b] 50 0xa03c7100 0x508540
2009-04-22 22:17:29.662 LeakSampler[27569:20b] 51 0xa03c6120 0x508540
2009-04-22 22:17:29.810 LeakSampler[27569:20b] 52 0xa03c4c30 0x508540
2009-04-22 22:17:29.958 LeakSampler[27569:20b] 53 0x5145d0 0x508540
2009-04-22 22:17:30.107 LeakSampler[27569:20b] 54 0xa03c99a0 0x508540
</pre>
<p></code></p>
<p>Note that for run 49 and 53 the results were different.  They are in a<br />
much lower section of memory.</p>
<p>Now use &#8220;Start with Performance Tool -> Leaks&#8221; and run the app.<br />
Repeat all the way up to 54, (You will have to use Console.app to<br />
watch the progress)</p>
<p>You should notice a few things.  The pointers for 1..54, except for<br />
for 49 and 53 were the EXACT same on this run.  The only items that<br />
show up as leaks are the entries for 49 and 53, which have the lower<br />
memory addresses.</p>
<p><code>
<pre>
4/22/09 10:19:35 PM LeakSampler[27582] 1 0xa03ca9f0 0x508570
4/22/09 10:19:36 PM LeakSampler[27582] 2 0xa03c3640 0x508570
4/22/09 10:19:36 PM LeakSampler[27582] 3 0xa03c9820 0x508570
4/22/09 10:19:36 PM LeakSampler[27582] 4 0xa03c8e20 0x508570
4/22/09 10:19:36 PM LeakSampler[27582] 5 0xa03c9dc0 0x508570
</pre>
<p></code></p>
<p>You might be tempted at this point to think Leaks doesn&#8217;t detect leaks<br />
with high memory addresses.  You would be wrong. Play some more.</p>
<p>Remove the comment for setting the label, and start again without<br />
Instruments.</p>
<p><code>
<pre>
- (IBAction)pushMe:(id)sender;
{
  static int k;
  NSString *leakyString = [[NSString alloc]  initWithFormat:@"%1d", ++k] ;
  myLabel.text = leakyString;
  NSLog(@"%@ %p %p",leakyString,leakyString,myLabel.text);
}
</pre>
<p></code></p>
<p>Note the first 5 lines of output.</p>
<p><code>
<pre>
2009-04-22 22:24:53.204 LeakSampler[27717:20b] 1 0xa03ca9f0 0xa03ca9f0
2009-04-22 22:24:53.939 LeakSampler[27717:20b] 2 0xa03c3640 0xa03c3640
2009-04-22 22:24:54.431 LeakSampler[27717:20b] 3 0xa03c9820 0xa03c9820
2009-04-22 22:24:54.790 LeakSampler[27717:20b] 4 0xa03c8e20 0xa03c8e20
2009-04-22 22:24:55.087 LeakSampler[27717:20b] 5 0xa03c9dc0 0xa03c9dc0
</pre>
<p></code></p>
<p>myLabel.text should be getting a copy of the string:</p>
<p><code>
<pre>
@property(nonatomic,copy)   NSString *text; //  default is nil
</pre>
<p></code></p>
<p>Yet the pointer for both leakyString and myLabel.text are exactly the<br />
same.  This is because NSString is non-mutable and copy of a non-<br />
mutable object can simply be replaced with a reference to the exact<br />
same object to reduce memory consumption.</p>
<p>Now a few more tests.  Instead of NSStrings, create NSMutableStrings</p>
<p><code>
<pre>
2009-04-22 22:27:06.118 LeakSampler[27739:20b] 1 0x50c450 0xa03ca9f0
2009-04-22 22:27:06.431 LeakSampler[27739:20b] 2 0x53e7b0 0xa03c3640
2009-04-22 22:27:06.508 LeakSampler[27739:20b] 3 0x518200 0xa03c9820
2009-04-22 22:27:06.898 LeakSampler[27739:20b] 4 0x526210 0xa03c8e20
2009-04-22 22:27:07.267 LeakSampler[27739:20b] 5 0x53ef00 0xa03c9dc0
</pre>
<p></code></p>
<p>Note that the mutable strings are in low memory, yet the copies have<br />
the same addresses as the very first run.  The addresses for the<br />
mutable strings will be different on each run as various other parts<br />
of the system allocate and release memory.</p>
<p>Now for the fun part.  Set a break point on the line that reads:</p>
<p><code>
<pre>
  static int k;
</pre>
<p></code></p>
<p>And fire up the program in GDB.  Press the button one time and at the breakpoint, before your call to initWithFormat:,  print the objects at the first five memory addresses that keep showing<br />
up:</p>
<p><code>
<pre>
(gdb) <strong>po 0xa03ca9f0</strong>
1
(gdb) <strong>po 0xa03c3640</strong>
2
(gdb) <strong>po 0xa03c9820</strong>
3
(gdb) <strong>po 0xa03c8e20</strong>
4
(gdb) <strong>po 0xa03c9dc0</strong>
5
</pre>
<p></code></p>
<p>The NSString objects that you thought were all yours, that you loving<br />
created with a clever call to initWithFormat:, turned out to just be<br />
filthy dirty replicants of NSStrings generated before your code even<br />
ran.</p>
<p>For fun, you can find some more strings that are already created:</p>
<p><code>
<pre>
(gdb) <strong>x/20x 0xa03c3640</strong>
0xa03c3640:	0xa03b84a0	0x000007c8	0x93c78a10	0x00000001
0xa03c3650:	0xa03b84a0	0x000007c8	0x93c80194	0x00000014
0xa03c3660:	0xa03b84a0	0x000007c8	0x93c801ac	0x00000002
0xa03c3670:	0xa03b84a0	0x000007c8	0x93c801b0	0x00000011
0xa03c3680:	0xa03b84a0	0x000007c8	0x93c801c4	0x00000001
</pre>
<p></code></p>
<p>Looks like tightly packed objects in a lookup table:</p>
<p><code>
<pre>
(gdb) <strong>po 0xa03b84a0</strong>
NSCFString
</pre>
<p></code></p>
<p>Yup, a bunch of NSCFString objects.  A quick examination shows this<br />
portion of the table to be:</p>
<p><code>
<pre>
(gdb) <strong>po 0xa03c3650</strong>
HelveticaNeue-Italic
(gdb) <strong>po 0xa03c3660</strong>
88
(gdb) <strong>po 0xa03c3670</strong>
orange_middle.png
(gdb) <strong>po 0xa03c3680</strong>
B
</pre>
<p></code></p>
<p>If you add this line of code what do you think you get?</p>
<p><code>
<pre>
NSLog(@"%p",[[NSString alloc] initWithFormat:@"%@",@"orange_middle.png"]);
2009-04-22 22:38:05.504 LeakSampler[27848:20b] 0xa03c3670
</pre>
<p></code></p>
<p>In Summary, I Repeat:  If you try to use NSString or other non-mutable objects to learn about<br />
Objective-C memory management you will get burned over and over again,<br />
because it uses tons of behind the scene tricks. NSString is not a<br />
good place to learn to leak detection.</p>
<p>As for why 49 and 53 aren&#8217;t in the table?  Well I think that is blindingly obvious once you think about it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2009/04/22/dont-use-non-mutable-objects-to-understand-leak-detection/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A drop-in replacement for NSLog()</title>
		<link>http://www.karlkraft.com/index.php/2009/03/23/114/</link>
		<comments>http://www.karlkraft.com/index.php/2009/03/23/114/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 16:41:58 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[TheCodeBook - Snippets]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=114</guid>
		<description><![CDATA[I recently saw this post on turning off NSLog for non-debug builds, and found it disappointing and inspirational at the same time. Scattering hundreds of #ifdefs around code is a recipe for disaster. Eventually some non debugging code will end up inside the #ifdef and the debug and release builds will function differently, making debugging [...]]]></description>
			<content:encoded><![CDATA[<p>I recently saw <a href="http://iphoneincubator.com/blog/debugging/how-to-create-conditional-log-statements-in-xcode"> this post</a> on turning off NSLog for non-debug builds, and found it disappointing and inspirational at the same time.  Scattering hundreds of #ifdefs around code is a recipe for disaster.  Eventually some non debugging code will end up inside the #ifdef and the debug and release builds will function differently, making debugging more difficult.</p>
<p>I&#8217;m not a big fan of debugging from log statements, but they can occasionally be useful.</p>
<p>What follows is details on building a full NSLog() replacement that turns off with a single #ifdef in the header file that contains the function.  You can either download the <a href="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-000.zip">m and h file</a>, or continue on to the extended entry for an explanation of how it works and ways to make it more useful for your particular needs.</p>
<p><span id="more-114"></span></p>
<p>Start with a basic Xcode Foundation Tool.  This will contain a main.m file that uses NSLog to print &#8220;Hello World!&#8221;<br />
<img src="http://www.karlkraft.com/wp-content/uploads/2009/03/xcode-001.png" alt="Xcode_001.png" border="0" width="300" height="255" /></p>
<pre>
  NSLog(@"Hello, World!");
</pre>
<p>The output will look like this:</p>
<pre>
  2009-03-23 10:57:13.619 DebugLog[11941:807] Hello, World!
</pre>
<p>Add a DebugLog.h and DebugLog.m to the file.  DebugLog.h should declare a method DebugLog() that will be the replacement for NSLog()</p>
<pre>
  void DebugLog(NSString *format,...);
</pre>
<p>And DebugLog.m should contain the implementation of that function. A particular item to note is that NSLog only adds a newline to the end of the NSLog format if one is not already there.  This function duplicates this feature of NSLog()</p>
<pre>
  void DebugLog(NSString *format,...) {
    va_list ap;
    va_start (ap, format);
    if (![format hasSuffix: @"\n"]) {
      format = [format stringByAppendingString: @"\n"];
    }
    NSString *body =  [[NSString alloc] initWithFormat: format arguments: ap];
    va_end (ap);
    fprintf(stderr,"%s",[body UTF8String]);
    [body release];
  }
</pre>
<p>You can <a href="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-001.zip" title="DebugLog_001.zip">download the project at this stage</a>.  If you play with the project at this point you will notice the output is different than NSLog().</p>
<pre>
  // With NSLog
  2009-03-23 11:01:32.936 DebugLog[12085:807] Hello, World!
  2009-03-23 11:01:32.938 DebugLog[12085:807] Hello, World!
  // With DebugLog
  Hello, World!
  Hello, World!
</pre>
<p>NSLog() includes the time, process name, process id and thread id as a prefix on every message.  I find this excessive in most cases, but you can add it in if you wish.  More on this later.</p>
<p>In the next version of the project, disable the function except for Debug builds.  Do this by editing DebugLog.h to have an #ifdef that turns DebugLog() into a macro, and rename the function from DebugLog to _DebugLog.  By using a #else we can disable DebugLog for any non DEBUG builds.</p>
<pre>
  #ifdef DEBUG
  #define DebugLog(args...) _DebugLog(args);
  #else
  #define DebugLog(x...)
  #endif
  void _DebugLog(NSString *format,...);
</pre>
<p>Rename the function in DebugLog.m as well.</p>
<pre>
  void _DebugLog(NSString *format,...) {
</pre>
<p>Finally, setup the build settings to include a DEBUG flag.  For more deatil or for iPhone configurations, see the <a href="http://iphoneincubator.com/blog/debugging/how-to-create-conditional-log-statements-in-xcode">the post that inspired this one.</a></p>
<p><img src="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-002.png" alt="DebugLog_002.png" border="0" width="250" height="300" /></p>
<p>Now try building both the Debug and Release version. Run from the command line, only the Debug version will produce the debug lines</p>
<pre>
  <strong>explorer:karl/tmp/DebugLog%</strong>./build/Debug/DebugLog
  Hello, World!
  <strong>explorer:karl/tmp/DebugLog%</strong>./build/Release/DebugLog
  <strong>explorer:karl/tmp/DebugLog%</strong>
</pre>
<p>Again, you can <a href="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-002.zip" title="DebugLog_002.zip">download the project at this stage</a>.  </p>
<p>Now take the function from better to best. By using some preprocessor directives we can embed the name of the file and line number where the DebugLog() is called, or have it print a function or method name.  </p>
<p>Change the macro definition and function declaration:</p>
<pre>
  #ifdef DEBUG
  #define DebugLog(args...) _DebugLog(__FILE__,__LINE__,args);
  #else
  #define DebugLog(x...)
  #endif
  void _DebugLog(const char *file, int lineNumber, NSString *format,...);
</pre>
<p>and change the fprintf() in the implementation to print the passed arguments:</p>
<pre>
  fprintf(stderr,"%s:%d %s",file,lineNumber,[body UTF8String]);
</pre>
<p>The output will now look like this:</p>
<pre>
  /Users/karl/tmp/DebugLog/main.m:15 Hello, World!
</pre>
<p>The __FILE__ is expanded to the complete path to the file, which is usually more verbose that I need.  It can be trimmed down to the actual file name by using an NSString method:</p>
<pre>
  ...
  NSString *fileName=[[NSString stringWithUTF8String:file] lastPathComponent];
  fprintf(stderr,"%s:%d %s",[fileName UTF8String],lineNumber,[body UTF8String]);
  ...
</pre>
<p>This will produce this output:</p>
<pre>
  main.m 15 Hello, World!
</pre>
<p></a>Again, you can <a href="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-003.zip" title="DebugLog_003.zip">download the project at this stage</a>.  </p>
<p>Finally, here is a more tricked out version that prints the function or method name instead of the file name, and prints the name of the thread.</p>
<pre>
  <strong>explorer:karl/tmp/DebugLog%</strong>./build/Debug/DebugLog
  MainThread/main (main.m:16) Hello, World!
  MainThread/+[SampleClass debugExample] (SampleClass.m:16) A sample debug message
  MainThread/-[SampleClass debugExample] (SampleClass.m:21) Another sample debug message
</pre>
<p>The final project <a href="http://www.karlkraft.com/wp-content/uploads/2009/03/debuglog-004.zip" title="DebugLog_004.zip">can be downloaded here</a>.  Stick the #import into your prefix header, and you can liberally sprinkle DebugLog commands all over your code.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2009/03/23/114/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Versions &#8211; &#8220;Waiting for transactions to finish&#8221;</title>
		<link>http://www.karlkraft.com/index.php/2009/02/10/versions-waiting-for-transactions-to-finish/</link>
		<comments>http://www.karlkraft.com/index.php/2009/02/10/versions-waiting-for-transactions-to-finish/#comments</comments>
		<pubDate>Tue, 10 Feb 2009 21:22:03 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[Flotsam and Jetsam]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=106</guid>
		<description><![CDATA[Every time I try to quit Versions it pops up an alert and says &#8220;Waiting for transactions to finish&#8221;. The alert will stay on the screen until I force quit Versions. This makes every reboot or logout a painful process. This has been driving me crazy for awhile now, so I looked into the problem [...]]]></description>
			<content:encoded><![CDATA[<p>Every time I try to quit Versions it pops up an alert and says &#8220;Waiting for transactions to finish&#8221;.  The alert will stay on the screen until I force quit Versions.  This makes every reboot or logout a painful process.</p>
<p>This has been driving me crazy for awhile now, so I looked into the problem and found a &#8220;solution&#8221;.  While I can&#8217;t vouch that it will work for everyone, I wanted to share it in the hopes that it might work for some.</p>
<p>This is going to be long so that everyone can understand the cause and possible soutions.</p>
<p><span id="more-106"></span></p>
<p>The problem firsrt showed up when I started using SVN 1.5.  I upgraded all my repositories on my linux and mac servers, and the mac server was working well, but the linux server would ocassionally just hang in Versions.  As part of the 1.5 upgrade there are some caches that you can either prebuild or build as needed, so I assumed the slowness was just those caches slowly being updated.</p>
<p>That was until this morning when I had the problem with a brand new empty repository.  I found that when Versions was running, access to the repository was slow even from the command line.  But if I wasn&#8217;t running Versions, performance was lightning fast from the command line.</p>
<p>It turns our the problem is related to the way SVN 1.5 uses random numbers.  On linux (and OS X), there are two sources of random numbers.  One is /dev/random, and the other is /dev/urandom.  /dev/random produces true cryptographically secure random numbers.  If there isn&#8217;t enough entropy available it will hang waiting for secure random numbers to become available.  urandom on the other hand will sacrafice cyrptographica quality and always produce random numbers.</p>
<p>Svnserve on my linux box uses /dev/random, and if the random numbers aren&#8217;t available it blocks until they are.  This in turn leads to Versions blocking waiting for svnserve to respond, which will happen eventually as sources of entropy like network traffic occur.</p>
<p>The problem is compounded when you turn on &#8220;Show Updates from Repository&#8221;.  For me this is the entire reason for having a program like Versions, so that I can keep track of what repositories I&#8217;m working with have experienced changes, so I can make sure my source stays up to date and that I&#8217;m aware of who is making what changes to the source.</p>
<p>The problem is that the SVN server doesn&#8217;t do much besides serve svn connections.  So there isn&#8217;t much entropy available. Eventually /dev/random runs out of random numbers and svnserve will hang, causing Versions to hang. Versions should be a bit smarter about realizing that if a request isn&#8217;t critical (like say a commit or update) that it can just terminate the connection on quit. </p>
<p>The solution is to either rebuild the Apache Portable Runtime library that svnserve from source and change it to use /dev/random instead of /dev/urandom. This would need to be done on the server.</p>
<p>The other choice is to simply remove /dev/random and replace it with the equivalent of urandom. This will affect all programs running on the server.</p>
<p>The commands are not for the faint of heart and can easily render the box unusable if done improperly.   These are for a Fedora Core 9 box, and won&#8217;t work on OSX or other platforms.  The commands must be run as root.</p>
<pre>rm /dev/random
mknod /dev/random c 1 9
chmod 666 /dev/random
</pre>
<p>For me, this has completely solved the problem of Versions hanging on quit, and I&#8217;m back to mostly happy with the product.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2009/02/10/versions-waiting-for-transactions-to-finish/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Yet another iPhone Emergency Call Security Bug</title>
		<link>http://www.karlkraft.com/index.php/2008/10/03/yet-another-iphone-emergency-call-security-bug/</link>
		<comments>http://www.karlkraft.com/index.php/2008/10/03/yet-another-iphone-emergency-call-security-bug/#comments</comments>
		<pubDate>Fri, 03 Oct 2008 14:15:22 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=105</guid>
		<description><![CDATA[iPhone Emergency Call has a security bug in the way it handles SMS messages]]></description>
			<content:encoded><![CDATA[<p>My twelve year old son brought to my attention a security bug he discovered on his iPhone.  He has an even more paranoid security mind than I do, because he primarily uses his iPhone to send and receive sweet nothings between himself and his girlfriend, and he is certain that his mother and I are desperate to intercept these messages.</p>
<p><span id="more-105"></span></p>
<p>Being security conscious he turned on the passcode lock and disabled SMS Preview.  </p>
<p>This screen shot shows the SMS preview disabled:</p>
<p><a href="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083337-0500-1.png"" ><br />
<img src="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083337-0500-1.png" alt="Screenshot 2008-10-03 08:33:37 -0500-1.png" border="0" width="160" height="240" /><br />
</a></p>
<p>This enables a mandatory passcode.  If a message is received during the passcode entry or while the screen is locked, a generic message of &#8220;New Text Message&#8221; appears, to prevent viewing of messages without unlocking the phone:</p>
<p><a href="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083308-0500-1.png"" ><br />
<img src="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083308-0500-1.png" alt="Screenshot 2008-10-03 08:33:37 -0500-1.png" border="0" width="160" height="240" /><br />
</a></p>
<p><a href="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083601-0500-1.png"" ><br />
<img src="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083601-0500-1.png" alt="Screenshot 2008-10-03 08:33:37 -0500-1.png" border="0" width="160" height="240" /><br />
</a></p>
<p>If however the phone is placed in emergency call mode, any incoming SMS messages are previewed instead of presented as the generic messages.  Thus all I need to do to intercept the messages from his girlfriend is to place the phone in emergency mode and wait 30 seconds for the next sickly sweet message.  </p>
<p><a href="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083736-0500-1.png"" ><br />
<img src="http://www.karlkraft.com/wp-content/uploads/2008/10/rowid-varchar12-screenshot-2008-10-03-083736-0500-1.png" alt="Screenshot 2008-10-03 08:33:37 -0500-1.png" border="0" width="160" height="240" /><br />
</a></p>
<p>This was in iPhone version 2.1 (5F136), the currently shipping version.  Since I have no access to beta of non-released firmwares I can&#8217;t test to see if it has been fixed since then.  For those how care, this is bug 6267416.  I don&#8217;t have much hope for it being fixed soon, because my security bug 5368148 from July of 2007 is still marked as open, and still unfixed in 10.5.5.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2008/10/03/yet-another-iphone-emergency-call-security-bug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HazMat &#8211; a Development Story</title>
		<link>http://www.karlkraft.com/index.php/2008/09/12/hazmat-a-development-story/</link>
		<comments>http://www.karlkraft.com/index.php/2008/09/12/hazmat-a-development-story/#comments</comments>
		<pubDate>Fri, 12 Sep 2008 20:57:42 +0000</pubDate>
		<dc:creator>Karl Kraft</dc:creator>
				<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.karlkraft.com/?p=100</guid>
		<description><![CDATA[A detailed story of the writing of HazMat with a spreadsheet full of numbers.]]></description>
			<content:encoded><![CDATA[<p>At the end of August my first iPhone application HazMat went on sale via the iTunes App Store.  During the past 6 months I have been having private conversations with various individuals about the development process and the resulting sales experience, and I thought it might be useful to others to collect this in a narrative about the application.  My goal is to give a full open view about the problems, pitfalls and pleasures of writing iPhone applications.</p>
<p>Send questions via <a href="mailto:karl@karlkraft.com">email</a></p>
<p>Those of you solely interested in my sales number can <a href="http://www.karlkraft.com/wp-content/uploads/2008/09/salesnumbers.zip" title="Sales.numbers.zip">check them here</a>.</p>
<p><span id="more-100"></span></p>
<h3>Background</h3>
<p>I have been writing Objective-C code since the early days of NeXTSTEP (20 years).  I work as a contractor and it is one of my many &#8220;day jobs&#8221;, along with system administration for LAMP systems, and a few other odds and ends.  I also have to deal with other languages like Java, Perl, Python, PHP, and so on.</p>
<p>Development on the iPhone is almost exclusively Objective-C.  You might think that I would have an extreme advantage, but honestly I don&#8217;t think so.  Objective-C is easy to pick up if you have any C based language development experience, including C++, C#, or even something like PHP.</p>
<p>Yes the syntax is different.  Every language has a different syntax, but it is all the same bits and pieces such as loops, conditionals, assignments, functions, etc.</p>
<p>Yes the framework is different, but then again, most of the iPhone UIKit framework is not a one to one match for the Cocoa AppKit framework. </p>
<p>So my Objective-C experience gave me a good start, but I know several people who have picked it up with little work, even when coming in with little to know serious programming experience.</p>
<p>I bought 2 iPhones on the day they were released and gave them as gifts to a client.  But with no development path I couldn&#8217;t see buying one for myself.</p>
<p>When jailbreaking became a real possibility and tool chains and documentation started to appear, I finally bought a phone for myself and my wife.</p>
<p>I paid tangental attention to the open source tool chain, and then when the October announcement of a pending real SDK came out, I set aside plans to build apps until the real SDK was released.</p>
<h3>Becoming an iPhone Developer</h3>
<p>As the SDK announcement approached, I began to track programs on other mobile platforms, and began to think of potential applications to write.  I also started to make guesses and observations about what the iPhone development ecosystem would be like.</p>
<p>In most cases I guessed right.  In quite a few I got it wrong, or I have no idea whether I&#8217;m right or wrong.  I&#8217;ll discuss that more later on.  But the important point is that if you want to have any kind of success as an iPhone developer you need to think about the future of the platform and be prepared for the change, because the iPhone ecosystem is still undergoing radical changes.  Items like push notification have been off, on, and off-again.</p>
<p>I felt that using my personal iPhone for day to day development probably wasn&#8217;t the best route, so I ordered another iPhone, and an iPod Touch as well.</p>
<p>I applied for the developer program right when it was announced.  In the first 2 weeks it seemed that no one was approved.  Then rumors of approval started to filter out, and the assumption was that Apple was processing them on some fair basis, such as first come first served, or approving ADC Premier members first.  Neither ended up being the case.  I was in the same boat as many other developers, with no idea why I wasn&#8217;t being approved, or what I could do to help the process.</p>
<p>I downloaded each version of the SDK, and worked on some early code. </p>
<h3>WWDC</h3>
<p>In 2007 I had attended WWDC, but now I found myself facing a dilemma.  I still hadn&#8217;t been accepted as an iPhone developer, and the primary reason to attend WWDC would be to learn more about iPhone development, and one-on-one interactions with Apple engineers about iPhone development.  I sent a note off to ADC about the problem with attending WWDC without being able to develop for the iPhone, and got the equivalent of a &#8220;just wait&#8221; notice.</p>
<p>At the time the simulator was even worse than it is now.  Major features like Open GLES simply did not work in the simulator, and those are the exciting aspects of the iPhone.  Given my background, getting to play with a simulated NSDictionary and some simulated buttons wasn&#8217;t something I would need help with at the WWDC level.</p>
<p>I ended up not attending WWDC.  A friend of mine (ADC Premier) got accepted as an iPhone developer less than 2 weeks before WWDC.  It was at this point that I started to really notice what I call the &#8220;If the guards have stopped my beatings, they must have stopped all the beatings of everyone else as well.&#8221; mentality.  His assumption was that since he had gotten his developer accepts, I must have gotten mine.  An alternate assumptions was that everyone going to WWDC was getting one. </p>
<p>Unfortunately neither was true.  I ended up getting mine a few days after July 11th when the App Store opened.  I know people who attended WWDC who got accepted even later than myself.</p>
<p>In general Apple did a poor job of communicating about the process of becoming an iPhone developer, and they are still doing a poor job.  And by communicating, I mean they are just not responding to some questions.  They seem to be trying to be deliberating opaque in their answers, walking a path around the truth instead of just explaining this clearly. </p>
<p>An example of this is the $99 fee for the Apple iPhone Developer program. Many are still confused as to whether this is an annual fee or one time fee.  As I have previously participated in Apple Developer programs, I was expecting it to be an annual fee.  But I still see new developers coming to the platform who aren&#8217;t sure, and the signup pages for the program are very unclear.  They just say &#8220;Standard Program $99&#8243;. </p>
<p>While Apple does have a press release that causally mentions it is a yearly fee, that doesn&#8217;t make it obvious, and one would think that if the question keeps coming up, Apple would be more active in addressing it on the iPhone Developer signup pages.  A $99 yearly fee should not be treated like a source of shame.</p>
<h3>An iPhone Developer</h3>
<p>Once I had been accepted as a developer I went through the process of generating the various keys, getting certificates, and provisioning profiles.  I had about 90% of the application written at this point, and I fired it up on the iPhone.</p>
<p>The results were not good.</p>
<p>Because the simulator runs at native Desktop speeds, it cannot be used to get an idea of the performance of your application.  And HazMat, which ran perfectly acceptably in the simulator was slower than molasses on an actual test device.</p>
<p>This is another one of those items were there just doesn&#8217;t seem to be any kind of pro active communication from Apple, and with the NDA still in effect, I&#8217;m discouraged from publishing my own experimental benchmarks that might help other developers get realistic expectations out of their product ideas.</p>
<p>But enough negativity.  Let&#8217;s talk about the development.</p>
<h3>HazMat Was Three Projects </h3>
<p>The first project was to gather and clean the raw data. This consisted of some data in spreadsheets, others in PDF files, and other in CSV files.  I had to clean up typos, oddities and the such and get the data into a common set of CSV files. </p>
<p>The second project was to take the CSV files and get them translated into a SQLite database.  This second project would lead me to discover errors in the first project, and I would cycle back and forth between the two projects.</p>
<p>The third project was the actual iPhone application which then reads the data from the SQLite database and displays the result.  This then lead to another revelation about the data needing to be massaged for performance and display quality.  About 30 commodities had very poor name choices.  For instance Gasoline is also called Gasohol,which while it is shorter is more confusing to United States users.  So I had to hand mark preferred names for certain commodities.</p>
<p>I also at this point started using the app myself, and learning more about particular usability features and performance.  A redesign was done for the detail display to break it into General Info, Fire, Spill, and First Aid instead of one long page. </p>
<p>I did the icon work myself using Photoshop and Adobe Illustrator.  A lot of images were based on inspiration from various Google image searches, and the App icon is based off a set of free HazMat placards done in Adobe Illustrator by <a href="http://ian-albert.com/misc/hazmat.php">Ian Albert</a>.  The original icon was a NFPA icon, but I ended up changing it when I pulled the NFPA data from the application.</p>
<p>Many items were pulled from the first version of the application, because I quickly saw HazMat becoming a huge time sink.  I perform development and system administration services as my livelihood, and I already knew at this point that HazMat would not only be a niche application, but probably the most niche application in the AppStore, and that meant a very small amount of income for a lot of work.  I decided it would be better to get a solid first version out, and then add more sections to the first screen as time went on.  That way it could continue to be a part time effort from me, that wouldn&#8217;t burn me out.</p>
<p>When it came to sales, I also had in mind a specific idea of how many units of HazMat whould actually sell.  Unlike a game or a productivity utility HazMat has a very narrow audience.  My estimate was 2-3 copies s day, with maybe a peak of 14 or so at the beginning.  I also formed a mental benchmark of 40 per day as the number at which I was wrong about my estimates.</p>
<h3>Pricing</h3>
<p>Based on my guess of 3 copies a day average, I guessed maybe a thousand copies in the first year. To recoup my actual time I would have to charge what I felt was an unreasonable amount of money.  I felt that while releasing it for free would result in a lot of people downloading the application it wouldn&#8217;t provide any benefit to me, not even a psychological boost. </p>
<p>While 99 cents was an option, I quickly saw it becoming the &#8220;price of crap&#8221; in the App Store.  Chris Rock tells a joke about minimum wage, in which he points out that</p>
<blockquote><p> &#8220;You know what that means when someone pays you minimum wage?  You know what your boss was trying to say? It&#8217;s like &#8220;Hey if I could pay you less, I would, but its against the law&#8221;.
</p></blockquote>
<p>So it is with the 99 cent price. It acts like a signal that the developer wants something, but that the application would be cheaper than 99 cents but Apple won&#8217;t let them charge less.  I understand the dilemma for Apple. It is hard to make profit on 10 cent internet sales that cost 25 cents to process. </p>
<p>In the end I decided to go with pure signaling with the application.  I choose the $3.99 price to signify that the application was a significant body of work designed for a specific audience.  I didn&#8217;t choose it to maximize revenue, or because I did great research, or to match price in other mobile devices.  I choose it as a pure signal.  I believed then and now that I would have the same number of sales of the app whether I priced at 99 cents or $7.99.  $3.99 just sent the right signal.</p>
<p>I would have considered 99 cents if there was a way to raise the price and charge for upgrades, where I could slowly raise the price as the value of the app increases.  But that isn&#8217;t an option in the AppStore and likely won&#8217;t ever be an option.</p>
<p>So in the final analysis, over the next 3 years, I might make $2.80 per copy, with about 3000 copies being sold.  That comes to $8,400.00 over 3 years.  That works out to PFV of about $7,500.00 which is about how much time I have put into the application.  I&#8217;ll probably put another $15,000.00 of work into the application over that same time period.  In short this application is a money loser, but a labor of love and a personal itch.  A hobby of time.</p>
<p>All of this was capped with me needing to actually get all the banking information setup in expectation of maybe getting an occasional wire transfer from Apple.  For such a small amount, I almost wish they would have given me the option of taking it in Apple Store credit.</p>
<h3>Submitting the App</h3>
<p>Submitting the app took a couple of tries.  Learning how codesigning work, and how to use the codesign command line utility is essential, because when Xcode is not setup correctly it will say the build succeeded even when it didn&#8217;t sign the application.</p>
<p>The ApplicationLoader used to submit the zip file also produces some cryptic and misleading error messages. On the positive side it does detect several common errors such as incorrect icon sizes, or invalid zip files.</p>
<p>I work on about two dozen Cocoa applications, so I have a common build and deployment script and practice, where all development builds have a DEVELOPMENT version number, and the build process changes the Info.plist in the app wrapper during deployment.  Those builds are done on an old G5 that I have stuck in a corner.  It regularly builds each svn repository, detects deployment versions, does the app-casting and so on.</p>
<p>However the G5 can&#8217;t build iPhone applications, and even though I have a half dozen Intel boxes, they are all in active use and not ready for corner of the closet retirement.</p>
<p>So I built the application by hand, and forgot to change the version from DEVELOPMENT to something else.  IIRC, the Application Loader detected this and rejected the binary and explained the version number was invalid.  So I changed it to &#8220;1&#8243;, and then rebuilt.  Unlike my other build process I can&#8217;t change it after it is built because the Info.plist is one of the signed resources.</p>
<p>I submitted version &#8220;1&#8243; and then waited.</p>
<p>About 2 days later my application still showed &#8220;Waiting for Upload&#8221;.  I have gotten the distinct impression that all the pieces of the App Store are not directly linked.  It seems common for people to report that their application says &#8220;Waiting for Upload&#8221; for hours after they upload and &#8220;In Review&#8221; even when it has gone on sale.  Again something I wish Apple would be clearer about.</p>
<p>But after 2 days I figured there might be a problem.  So I sent an email.  At about the same time, Apple was sending an email to me.</p>
<h3>Rejected</h3>
<p>The version number &#8220;1&#8243; is not allowed.  </p>
<p>Apple sent me a paragraph that detailed the requirement for version numbers, which basically requires they have a decimal point.  So &#8220;1.0&#8243; is valid, &#8220;1&#8243; is not.  Foolishly I figured that if Application Loader knew that &#8220;DEVELOPMENT&#8221; was not valid, it would have told me if &#8220;1&#8243; was invalid as well.</p>
<p>So I carefully read the rules and resubmitted with a date encoded version number &#8220;2008.08.18&#8243;.  Normally I don&#8217;t do this for OSX applications, but with the mandatory review process it is unlikely I will ever have 2 versions submitted on the same day.</p>
<p>So I submitted, and the next day checked.  &#8220;In Review&#8221;</p>
<p>And then waited, and waited.</p>
<p>Again, there is that feeling that maybe they forgot my application.  So everyday I would login, check, see the In Review, and then work on breathing and meditation exercises.</p>
<p>Finally in the early evening of August 29th , I got the email that my application had been approved and was now available for sale.  It still showed &#8220;In Review&#8221;, and I couldn&#8217;t find it in the App Store.  However I took them at their word and quickly worked up the web site, and a simple FAQ, and then waited.</p>
<p>Later that night I could finally find it in the US App Store, but not in some foreign stores.  My belief is that again the process is not a instant worldwide single button deployment, but rather a series of loosely connected systems.  I went to sleep happy.</p>
<p>The version posted to the store was the previously not allowed version number &#8220;1&#8243;. I would let Apple know, but who can I communicate with in a timely manner about this mistake that could possible solve it?</p>
<h3>The Sales, The Reviews, The Spreadsheet</h3>
<p>The next morning I got up and checked iTunes Connect to see whether I sold a copy. Incredibly I had sold 3 copies. Two in the US, and one in Canada.  Pretty much right on target.  I congratulated myself on my wonderful prediction.</p>
<p>I also started to notice reviews.  Two of the first reviews were complaints that it should have been free, and another that it was overpriced that it should have been 99 cents, but that I was basically smoking crack if I thought I would sell any copies at $3.99.  After some meditation and breathing exercises I got over it.  Rather than sock puppet a bunch of reviews, or post my own railing at their lack of understanding of capitalism and economics, I instead found solace in two items.</p>
<p>First, I clipped their comments down and posted them on my web site as endorsements.</p>
<p>Second, except for those pointless whining rants, the rest of the reviews were from people who like the app, and were mostly giving it five stars.  It seems I had hit an app that at least a few people wanted or appreciated.  I also got two emails from people expressing their pleasure with the application, and pointing out ideas for future versions.</p>
<p>The next morning, I logged into iTunes Connect to see how I did on my first full day of sales.</p>
<p>91 copies, with 76 in the United States.</p>
<p>That was a lot more than I was expecting.  I put it down to a big first day boost, and went back to work on other projects.  I was sure that by tomorrow it would be down to my previously mindset value of 14 or below, or at the most 40 or so, all depending on whether it was a quick crash or soft landing down to 3 copies.</p>
<p>Instead the next day it was 86 copies.  Still way larger than I expected.  Sales continued for the next several weeks to be higher than expected.  After 2 weeks I&#8217;m still not below 14 copies.  Instead I seem to have soft landed at about 25 copies a day.  I started watching and graphing the values on a Numbers spreadsheet.</p>
<p>That third day was August 31st.  I added up my sales to that point and realized that I had made $389.00 in royalties.  While not enough to retire on, it was still a pleasant surprise.  That meant that I should be getting a check for my two-ish days of sales in August.  From other posts I had heard that Apple takes about 10 days to settle on the sales, and then about 10-15 days later actual transfers the money.  The idea of getting a &#8220;check&#8221; at the end of September helped sooth the logical part of my mind that said this was not a business project but rather a hobby.</p>
<p>The total for the first 14 days is $1,541.23 of which about $278.43 is in miscellaneous foreign currencies that aren&#8217;t large enough for Apple to perform the wire transfer.</p>
<p>My expectations were and remain so low, that each day I wake up to gleefully check iTunes Connect for sales figures.</p>
<h3>The Check</h3>
<p>On September 10th, I got the email from Apple indicating that the actual financial reports for August payments were ready for download.  I expected that there might be a small discrepancy, but was interested in finding out how close to the $389.00 amount the payment would be.</p>
<p>The answer was a bit depressing.  No check.  No payment, $53 US sales.  And onesie-twosie sales in other regions. </p>
<p>I sent a note to the email address for the payment people.  For all my previous moaning above about the lack of communication with Apple regarding the development side, let me say that the payment and contracts people are the exact opposite. Every email I have sent them has been very quickly replied to, and questions are honestly and completely answered on the very first response.  That group seems to have the process down to machine like precision.</p>
<p>I had made 2 incorrect assumptions.  The first is that August meant 8/1 to 8/31. Apple doesn&#8217;t pay on calendar month, but rather on financial month (<a href="http://www.karlkraft.com/wp-content/uploads/2008/09/apple-fy08.pdf" title="Apple FY08.pdf">2008</a> <a href="http://www.karlkraft.com/wp-content/uploads/2008/09/apple-fy09.pdf" title="Apple FY09.pdf">2009</a>).  The contract and payments group was kind enough to send me the exact financial calendar they use.  Not only for this financial year, but next financial year as well.  For August of this year, the financial month was 8/3 to 8/30.</p>
<p>But even with the calendaring mistake I sold more than $53 worth on 8/30 alone.  My second mistake was in thinking that the delay from 9/1 to 9/9 in getting reports out was to settle all the outstanding credit card charges, since Apple doesn&#8217;t charge credit cards at the same time the end user downloads HazMat.</p>
<p>Instead that time is just for them to reconcile all the transactions.  So downloads on 8/30 are transactions, but only some of them are financial sales.  Those people who got credit card receipts via email on 8/30 count, those that Apple didn&#8217;t charge till 8/31 or 9/1 don&#8217;t count.</p>
<p>In the end, I&#8217;ll still get paid, just at the end of October instead of September.</p>
<h3>Bullets in Hindsight</h3>
<ul>
<li>I didn&#8217;t make a lot, but more than I thought, and it is nowhere near as I expected.
<li> Niche apps can sell on the store.  Even though Apple is promoting games, there are people who want other items.
<li> Was it better to write something niche that isn&#8217;t likely to be duplicated, or better to write something everyone can understand because it isn&#8217;t unique?
<li> I was in books.  This meant I stayed on the front page longer.
<li>The iPhone shows the first 5 apps without scrolling. iTunes shows the first 21.  Moving to number 6 didn&#8217;t decrease sales.  Moving to number 22 did.  More people buy on the desktop than on the phone.  However I dropped to #22 on 9/11, so can&#8217;t be sure if that was the contributing factor.
<li> Some of the people who downloaded my app probably have no interest in hazardous materials, but found the application to be appealing because of the sense of a source of &#8220;secret&#8221; information.
<li>Getting listed at the end of the month sucks.
<li>You will get bad reviews no matter want.  Don&#8217;t let the bozos get you down.
<li>The NDA didn&#8217;t stop me from writing code, but it does stop me from sharing 20 years of experience as it relates to this platform.
<li>There are lots of reasons to sit and whine about iPhone development, there are a thousand reasons to pound out the code.
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.karlkraft.com/index.php/2008/09/12/hazmat-a-development-story/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
