<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
    <title>iPhone in Action</title>
    
    
    <link rel="alternate" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/" />
    <id>tag:typepad.com,2003:weblog-1767228</id>
    <updated>2010-03-03T14:44:29-08:00</updated>
    <subtitle>Tutorials, classes, and other info on iPhone SDK programming.</subtitle>
    <generator uri="http://www.typepad.com/">TypePad</generator>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/typepad/iphone_in_action" /><feedburner:info uri="typepad/iphone_in_action" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
        <title>Core Data, Part 7: Lightweight Migration</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/mP4mZZpOls4/core-data-part-7-lightweight-migration.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2010/03/core-data-part-7-lightweight-migration.html" thr:count="0" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a8f48597970b</id>
        <published>2010-03-03T14:44:29-08:00</published>
        <updated>2010-03-03T14:44:29-08:00</updated>
        <summary>A how-to for doing lightweight migration of your Core Data model.</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="Common SDK Errors" />
        <category scheme="http://www.sixapart.com/ns/types#category" term="Core Data" />
        
        <category scheme="http://sixapart.com/ns/types#tag" term="core data" />
        <category scheme="http://sixapart.com/ns/types#tag" term="iphone" />
        <category scheme="http://sixapart.com/ns/types#tag" term="sdk" />
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml"><p>In a <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/errors-the-model-used-to-open-the-store-is-incompatible-and-other-core-data-errors.html">previous article</a>, I talked about the feared Core Data error, "The model used to open the store is incompatible". As I said at the time, it comes about when you've been running a Core Data program, then you go back and make a change to the underlying Data Model.</p>

<p>This is easy enough to fix when you're in development mode. As long as you don't care about losing the data you've entered into your program through use, just delete it on your testing device or in the Simulator by touching the app, waiting for it to shimmer, then hitting the "X". When you recompile, everything will work fine.</p>

<p>However, you can't do that once a program has been released. Fortunately, Core Data includes migration tools to help you get the database in your live program upgraded to match the updated model in your source. And, if you've made simple Model changes, the migration is called "lightweight", which means that it's almost entirely painless--as long as you know what you're doing, and this article should make sure you do.</p>

<p>Here's what you'll need to do:</p>

<p><strong>1. Verify that you can use lightweight migration.</strong></p>

<p>You can only use lightweight migration if you're doing a simple, obvious change to your data model. Fortunately, that includes adding a relationship or an attribute, and that's exactly what you'll be doing most of the time.</p>

<p>If you want to do more, that's beyond the scope of this article, but you can read the <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreDataVersioning/Introduction/Introduction.html#//apple_ref/doc/uid/TP40004403">Apple Documentation</a>.</p>

<p><strong>2. Add a new model version.</strong></p>

<p>Click on your data model, then choose "Design &gt; Data Model &gt; Add Model Version". Where you previously had an "xcdatamodel" file, you should now see an "xcdatamodeld" folder that contains your original "xcdatamodel", plus a new copy of it numbered with a "2". </p>

<p>For example, my "Money.xcdatamodel" was put into the "Money.xcdatamodeld" folder and cloned as "Money 2.xcdatamodel", as shown in the picture below.</p>

<p><strong>3. Make your changes.</strong></p>

<p><span style="font-style: italic;">You should not have made any changes prior to adding that new model version.<em> </em></span>If you did, this upgrade will NOT work.</p>

<p>Now that you've created a new model version, you should edit the new one, adding the attributions, relationships, or other simple updates that you want.</p>

<p><strong><a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c01310f5b3c39970c-pi" style="float: right;"><img alt="Model" border="0" class="asset asset-image at-xid-6a010535e1becf970c01310f5b3c39970c " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c01310f5b3c39970c-800wi" style="margin: 0px 0px 5px 5px; border: 1px solid black;" title="Model" /></a> 4. Change your current verison.<br /></strong></p>

<p>When you're all done, click on the new version, then select "Design &gt; Data Model &gt; Set Current Version". This will make it so that the new, updated version of your model is now the one being used by program.</p>
<p><strong>5. Update your persistentStoreCoordinator call.</strong></p>

<p>By default, Xcode should have created a persisentStoreCoordinator method for you when you created your project. You now need to modify that by adding two options which tell the coordinator to attempt a lightweight migration whenever it's run.</p>

<p>Here's the updated coordinator, from my Money program:</p>

<blockquote>
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {<br />    <br />    if (persistentStoreCoordinator != nil) {<br />        return persistentStoreCoordinator;<br />    }<br /><br />    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"Money.sqlite"]];<br />    <br />    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:<br />        [NSNumber numberWithBool:YES], <br />            NSMigratePersistentStoresAutomaticallyOption,<br />        [NSNumber numberWithBool:YES],<br />            NSInferMappingModelAutomaticallyOption,<br />        nil];<br />    <br />    NSError *error;<br /><br />    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] <br />        initWithManagedObjectModel: [self managedObjectModel]];<br /><br />    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType <br />        configuration:nil URL:storeUrl options:options error:&amp;error]) {<br /><br />        NSLog(@"Could Not Start Peristent Store: %@, %@", error, [error userInfo]);<br />    }    <br />    <br />    return persistentStoreCoordinator;<br />}</blockquote>
If you compare that to the original, you'll see two notable changes. First,an options dictionary is created with two objects, then options is passed as an argument to addPersistentStoreWithType: ...<br /><p><strong>5. Prefill Any Data</strong></p>

<p>You may now need to prefill the new attribute or relationship you created, to make sure that your data content catches up with the new data field. Here's a sample of some code I used in my Money program:
</p><blockquote>
-(void)upgradePath {<br /><br />    int upgradeV = [[cardDecks getOptionStringForKey:@"upgradeVersion"] intValue];<br />    <br />    if (!upgradeV || upgradeV &lt;= 1) {<br />        int cardBackNum = [[cardDecks getOptionStringForKey:@"cardBack"] intValue];<br />        NSString *thisBack = [self cardBackForInt:cardBackNum];<br />        <br />        [cardDecks setCardBacks:thisBack forType:nil];<br />        [cardDecks setOptionString:@"2" forKey:@"upgradeVersion"];<br />    }<br /><br />}<br /></blockquote>

<p>
Most of these method calls are internal to my own program. However, the general philosophy should be quickly adaptable. </p>

<p>First, you want to maintain some variable (probably in Core Data) that keeps track of how far you've updated your data to match your database. Here, if a user skips this version, but then downloads the next which has another data content change, he'll still be back at "upgradeVersion" 1, and so the program will know to do the 2nd upgrade as well as any newer ones.</p>

<p>Second, you want to fill your new relationship or attribute with some rational information. In this case, I went off and I set the "cardBack" (which was my new relation) for the entire deck to a standard cardBack selected by the user in an option file.</p>

<p>Your Mileage Will Vary, but the core ideas will be similar.</p>

<p />

<p><strong>6. Make clean.</strong></p>

<p>Before you recompile, do a "Build &gt; Clean All Targets". If you do not you may get the error, "Can't merge models with two different entities named 'Whatever'", followed by an annoying crash. </p><p><strong>Conclusion</strong></p><p>Once you've done a lightweight migration once, it should be simple and stress-free in the future. Just follow the same procedures.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2010/03/core-data-part-7-lightweight-migration.html</feedburner:origLink></entry>
    <entry>
        <title>Bringing Mü to the iPhone</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/xOeD-h2MJ1o/bringing-m%C3%BC-to-the-iphone.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2010/02/bringing-m%C3%BC-to-the-iphone.html" thr:count="2" thr:updated="2010-03-10T12:31:57-08:00" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0128775c7722970c</id>
        <published>2010-02-03T15:56:38-08:00</published>
        <updated>2010-02-03T16:13:17-08:00</updated>
        <summary>While working on Reiner Knizia's Money I had the privilege of speaking with designer Steve Blanding, who was working on bringing another popular card game, Mü, to the iPhone. Steve was kind enough to offer me an article on his...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        
        <category scheme="http://sixapart.com/ns/types#tag" term="card games" />
        <category scheme="http://sixapart.com/ns/types#tag" term="eurogames" />
        <category scheme="http://sixapart.com/ns/types#tag" term="iphone" />
        <category scheme="http://sixapart.com/ns/types#tag" term="programming" />
        
<content type="html" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;em&gt;While working on &lt;a href="http://click.linksynergy.com/fs-bin/stat?id=LCzSDs/1/VE&amp;offerid=146261&amp;type=3&amp;subid=0&amp;tmpid=1826&amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Freiner-knizias-money%252Fid349220571%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30"&gt;Reiner Knizia's Money&lt;/a&gt; I had the privilege of speaking with designer Steve Blanding, who was working on bringing another popular card game, Mü, to the iPhone. Steve was kind enough to offer me an article on his own design experiences on Mü, which I've printed below. If you're interested in playing the game, you can purchase &lt;a href="http://click.linksynergy.com/fs-bin/stat?id=LCzSDs/1/VE&amp;offerid=146261&amp;type=3&amp;subid=0&amp;tmpid=1826&amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Fmu%252Fid351448383%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30"&gt;Mü&lt;/a&gt; at the Apple iPhone store.&lt;/em&gt;

&lt;hr&gt;
&lt;h1&gt;Bringing Mü to 
	the iPhone&lt;/h1&gt;
	&lt;p&gt;by Steve 
	Blanding&amp;nbsp;&lt;/p&gt;
	&lt;p&gt;About a year and a half ago I had a Zune. I'd been given one as a gift 
	and my beloved iPod classic was broken. Microsoft had just released a free SDK 
	that let people write code for it. Being the geek I am, I thought it 
	would be a fun project to write a version of Mü that would run on my Zune. 
	My friends all thought I was crazy. Surely it wasn't possible to make a 
	good version of Mü on such a tiny, wimpy device! Nevertheless, I ignorantly 
	forged ahead and a few months later I had a version of Mü that not only 
	worked on the Zune, it worked surprisingly well! What I didn't have was a 
	license to distribute the game. The Zune games market being what it is 
	(non-existent) I didn't see much of a point. &lt;/p&gt;
	&lt;p&gt;Fast forward a 
	few months. My wife and I had just bought iPhones and suddenly I was looking 
	at some interesting possibilities. Unlike Zune, the iPhone has a very 
	vibrant games market. While I was pretty sure I wouldn't make any serious 
	money doing it (let's face it, the game is a little too complicated to 
	appeal to your average iPhone gamer) I recognized that there just might be a 
	market for an iPhone version of Mü; and besides, I wanted one for myself!&lt;/p&gt;
	&lt;p&gt;In this article 
	I'll discuss some of the challenges I had to overcome and some of the things 
	that I learned along the way.&lt;span&gt;&amp;nbsp; &lt;/span&gt;
	Perhaps you'll find it interesting. &lt;/p&gt;
	&lt;h2&gt;Becoming Legal&lt;/h2&gt;
	&lt;p&gt;The first hurdle 
	that I had to overcome was the fact that Mü is a copyrighted game. I didn't 
	really fancy the idea of stealing Frank Nestel's game and Doris Matthäus' 
	artwork so before I even started writing code I sent email to Dr. Nestel, 
	explained what I wanted to do, and asked if he would be interested in 
	licensing his game. Happily he replied in the affirmative. &lt;/p&gt;
	&lt;p&gt;I probably don't 
	need to tell you that the internet is a pretty wonderful thing. Thanks to 
	the magic of the internet, finding Frank's contact information was extremely 
	easy and we were able to handle pretty much everything via email. Still, 
	conducting international business is never without its challenges. He's in 
	Germany. I'm in Seattle. Luckily his English is way better than my German. 
	Negotiations went fairly quickly since we were both pretty enthusiastic from 
	the start but it still took quite some time to actually get a contract 
	signed. In the mean time, I had begun development in earnest.&lt;/p&gt;
	&lt;h2&gt;Preparing for 
	Development&lt;/h2&gt;
	&lt;p&gt;When this project 
	started, I hadn't used a personal computer made by Apple since the 1980s. 
	Since iPhone development requires a Mac, I had some shopping to do. I 
	decided that the cheapest and quickest way to get things going would be to 
	buy a used Mac Mini. My wife thought I was nuts when I spent most of a 
	Saturday driving to some stranger's house to buy one that he'd advertised on 
	Craig's List. It turned out to be a pretty good way to go though. I love the 
	portability of the machine and while it's not the fastest Mac out there, 
	it's more than powerful enough for iPhone development. &lt;/p&gt;
	&lt;p&gt;The other hurdle 
	I had to overcome was that I had to learn the development environment. 
	Luckily that didn't prove to be too difficult. Apple's on-line documentation 
	and videos are surprisingly good. If anything, there was too much 
	information. Objective C isn't my favorite language but it's not too bad. 
	I've never been much of a language bigot. Unfortunately, since Zune 
	development is typically done in C#, virtually none of the code that I'd 
	done for the Zune version could be used unaltered. I had to essentially 
	re-write the entire game from scratch. Still, that was probably a good 
	thing. It forced me to reevaluate most of the decisions that I'd made on the 
	first version and the result was a much stronger game.&lt;/p&gt;
	&lt;p&gt;I spent several weeks just pouring over Apple's documentation, trying to 
	learn the environment and absorbing as many of Apple's recommended best 
	practices as I could. I installed the SDK, I played around with sample code. 
	I familiarized myself with the environment. I watched scores of video 
	presentations. Looking back, I'm glad I did. All of that initial groundwork 
	would eventually pay off when I submitted Mü to Apple and they approved it 
	in just two days.&lt;/p&gt;
	&lt;h2&gt;Screen Size&lt;/h2&gt;
	&lt;p&gt;One major hurdle 
	that any developer has bringing anything to a portable platform such as the 
	iPhone is the small screen. The iPhone's 320x480 screen is pretty big for a 
	hand-held device (that's twice as many pixels as there were on my Zune) but 
	it's still pretty cramped. Furthermore, those pixels are crammed onto a 
	screen that's only 3 inches high so coming up with cards that are readable 
	becomes a huge challenge.&lt;/p&gt;
	&lt;p&gt;The cards 
	underwent several design changes. I started with raw scans of the original 
	cards shrunk down to 40x65 pixels. While that had worked OK on the Zune, 
	that turned out to be way too small for the iPhone so I started over, this 
	time with cards that were shrunk down to 44x70. That was still too small but 
	I couldn't really go much bigger and still leave room for bidding areas for 
	each player so I decided that I had to make some subtle changes to the card 
	design.&lt;/p&gt;
	&lt;p&gt;The first thing I did was get rid of most of the white border around each 
	card. I kept all of Doris' lovely artwork but made all of the elements on 
	each card just a little bit larger. The numbers were pushed a little bit 
	closer to the color bands and the color bands were enlarged so that they 
	more completely filled each card. That left me with virtual cards that 
	looked almost undistinguishable from the original cards but if you look 
	closely, you might notice that the numbers are actually a bit larger.&lt;/p&gt;
	&lt;p&gt;The next thing 
	that I did was dramatically over-saturate all of the colors on the cards. I 
	found that the original suit colors were far too difficult to distinguish 
	when reduced to those sizes. Over saturating and slightly altering all of 
	the colors made it much easier to tell blue from green from black.&lt;/p&gt;
	&lt;p&gt;I finally had 
	cards that were readable and still looked like Doris' originals but that 
	still wasn't good enough. The ornate numbers on the cards made them a little 
	difficult to read and one of my testers was really pushing for a solution 
	that was more friendly to the color-blind. I was really reluctant to abandon 
	any elements of Doris' card design but I finally realized that it had to be 
	done. Not wanting to completely abandon the traditional design, I left the 
	traditional cards in the game as an optional setting but the default card 
	set was changed to use the cleanest font I could find and different symbols 
	were used as the pips of each suit.&lt;/p&gt;
	&lt;div style="direction: ltr; text-align: center;"&gt;
		&lt;table style="direction: ltr; width: 323px; height: 117px; text-align: left; margin-left: auto; margin-right: auto;" valign="top" border="0" cellpadding="0" cellspacing="0"&gt;
			&lt;tbody&gt;&lt;tr&gt;
				&lt;td class="style1" style="padding: 4pt; vertical-align: bottom;"&gt;
				&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a85a2b20970b-pi" style="display: inline;"&gt;&lt;img  alt="Original colors" class="asset asset-image at-xid-6a010535e1becf970c0120a85a2b20970b " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a85a2b20970b-800wi" title="Original colors" border="0" /&gt;&lt;/a&gt; &lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;strong&gt;
				original colors&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;
				&lt;td class="style1" style="padding: 4pt; vertical-align: bottom;"&gt;
				&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c6ebe970c-pi" style="display: inline;"&gt;&lt;img  alt="Traditional cards" class="asset asset-image at-xid-6a010535e1becf970c0128775c6ebe970c " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c6ebe970c-800wi" title="Traditional cards" border="0" /&gt;&lt;/a&gt; &lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;strong&gt;
				traditional cards
				&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;
				&lt;td class="style1" style="padding: 4pt; vertical-align: bottom;"&gt;
				
				&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c6f6f970c-pi" style="display: inline;"&gt;&lt;img  alt="Default cards" class="asset asset-image at-xid-6a010535e1becf970c0128775c6f6f970c " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c6f6f970c-800wi" title="Default cards" border="0" /&gt;&lt;/a&gt; &lt;br&gt;&lt;div style="text-align: center;"&gt;&lt;strong&gt;
				final design
				&lt;/strong&gt;&lt;/div&gt;&lt;/td&gt;
			&lt;/tr&gt;
		&lt;/tbody&gt;&lt;/table&gt;
	&lt;/div&gt;
	&lt;h2&gt;Screen Layout&lt;br&gt;&lt;/h2&gt;
	&lt;p&gt; &lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c7478970c-popup" onclick="window.open( this.href, '_blank', 'width=640,height=480,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0' ); return false" style="float: right;"&gt;&lt;img  alt="Zune screenshot" class="asset asset-image at-xid-6a010535e1becf970c0128775c7478970c " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0128775c7478970c-250wi" style="margin: 0px 0px 5px 5px; width: 240px;" /&gt;&lt;/a&gt; The next 
	difficult decision I had to make was how to arrange all of the game 
	elements.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I had originally 
	thought that I would lay out the screen in landscape mode as I had done on 
	the Zune (&lt;strong&gt;right&lt;/strong&gt;) but the more I experimented with my mock-ups the more I began to 
	drift away from that decision. I realized that if I used the standard iPhone 
	OS elements of a navigation bar at the top and a status bar at the bottom, 
	I'd be left with a nearly perfect square in the center of the screen (&lt;strong&gt;below&lt;/strong&gt;). That 
	would give me a natural place to put menu icons and status text and allow me 
	to follow iPhone conventions as much as possible. Following iPhone 
	conventions would mean that users would feel more at home with the user 
	interface and it would also make it possible for me to use many of the 
	built-in features of the iPhone operating system.&lt;/p&gt;
	
	&lt;p&gt;I also realized 
	that when I hold my iPhone, it just feels more natural in the portrait 
	orientation. Landscape is fine for two-handed action games like shooters and 
	the like but for a card game, where one hand cradles the device and the 
	other hand is used to interact with the game, portrait mode just feels more 
	natural to me. That's a personal preference of course but hey, it's my game 
	so I get to do what I like.&lt;/p&gt;

	&lt;p&gt;&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a85a2e76970b-popup" onclick="window.open( this.href, '_blank', 'width=640,height=480,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0' ); return false" style="float: right;"&gt;&lt;img  alt="IPhone screenshot" class="asset asset-image at-xid-6a010535e1becf970c0120a85a2e76970b " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a85a2e76970b-250wi" style="margin: 0px 0px 5px 5px; width: 240px;" /&gt;&lt;/a&gt; Early in the 
	development process I realized one other unanticipated benefit of sticking 
	with portrait mode. I could use the iPhone's built-in accelerator functionality to 
	attach subordinate UI screens to the two landscape orientations. I 
	decided to use the left landscape orientation to display the summary cards 
	and the right landscape orientation to display a score sheet. &lt;/p&gt;
	&lt;p&gt;The game screen 
	can still get quite crowded because I had to make it possible to represent 
	the scenario where the maximum of six players have bid nearly all of their 
	cards, and I needed room for essential scoring information, player names, 
	link status and bidding feedback. Despite being a little crowded, I think it 
	works pretty well.&lt;/p&gt;
	&lt;p&gt;One request that 
	I've had from time to time is to display points taken during the current 
	hand while the hand is in progress. Early on I decided not to do that for a 
	number of reasons: first, it would be yet another set of numbers on an already 
	crowded screen; second, it's information that you normally would be required 
	to keep in your head during a real game; but third, and more importantly, if 
	you stop to think about it, it's not really very useful information. Think 
	about it. Are you really likely to change the way you play on a trick based on that 
	knowledge? Almost certainly not. You're going to try to give as many points 
	to your team as you can while keeping as many points away from your 
	opponents. It doesn't really matter if the bid is already made or not. The 
	only scenario where it might matter is if you've already got the result you 
	wanted and you're deciding whether to give a point card to a partner or 
	trying to keep it for yourself, and that scenario really isn't all that 
	important in the grand scheme of things. If you're the type of player for 
	whom that one or two points really matters, then you can track the points in 
	your head, just as you would have to do in a live game.&lt;/p&gt;
	&lt;h2&gt;Input Method&lt;/h2&gt;
	&lt;p&gt;Another 
	difficult, and perhaps somewhat controversial decision that I had to make 
	was to decide how the user would select, bid, and play cards.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;I looked at several different methods before finally making a choice.&lt;/p&gt;
	&lt;p&gt;The most obvious 
	method for playing a card would be simply to allow the player to touch the 
	card he wants to play. On its surface this seems like a good idea but I 
	quickly rejected it. Fat fingers touching tiny cards on a tiny screen are 
	not very precise. The cards are small enough that it is all too easy to 
	accidentally touch the wrong card. There are few things more frustrating 
	than playing a card by mistake. That clearly wasn't going to work.&lt;/p&gt;
	&lt;p&gt;Tapping a card 
	and dragging or flicking it to the middle of the screen worked a little 
	better but I still found it too easy to accidentally select the wrong card. 
	What I wanted was an input method that was very clear and as error free as I could 
	make it.&lt;/p&gt;
	&lt;p&gt;Eventually I 
	settled on an input method where the selected card is always shown in front of the 
	rest of the hand, making it very obvious which one is selected. If you've 
	got the wrong card you can tap on a different one or slide your finger to one side or the other 
	until you find the card you want. An arrow icon 
	appears above the selected card, further reinforcing the selection.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;Only after tapping on that icon is the card actually played to the 
	table. This extra step has seemed a little awkward to some but of all the 
	input methods that I experimented with, this one was by far the most error 
	resistant.&lt;/p&gt;
	&lt;p&gt;Bidding uses 
	exactly the same method except that instead of playing your card to the 
	trick, it pushes your card forward in a "marked for bidding" state.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;The icon above the card changes to a down arrow. Touch the down arrow 
	and the card will be pulled back into your hand.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;A second icon, pointing to your opponent, is used to lock in your bid 
	and yield control to the next player. This results in an input method that 
	is consistent across the entire game and very resistant to accidental taps, 
	touches or swipes. It may take a little bit of getting used to at first but 
	I remain convinced that it's the best solution.&lt;/p&gt;
	&lt;p&gt;From the start, I 
	disallowed selecting illegal cards but one of my testers suggested a 
	wonderful finishing touch: that I grey out or dim illegal cards, making it 
	easy to tell at a glance which cards are legal to play and which ones are 
	not.&lt;/p&gt;
	&lt;h2&gt;Artificial 
	Intelligence&lt;/h2&gt;
	&lt;p&gt;Of all the 
	obstacles that I had to overcome on this project, the AI was certainly the 
	most challenging. Mü is a very complicated game with a rich bidding mechanic. When I was doing the initial Zune version I did a lot of research 
	on the topic and I have to say that what I learned was not very encouraging. 
	After decades of research and development, computers are only just now able 
	to play a decent game of Bridge, and that's on a very powerful computer! 
	Card play isn't too terribly difficult but even that's not easy (witness all 
	of the really crappy Hearts games out there) but bidding! that's another 
	matter entirely. Getting bidding right is a notoriously hard problem.&lt;/p&gt;
	&lt;p&gt;Step one to 
	creating a good game of Mü is just to get the computer to play a hand 
	correctly. I didn't even think about bidding at the start. Card play is 
	complicated by the fact that trump changes dramatically from hand to hand, 
	as do partnerships, and the cards are not all worth the same amount of 
	points. That meant that a lot of the conventional optimization tricks that 
	are used to speed card play in a Bridge game just don't apply. I 
	had to come up with my own optimization techniques, based on some of what 
	I'd seen in Bridge implementations to be sure, but my own nonetheless.&lt;/p&gt;
	&lt;p&gt;The card play 
	logic in Mü (like most card games) is handled using something called a Monte 
	Carlo routine. In a Monte Carlo routine you start with all of the cards that 
	you know (because they've already been played or because they've been bid or 
	because they're in your own hand) and you randomly assign all of the others. 
	Then you play a number of tricks and you evaluate the outcome. Repeat that 
	process a number of times and whichever card gives the best results, that is 
	the card you play. It's a brute-force implementation that, given enough 
	random samples, and given that you play enough tricks ahead, will result in 
	optimal play. The problem is that on the iPhone we don't have nearly enough 
	computing power to evaluate enough tricks or samples to arrive at optimal 
	play so on top of this foundation I poured a little bit of secret sauce 
	that allows the computer to make slightly better than average choices 
	despite the very limited thinking time. The computer DOES NOT CHEAT but it 
	does get a little bit of help from my experience as a player. There isn't 
	enough time to really analyze the hand properly so it will occasionally make 
	a blunder or two but most of the time it gets it right and in my opinion, 
	that only serves to make the game a little more interesting and lifelike.&lt;/p&gt;
	&lt;p&gt;Bidding is a much 
	harder problem. At its core, it still works much the same way: you take a 
	whole bunch of random samples, you analyze them, and you make the choice 
	that seems to yield the best results. Unfortunately, if computing power was 
	scarce during card play, it's REALLY scarce during bidding so I had to take 
	a lot of short cuts.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Still, I 
	did manage to leave most of the bidding decisions up to the computer. It 
	analyzes the current bids to determine who it thinks is likely to be chief, 
	who is likely to be partner, who is likely to be vice, and what is likely to 
	be trump.&lt;span&gt;&amp;nbsp; &lt;/span&gt;At each stage in the 
	bidding it needs to decide if it should take chief, take vice, put itself on 
	the hook, position itself to be partner, or just pass. Every major decision 
	is made by playing a number of randomized hands to completion and deciding 
	what it thinks the score in a given situation is likely to be. It doesn't 
	take chief or vice unless it thinks there is a material advantage to doing 
	so within a given margin for error. Deciding what that margin for error 
	should be can be tricky. I probably played thousands of hands where the 
	computer played against me or against itself. I analyzed so many hands that 
	I got well and truly sick of looking at them but the results were worth it. 
	It still doesn't play perfectly but given the limitations of the hardware, 
	I'm very satisfied.&lt;span&gt;&amp;nbsp; &lt;/span&gt;The fact 
	that I can regularly lose to my own game is quite satisfying.&lt;/p&gt;
	&lt;h2&gt;Linked Play&lt;/h2&gt;
	&lt;p&gt;The final 
	challenge, and certainly a formidable one, was getting linked play to work. 
	I really wanted to be able to play a game with several human players, all 
	linked over the network. Getting there turned out to be a lot of work.&lt;/p&gt;
	&lt;p&gt;I immediately 
	discarded the idea of linking arbitrary iPhones over the internet. That 
	would require some sort of match-making service or dedicated server to 
	enable players to find one another and that was way beyond the scope of what 
	I was interested in doing.&lt;span&gt;&amp;nbsp; &lt;/span&gt;
	Instead, I focused on linking over Bluetooth. That had some immediate 
	advantages: first, it meant that I didn't also have to implement some sort 
	of chat facility because using Bluetooth implies that all players are within 
	shouting distance of one another; second, the iPhone v3.0 SDK has built in 
	matchmaking facilities for linking players over Bluetooth.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;The only real drawback there was that I wanted to be able to link 
	more than two players at a time and nowhere could I find any examples of 
	code that did that. I couldn't even find any games in the App Store that did 
	that. (I'm sure they must exist but I couldn't find any in my admittedly 
	short search.)&lt;/p&gt;
	&lt;p&gt;Once I'd figured out how to link multiple players, I still had other 
	challenges. Even though I had designed the game from the start with the 
	knowledge that I would be adding networked play, and even though I had 
	experience working on other networked games, I still found it more difficult 
	than I had anticipated. When you have two computers linked together, all 
	playing the same game, you need to be very careful that they both stay in 
	sync. Furthermore, 
	because they ARE separate computers, there is a built-in expectation that 
	they should both be able to be doing different things at the same time. For 
	instance, one player could be reviewing the score sheet while another player 
	is bidding. Keeping all of those states synchronized and dealing with the 
	fact that you could be getting messages (or not getting messages) from 
	another player at any time is really challenging. Despite all of my careful 
	planning, I still went through several builds where I was unable to play 
	more than a hand or two without encountering really strange behavior. 
	Players would play cards that had already been played. I'd end up with 
	multiple partners, or sometimes no partner at all. Cards would mysteriously 
	move about the screen. Good times.&lt;/p&gt;
	&lt;p&gt;That was 
	complicated further by the fact that none of my beta testers seemed to be 
	much help where multi-player games were concerned. Most of my beta testers 
	lived in different cities (or even countries) and therefore they couldn't 
	really test linked play. Luckily my wife and I both have iPhones and my son 
	has an iPod Touch so I was able to test linked play myself. My son and I 
	played a lot of games but I still wish we'd had a lot more time to test. I'm 
	keeping my fingers crossed that someone won't run into some really hideous 
	bug when playing with six humans all linked over Bluetooth.&lt;/p&gt;
	&lt;p&gt;There were some 
	other really interesting limitations imposed by the iPhone form factor. The 
	iPhone does not support running more than one application at once and your 
	application can be shut down at any time for any number of reasons. That 
	meant that the game had to be designed from the start to be able to save and 
	resume automatically and with a minimum amount of user interaction. &lt;/p&gt;
	&lt;p&gt;Furthermore, what 
	do you do if someone gets a phone call or a text message in the middle of 
	your linked game and he has to exit the game to answer it? How do you get 
	that player back into the game? And what if someone has to go home? Do you 
	force everyone to quit the game just because little Bobby's out past his 
	curfew? Clearly I needed to allow players to jump back into the middle of a 
	game in progress and I needed to allow the computer to fill in should 
	someone leave. Making that happen in a way that was as simple as possible 
	for the user was a bit of a challenge.&lt;/p&gt;
	&lt;h2&gt;Localization&lt;/h2&gt;
	&lt;p&gt;Both Frank and I 
	really wanted Mü to be available in more languages than just English. One of 
	the first things that Frank requested was that we do a German version. I was 
	completely on board with that idea, especially knowing that the German board 
	game market is so active, so from the start, I structured the game to allow 
	localization. That turns out to be really easy on the iPhone. The iPhone has 
	built-in facilities for separating localizable resources and bundling 
	multiple languages into the same application package. I also had past 
	experience with localization so I was aware of virtually all of the issues I 
	would come up against. From the start I made sure that any localizable 
	strings used the NSLocalizedString macros. I used icons instead of text 
	whenever it made sense to do so. I was also very careful to avoid writing 
	code that would build sentences from component phrases. That resulted in 
	some redundant strings here and there but it gave me the luxury of rewording 
	longer sentences if they became too long to fit on screen after localization 
	and it meant that localizers were always free to use the proper grammar.&lt;/p&gt;
	&lt;p&gt;I speak 
	Portuguese so I did a very rough Portuguese translation early on which I 
	used to work out any kinks in the process.&lt;span&gt;&amp;nbsp;
	&lt;/span&gt;Unfortunately, my Portuguese isn't good enough that I could release 
	THAT version of the game. It's currently being proof-read by a native 
	speaker to fix all of my many embarrassing mistakes.&lt;/p&gt;
	&lt;p&gt;All of the 
	in-game documentation (and there is quite a bit of it) is displayed using 
	the iPhone's wonderful built-in web controls so I was able to put it all in 
	html files which made localizing the rules and credits a breeze.&lt;/p&gt;
	&lt;h2&gt;Conclusion&lt;/h2&gt;
	&lt;p&gt;This was a 
	phenomenally satisfying project. I feel that I've produced a fantastic game 
	and I've learned a lot along the way. I can now play my favorite card game 
	during my commute! Will it prove to be financially profitable? That remains 
	to be seen but either way it was well worth the undertaking. Bringing a game 
	I love to the iPhone has been a reward unto itself.&lt;/p&gt;
	&lt;p&gt;Thanks for 
	reading. Now go play &lt;a href="http://click.linksynergy.com/fs-bin/stat?id=LCzSDs/1/VE&amp;offerid=146261&amp;type=3&amp;subid=0&amp;tmpid=1826&amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Fmu%252Fid351448383%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30"&gt;Mü&lt;/a&gt;!&lt;/p&gt;&lt;/div&gt;
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2010/02/bringing-m%C3%BC-to-the-iphone.html</feedburner:origLink></entry>
    <entry>
        <title>Creating a First iPhone Game: Output &amp; Input</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/Wm2nUr76hMo/creating-a-first-iphone-game-output-input.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2010/01/creating-a-first-iphone-game-output-input.html" thr:count="2" thr:updated="2010-01-25T16:09:15-08:00" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a7d8c788970b</id>
        <published>2010-01-20T23:00:00-08:00</published>
        <updated>2010-01-20T23:14:17-08:00</updated>
        <summary>Today we released our first complete iPhone game, Reiner Knizia's Money. It's a "Eurogame", which means that it's part of a stream of very intelligent game design that's been coming out of Germany (primarily) for the last 30 years. It's...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        
        <category scheme="http://sixapart.com/ns/types#tag" term="reiner knizia" />
        
<content type="html" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;Today we released our first complete iPhone game, &lt;a click.linksynergy.com="" fs-bin="" href="" http:="" stat?id="LCzSDs/1/VE&amp;amp;offerid=146261&amp;amp;type=3&amp;amp;subid=0&amp;amp;tmpid=1826&amp;amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Freiner-knizias-money%252Fid349220571%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30&amp;quot;" target="itunes_store"&gt;Reiner Knizia&amp;#39;s Money&lt;/a&gt;. It&amp;#39;s a &amp;quot;Eurogame&amp;quot;, which means that it&amp;#39;s part of a stream of very intelligent game design that&amp;#39;s been coming out of Germany (primarily) for the last 30 years. It&amp;#39;s full of games that are often quick to play, but have carefully designed mechanics, and allow for a lot of strategy. Depending on how you classify it, &lt;em&gt;Money&lt;/em&gt; is either a card game or an auction game. You&amp;#39;re trying to use money you&amp;#39;re dealt to earn more money, eventually collecting sets of the same currency to earn points.&lt;/p&gt;

&lt;p&gt;If you&amp;#39;ve enjoyed this blog, and want to see what one of our actual designs looks like, I encourage you to &lt;a href="http://click.linksynergy.com/fs-bin/stat?id=LCzSDs/1/VE&amp;amp;offerid=146261&amp;amp;type=3&amp;amp;subid=0&amp;amp;tmpid=1826&amp;amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Freiner-knizias-money%252Fid349220571%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30" target="itunes_store"&gt;buy a copy&lt;/a&gt;. We&amp;#39;re offering it for $1.99 until Sunday, after which we increase to our normal price of $2.99.&lt;/p&gt;

&lt;p&gt;With that crass commercialism out of the way, I&amp;#39;m now going to talk a bit about some of the decisions we made when putting together the game, as a guide to what you might want to consider in your own designs. This is going to be a code-free blog entry. My goal is to talk about higher-level design considerations, specifically on the topics of output and input, which together represent the foundation of the program. If you think the code for any section would be particularly interesting, leave me a note in the comments, and I&amp;#39;ll consider it for a future entry.
&lt;/p&gt;&lt;h3&gt;Choosing the Graphic System&lt;/h3&gt;
The first step in writing the game was figuring out how to represent the playing field and the cards. Clearly, they&amp;#39;d need to be drawn on the iPhone in some way, but there were several possibilities, including using Core Graphics to write directly to a view, designing with UIImageViews (or something similar), and going with a more complex language like OpenGL.

&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c012876f924e0970c-popup" onclick="window.open( this.href, &amp;#39;_blank&amp;#39;, &amp;#39;width=640,height=480,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0&amp;#39; ); return false" style="float: right;"&gt;&lt;img alt="Moneydesign1-2" class="asset asset-image at-xid-6a010535e1becf970c012876f924e0970c " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c012876f924e0970c-320wi" style="margin: 0px 0px 5px 5px; width: 320px;" /&gt;&lt;/a&gt; &lt;/span&gt;&amp;#0160;I believe that building with Apple&amp;#39;s core expertise is likely to benefit you in the long run, as it&amp;#39;s probably more likely to be upgraded and improved through future releases. Thus I threw out OpenGL pretty early.

&lt;/p&gt;

&lt;p&gt;However, I also didn&amp;#39;t want to use a higher-level class like UIImageView, because I was afraid it would create additional overhead, and that could really add up, as I&amp;#39;d have almost 70 cards on the screen in &lt;em&gt;Money&lt;/em&gt;. That left me with two potential middle grounds: creating each card as a UIView and creating each card as a CALayer of a UIView. To be honest, I&amp;#39;m still not certain how much of an efficiency difference either would have made, but since I know that every UIView is backed by a CALayer, clearly going with a UIView would have meant &lt;em&gt;something&lt;/em&gt; more in resource allocation. So I went with the simplest answer possible, the CALayer, which could be created as a sublayer of my main GameTableView.

&lt;/p&gt;

&lt;p&gt;Choosing an individual object--the CALayer--over something more kludgy--like scribbling card images directly onto the main rectangle of my GameTableView--also offered a few more advantages. First, I could directly access Core Animation--and that&amp;#39;s in fact how almost all the animations in the game are managed. Second, it abstracted things well, in the way that you&amp;#39;d expect from an object-oriented program. 

&lt;/p&gt;

&lt;p&gt;That meant that I could actually expand on Apple&amp;#39;s basic CALayer a bit, attaching more information to each object. And, I did. When I was done I&amp;#39;d created a subclass called CArdLayer which actually included a number of different CALayers (for the front and back of the card, plus some additional layers to brighten or darken the card) and several properties (most importantly, a tag, which let me uniquely identify the layer).

&lt;/p&gt;

&lt;p&gt;&lt;a href="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a7d8c35c970b-pi" style="float: right;"&gt;&lt;img alt="Moneydesign2-1" border="0" class="asset asset-image at-xid-6a010535e1becf970c0120a7d8c35c970b " src="http://iphoneinaction.manning.com/.a/6a010535e1becf970c0120a7d8c35c970b-800wi" style="margin: 0px 0px 5px 5px;" title="Moneydesign2-1" /&gt;&lt;/a&gt; Just having all of those cards shuffling around as sublayers of a UIView did most of what I wanted. It allowed me to represent a card game. However late in the process I ran into one other problem: I wanted to create some popups and other information that would &lt;em&gt;always&lt;/em&gt; appear above my cards. 

&lt;/p&gt;

&lt;p&gt;I discovered that I couldn&amp;#39;t guarantee the position of layers relative to each other, but it was a pretty simple matter to instead break out two subviews from my GameTableView and keep the cards on the lower view and the info on the higher one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Figure 1-1&lt;/strong&gt; shows how these various objects ended up laying out in relation to one another.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before I close out, I should offer one final caveat about my graphic design. There turned out to be some performance problems with the display of my 70 cards, which makes them slower than I wanted when animations like dealing ran on my actual iPhone. My colleague noted that he&amp;#39;d read about some people moving over to OpenGL as a result of similar problems.

Fortunately, the performance problems turned out to be related only to 1st generation iPhones, which is what I was testing on. The GPUs on everything newer offered very sprightly animation speeds. So though I&amp;#39;m still not thrilled that 1st-gen iPhones go slower than I&amp;#39;d like, I can now see that it&amp;#39;s an issue that affects just a fraction of the user base, and one getting smaller day by day. So for the moment I feel confident in my decision about how to display things graphically, as I go forward.&lt;/em&gt;

&lt;/p&gt;&lt;h3&gt;Designing the Touch Interface&lt;/h3&gt;
Now that I knew how I was going to display the output of the game, I needed to figure out how to manage the input. That meant building touch interfaces as described on pages 240-252 of &lt;em&gt;iPhone in Action&lt;/em&gt;.

&lt;p&gt;I don&amp;#39;t find the code itself that interesting. It builds out of touchesBegan:withEvent:, touchesEnded:withEvent:, and touchesMoved:withEvent: as you&amp;#39;d expect. Beyond that it&amp;#39;s a rat&amp;#39;s nest of conditionals to support three different types of touches for active cards (card selection, card movement, and deck movement--only two of which are used in this particular game) and touches for &amp;quot;nonactive&amp;quot; cards (e.g., actions for decks other than the one you&amp;#39;re currently holding), both over multiple game phases.

&lt;/p&gt;

&lt;p&gt;However, I do think the &lt;em&gt;design&lt;/em&gt; of the big-picture input is more interesting, and so that&amp;#39;s what I&amp;#39;m going to talk about here.

&lt;/p&gt;

&lt;p&gt;When designing the input of &lt;em&gt;Money&lt;/em&gt;, I set two major goals:
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every object must do &lt;em&gt;something&lt;/em&gt; when touched, to create a playing space that feels alive and three-dimensional.
&lt;/li&gt;
&lt;li&gt;The UI must be consistent.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These goals haven&amp;#39;t been entirely fulfilled in the first release of &lt;em&gt;Money&lt;/em&gt;, but the framework is there, which will allow for self-consistent expansion if the game does well enough to warrant more work.

&lt;/p&gt;

&lt;p&gt;To accomplish the second goal, of consistency, I broadly defined four types of input. As you&amp;#39;ll see, when I had this rich set of gestures in hand, I could then assign actions to most objects on the screen.
&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;tap-and-release&lt;/strong&gt; could be used to simultaneously select multiple objects. In &lt;em&gt;Money&lt;/em&gt; you bid with your cards by selecting several of them, one at a time, then clicking a &amp;quot;bid&amp;quot; button to mark that you&amp;#39;re done.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tap-drag-and-release&lt;/strong&gt; could be used to move one object to another, initiating an action. In &lt;em&gt;Money&lt;/em&gt; this is used to drag your completed bid to an available set of money, exchanging them.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;tap-and-hold&lt;/strong&gt; could be used to view information on an object. In &lt;em&gt;Money&lt;/em&gt;, this is what allows for actions to occur on most &amp;quot;non-active&amp;quot; cards on the screen. For example, touching an opponent&amp;#39;s deck tell you their win-loss stats, touching an opponent&amp;#39;s bid makes it easier to see, and touching the draw deck tells you (approximately) how many cards are left.
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;double-tap&lt;/strong&gt; could be used to initiate a default action for an object. This is not coded into the game yet, but in a future revision you&amp;#39;ll be able to continue to tap-drag-and-release to exchange your bid with an available set of money, or you can alternatively double-click on an available set of money to do so automagically.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The trick of overloading this many input functions is making sure that they don&amp;#39;t bash into each other. For the purposes of &lt;em&gt;Money&lt;/em&gt;, all of the single-tap functions are singular: no object supports more than one of them, and the interface strives to make it obvious which you&amp;#39;d want to use on each place. tap-and-release and tap-drag-and-release are only used for manipulating your active deck of cards while tap-and-hold are only used for revealing information on other objects.

&lt;/p&gt;

&lt;p&gt;Implementing the double-taps is a bit trickier, because it means you need to slightly delay your single-tap results, so that they don&amp;#39;t show up when a double-tap is intended. That&amp;#39;s the main reason that they haven&amp;#39;t gone into the game yet.

&lt;/p&gt;

&lt;p&gt;However, as soon as they do, I think we&amp;#39;ll make an intuitive interface even stronger, and that we&amp;#39;ll be creating a model of interactivity that we can continue using across similar games.

(There are also still a few objects that don&amp;#39;t have touch-and-hold info--namely the two lots, our game logo, and our score info--mainly because we&amp;#39;re still thinking about the best info to include for each.)
&lt;/p&gt;&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;So those are my thoughts on how we designed input and output for our first iPhone game. I&amp;#39;m considering a future article talking about how we designed the game infrastructure. In the meantime you can read a companion article on what was specifically required to &lt;a href="http://www.boardgamenews.com/index.php/boardgamenews/comments/turning_reiner_knizias_money_into_an_iphone_game/"&gt;adapt an existing game&lt;/a&gt; over at BoardGameNews.com.

&lt;/p&gt;

&lt;p&gt;And finally I&amp;#39;ll again encourage you to &lt;a href="http://click.linksynergy.com/fs-bin/stat?id=LCzSDs/1/VE&amp;amp;offerid=146261&amp;amp;type=3&amp;amp;subid=0&amp;amp;tmpid=1826&amp;amp;RD_PARM1=http%253A%252F%252Fitunes.apple.com%252Fus%252Fapp%252Freiner-knizias-money%252Fid349220571%253Fmt%253D8%2526uo%253D6%2526partnerId%253D30" target="itunes_store"&gt;buy a copy&lt;/a&gt; of &lt;em&gt;Reiner Knizia&amp;#39;s Money&lt;/em&gt; if you&amp;#39;re interested. I hope that knowing a bit about how it was designed will help you enjoy the game that much more!&lt;/p&gt;&lt;/div&gt;
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2010/01/creating-a-first-iphone-game-output-input.html</feedburner:origLink></entry>
    <entry>
        <title>2009 Table of Contents</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/PivhA7ukjtQ/2009-table-of-contents.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2010/01/2009-table-of-contents.html" thr:count="0" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c012876b547b0970c</id>
        <published>2010-01-07T13:07:04-08:00</published>
        <updated>2010-01-07T13:07:04-08:00</updated>
        <summary>A table of contents listing all of the iPhone tutorial, class recipes, and other articles from the first year of the iPhone in Action blog.</summary>
        <author>
            <name>iPhone in Action</name>
        </author>
        
        <category scheme="http://sixapart.com/ns/types#tag" term="iPhone" />
        
<content type="html" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;2009 not only saw the actual publication of &lt;em&gt;&lt;a href="http://www.manning.com/callen/"&gt;iPhone in Action&lt;/a&gt;&lt;/em&gt;, but also the posting of many (hopefully) helpful articles here, on the &lt;em&gt;iPhone in Action&lt;/em&gt; blog. To help make those articles continually useful and accessible, this article supplements our tags by organizing all of the articles based on where they would have appeared if published in the &lt;em&gt;iPhone in Action&lt;/em&gt; book. A few things are listed in multiple places.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chapter 2: Web Development or the SDK&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/presentation-web-development-or-sdk.html"&gt;Presentation: Web Development or SDK&lt;/a&gt;: A slide show derived from chapter 2 of our book.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 7: Building Web Apps with Dashcode&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/07/dashcode-setcurrentviewwithtransition.html"&gt;Dashcode: setCurrentViewWithTransition&lt;/a&gt;: A simple transition animation in Dashcode. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 9: SDK Programming for Web Developers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/all-about-casting.html"&gt;All About Casting&lt;/a&gt;: About casting generally, and how it relates to some of Objective-C's multiple families of classes.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 10: Learning Objective-C and the iPhone OS&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/create-delegate-protocols-for-the-iphone.html"&gt;Creating Delegate Protocols for the iPhone&lt;/a&gt;: How to create your own delegate protocol. (Sometimes the article title just explains itself.) &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 11: Using Xcode&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/11/the-iphone-simulator-performance.html"&gt;The iPhone Simulator &amp;amp; Performance&lt;/a&gt;: How the iPhone Simulator can give you too good a view of your app. &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/errors-no-provisioned-iphone-os-device-is-connected.html"&gt;Errors: No Provisioned iPhone OS Device is Connected&lt;/a&gt;: An annoying error when trying to build to a device.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/05/problems-cant-build-clean.html"&gt;Problems: Can't Build &amp;gt;&amp;gt; Clean&lt;/a&gt;: When the "Build Clean" option doesn't show up. &lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 13: Creating Basic View Controllers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/table-tricks-tips-part-one-the-contentview.html"&gt;Table Tricks &amp;amp; Tips, Part 1: The ContentView&lt;/a&gt;: How to create a Settings-like table (now somewhat redundant due to new capabilities introduces in 3.0; overall this is the series of articles impacted most by 3.0 and by later correction, so read with care).&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/table-tricks-tips-part-two-clickable-accessories.html"&gt;Table Tricks &amp;amp; Tips, Part 2: Clickable Accessories&lt;/a&gt;: So how can you click those checkmarks? Several so-so answers.&lt;/li&gt;
&lt;li&gt;&amp;nbsp;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/table-tricks-tips-part-three-beautiful-tables.html"&gt;Table Tricks &amp;amp; Tips, Part 3: Beautiful Tables:&lt;/a&gt; How to create multicell table cells from scratch--and how to use color. (Some of this is made easier in 3.0, but sometimes you'll still need to go back to the basics, as described here.)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/05/table-tricks-tips-part-3b-contentview-cell-images-done-right.html"&gt;Table Tricks &amp;amp; Tips, Part 3B: Content View and Cell Images Done Right&lt;/a&gt;: Some corrections to the code in parts one and three.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/05/table-tricks-tips-part-four-editing-tables.html"&gt;Table Tricks &amp;amp; Tips Part 4: Editing Tables&lt;/a&gt;: How to use the delegates that support table editing. (Of the table articles, this one remains the most relevant.) &amp;nbsp; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/table-tricks-for-iphone-os-30.html"&gt;Table Tricks for iPhone OS 3.0&lt;/a&gt;: A look at the multiple sorts of table cells available in 3.0.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/07/beauti.html"&gt;Beautiful Section Heads&lt;/a&gt;: More table tricks to make sections look nicer. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 14: Monitoring Events and Actions&lt;br&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/uiactionsheet-part-one-alternate-user-input.html"&gt;UIActionSheet, Part 1: Alternate User Input&lt;/a&gt;: Another way to accept input from users. &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/uialertview-part-one-the-basics.html"&gt;UIAlertView, Part 1, The Basics&lt;/a&gt;: Another method for accepting simple, action-based input.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/uialertview-part-two-the-complexities.html"&gt;UIAlertView, Part 2, The Complexities&lt;/a&gt;: Expanding the above with buttons and delegation.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/creating-a-uitextfield-by-hand.html"&gt;Creating a UITextField ... by Hand&lt;/a&gt;: Some quick notes on using alloc/init instead of Interface Builder. &lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 16: Data: Actions, Preferences, Files, SQLite, and Addresses&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/07/skdatabase-11-a-sqlite-library-for-the-iphone.html"&gt;SKDatabase 1.1: A SQLite Library for the iPhone&lt;/a&gt;: An SQL library, offered with no guarantees.&lt;br&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/errors-sqlite3-database-doesnt-remain-updated.html"&gt;Errors: SQLite3 Database Doesn't Remain Updated&lt;/a&gt;: How file locking can mess up your SQLite db.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-1-an-introduction.html"&gt;Core Data, Part 1: An Introduction&lt;/a&gt;: Introducing the next generation of data storage.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html"&gt;Core Data, Part 2: The Data Model&lt;/a&gt;: How Core Data models its data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-3-retrieving-data.html"&gt;Core Data, Part 3: Retrieving Data&lt;/a&gt;: How to get data out of Core Data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-4-inserts-updates-deletes.html"&gt;Core Data, Part 4: Inserts, Updates &amp;amp; Deletes&lt;/a&gt;: How to put data into Core Data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-5-prefilling-data.html"&gt;Core Data, Part 5: Prefilling Data&lt;/a&gt;: How to insert data in advance. &amp;nbsp; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/10/core-data-part-six-theres-more-than-one-way-to-do-it.html"&gt;Core Data, Part 6: There's More than One Way to Do It&lt;/a&gt;: Moving away from the SQL paradigm.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-two-core-data-integration.html"&gt;NSSet, Part 2: Core Data Integration&lt;/a&gt;: How NSSets work directly with Core Data.&amp;nbsp; &lt;br&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/errors-the-model-used-to-open-the-store-is-incompatible-and-other-core-data-errors.html"&gt;Errors: The Model Used to Open the Store is Incompatible (and other Core Data Errors)&lt;/a&gt;: A common Core Data error, concerning changing data models. &lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter 19: Graphics: Quartz, Core Animation, and OpenGL&lt;br&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/02/thinking-about-user-interface.html"&gt;Thinking About User Interface&lt;/a&gt;: How to build within Apple's interface paradigm.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/animating-sublayers.html"&gt;Animating Sublayers&lt;/a&gt;: How to animate sublayers instead of views. &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/creating-a-splash-screen-part-three.html"&gt;Creating a Splash Screen, Part 3&lt;/a&gt;: Part of the splash screen class recipe (see Appendix E) that contains an example of animation.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/warning-kcgcolorspacegenericrgb-is-deprecated.html"&gt;Warning: kCGColorSpaceGenericRGB is Deprecated&lt;/a&gt;: What to do about this graphical warning. &lt;br&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Chapter "21": iPhone OS 3.0&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/a-preview-of-iphone-os-30.html"&gt;A Preview of iPhone OS 3.0&lt;/a&gt;: A list of six new categories of functionality for 3.0.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/table-tricks-for-iphone-os-30.html"&gt;Table Tricks for iPhone OS 3.0&lt;/a&gt;: A look at the multiple sorts of table cells available in 3.0.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-1-an-introduction.html"&gt;Core Data, Part 1: An Introduction&lt;/a&gt;: Introducing the next generation of data storage.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html"&gt;Core Data, Part 2: The Data Model&lt;/a&gt;: How Core Data models its data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-3-retrieving-data.html"&gt;Core Data, Part 3: Retrieving Data&lt;/a&gt;: How to get data out of Core Data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-4-inserts-updates-deletes.html"&gt;Core Data, Part 4: Inserts, Updates &amp;amp; Deletes&lt;/a&gt;: How to put data into Core Data.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-5-prefilling-data.html"&gt;Core Data, Part 5: Prefilling Data&lt;/a&gt;: How to insert data in advance. &amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/10/core-data-part-six-theres-more-than-one-way-to-do-it.html"&gt;Core Data, Part 6: There's More than One Way to Do It&lt;/a&gt;: Moving away from the SQL paradigm.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-two-core-data-integration.html"&gt;NSSet, Part 2: Core Data Integration&lt;/a&gt;: How NSSets work directly with Core Data.&amp;nbsp; &lt;br&gt;
&lt;/li&gt;
&lt;li&gt; &lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/errors-the-model-used-to-open-the-store-is-incompatible-and-other-core-data-errors.html"&gt;Errors: The Model Used to Open the Store is Incompatible (and other Core Data Errors)&lt;/a&gt;: A common core data error, concerning changing data models. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Appendix A: iPhoneOS Class Reference&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-one-the-basics.html"&gt;NSSet, Part 1: The Basics&lt;/a&gt;: Why and how to use an NSSet.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-two-core-data-integration.html"&gt;NSSet, Part 2: Core Data Integration&lt;/a&gt;: How NSSets work directly with Core Data.&amp;nbsp; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/uiactionsheet-part-one-alternate-user-input.html"&gt;UIActionSheet, Part 1: Alternate User Input&lt;/a&gt;: Another way to accept input from users. &lt;br&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/uialertview-part-one-the-basics.html"&gt;UIAlertView Part 1, The Basics&lt;/a&gt;: Another method for accepting simple, action-based input.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/01/uialertview-part-two-the-complexities.html"&gt;UIAlertView Part 2, The Complexities&lt;/a&gt;: Expanding the above with buttons and delegation.&amp;nbsp; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Appendix C: Publishing Your SDK Programs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/11/creating-an-ad-hoc-distribution.html"&gt;Creating an Ad Hoc Distribution&lt;/a&gt;: Everything about sending your program out. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Appendix D: Common Errors&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/errors-no-provisioned-iphone-os-device-is-connected.html"&gt;Errors: No Provisioned iPhone OS Device is Connected&lt;/a&gt;: An annoying error when trying to build to a device.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/04/errors-sqlite3-database-doesnt-remain-updated.html"&gt;Errors: SQLite3 Database Doesn't Remain Updated&lt;/a&gt;: How file locking can mess up your SQLite db.&lt;/li&gt;
&lt;li&gt; &lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/errors-the-model-used-to-open-the-store-is-incompatible-and-other-core-data-errors.html"&gt;Errors: The Model Used to Open the Store is Incompatible (and other Core Data Errors)&lt;/a&gt;: A common core data error, concerning changing data models. &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/05/problems-cant-build-clean.html"&gt;Problems: Can't Build &amp;gt;&amp;gt; Clean&lt;/a&gt;: When the "Build Clean" option doesn't show up.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/06/warning-kcgcolorspacegenericrgb-is-deprecated.html"&gt;Warning: kCGColorSpaceGenericRGB is Deprecated&lt;/a&gt;: What to do about this graphical warning. &lt;/li&gt;
&lt;/ul&gt;
&lt;strong&gt;Appendix E: Class Recipes&lt;/strong&gt;&lt;br&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/creating-a-splash-screen-part-one.html"&gt;Creating a Splash Screen, Part 1&lt;/a&gt;: A new splash screen class, and how to use it.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/creating-a-splash-screen-part-two.html"&gt;Creating a Splash Screen, Part 2:&lt;/a&gt; About the class header file.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/03/creating-a-splash-screen-part-three.html"&gt;Creating a Splash Screen, Part 3&lt;/a&gt;: About the class source file. &amp;nbsp; &lt;br&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/05/creating-a-splash-screen-splashview-11.html"&gt;Creating a Splash Screen: splashView 1.1&lt;/a&gt;: Updates to the class and improved instructions. &lt;/li&gt;
&lt;li&gt;&lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/07/skdatabase-11-a-sqlite-library-for-the-iphone.html"&gt;SKDatabase 1.1: A SQLite Library for the iPhone&lt;/a&gt;: An SQL library, offered with no guarantees.&lt;br&gt;
 &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;/ul&gt;&lt;/div&gt;
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2010/01/2009-table-of-contents.html</feedburner:origLink></entry>
    <entry>
        <title>NSSet, Part Two: Core Data Integration</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/Q-w6PRxApy8/nsset-part-two-core-data-integration.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-two-core-data-integration.html" thr:count="1" thr:updated="2010-01-17T00:55:32-08:00" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c01287662bf8a970c</id>
        <published>2009-12-17T12:42:18-08:00</published>
        <updated>2009-12-17T12:42:58-08:00</updated>
        <summary>In the first part of this article I discussed the basics of NSSet: why you'd want to use one and how you can simply access the contents of an NSSet. As I wrote at the time, my greatest use of...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="Core Data" />
        <category scheme="http://www.sixapart.com/ns/types#category" term="SDK Missing Classes" />
        
        
<content type="html" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
&lt;div xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;p&gt;In the &lt;a href="http://iphoneinaction.manning.com/"&gt;first part&lt;/a&gt; of this article I discussed the basics of NSSet: why you'd want to use one and how you can simply access the contents of an NSSet. 

&lt;p&gt;As I wrote at the time, my greatest use of NSSet thus far has come when using Core Data. That's because you get an NSSet whenever you access a one-to-many relationship in Core Data. In this article, I'm going to talk about some of the many ways to use NSSets in that context.

&lt;p&gt;All of my examples will center around the data model that I laid out way back in &lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html"&gt;Core Data, Part Two: The Data Model&lt;/a&gt;. You might want to look at the graphics there for clarification, but the basic idea that I'll focus on here is that I have a "CardStack" entitity which includes a one-to-many relationship with a "Card" entity called "cards". In other words, it's an entity that represents a deck of cards.
&lt;/p&gt;&lt;h3&gt;The Simple Core Data Stuff&lt;/h3&gt;
The simplest thing you can do with Core Data is directly grab an NSSet by looking up a one-to-many relationship. If you want, you can then turn it into an array with the allObjects method call that I mentioned in the last article:
&lt;blockquote&gt;
NSArray *theseCards = [fromDeck.cards allObjects];
&lt;/blockquote&gt;
You can similarly set one-to-many relationships using NSSet, as I did when I set up my cards initially:
&lt;blockquote&gt;&lt;p&gt;
[card setImages:[NSSet setWithObject:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; [self setupCardPic:(CardPics *)myCardPic]]];
&lt;/p&gt;

&lt;/blockquote&gt;
This example shows the creation of a one-to-many-relationship with a single element, but it's easy enough to use other NSSet messages such as setWithArray: and setWithObjects: to instead add multiple objects to your relationship.

&lt;p&gt;Note that this methodology is also what I was highlighting in &lt;a href="http://iphoneinaction.manning.com/iphone_in_action/2009/10/core-data-part-six-theres-more-than-one-way-to-do-it.html"&gt;Core Data Part Six, There's More Than One Way to Do It&lt;/a&gt;. Accessing an NSSet often represents a cleaner, more intuitive way to get to your data. However, it's not just restricted to the simple NSSet lookups described here.

&lt;p&gt;What follows are some more complex NSSet lookups that really highlight the power of the class--and its powerful integration with Core Data. Each of the examples that follows is part of a method directly built into my CardStack class. Thus you'll see references to things like "self.cards" which is just a way to access the cards relationships from inside a CardStack object.
&lt;h3&gt;Enumerating an NSSet&lt;/h3&gt;
&lt;p&gt;Thus far I've talked about how to access an NSSet mainly by turning it into a different sort of object (an NSArray). That's by no means necessary. You can walk through the contents of an NSSet with the help of an NSEnumerator:
&lt;blockquote&gt;&lt;p&gt;
-(NSNumber *)worthOfType:(NSString *)thisType {&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSSet *theseCards = [self cardsOfType:thisType];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSEnumerator *thisEnum = [theseCards objectEnumerator];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Card *thisCard;
	float totalWorth = 0; &lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; while (thisCard = [thisEnum nextObject]) {&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; totalWorth += [thisCard.worth floatValue]; &lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return [NSNumber numberWithFloat:totalWorth];&lt;/p&gt;

&lt;p&gt;}
&lt;/p&gt;

&lt;/blockquote&gt;
&lt;p&gt;This examples figures out the total worth of the cards of a specific type. Once you create an NSEnumerator object with the ObjectEnumerator NSSet message, you can step through it by continuously sending the NSEnumerator a nextObject message. I'll offer one warning that's also noted in the Apple docs: don't change an NSMutableSet as you're enumerating it. I've accidentally done that more than once, and sure enough, it doesn't work.

&lt;p&gt;Mind you, there's an alternative way to do this same thing with key paths, but stepping through an NSSet with an NSEnumerator will probably have many uses for you. &lt;h3&gt;Predicates &amp;amp; NSSets&lt;/h3&gt;
The cardsOfType: message call in the previous example shows another way that you can use an NSSet, by filtering it with an NSPredicate.

&lt;p&gt;Here's a complete example, with cardsOfType: actually sending a more generic cardsWithKey:Value: message:
&lt;blockquote&gt;&lt;p&gt;
-(NSSet *)cardsOfType:(NSString *)type {&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return [self cardsWithKey:@"type" Value:type];&lt;/p&gt;

&lt;p&gt;} &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;-(NSSet *)cardsWithKey:(NSString *)thisKey Value:(id)thisValue {&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSSet *theseCards = self.cards;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSPredicate *predicate 
      =&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; [NSPredicate predicateWithFormat:@"%K=%@",
        thisKey,thisValue];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSSet *filteredCards = [theseCards filteredSetUsingPredicate:predicate];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return filteredCards; &lt;/p&gt;

&lt;p&gt;}
&lt;/p&gt;

&lt;/blockquote&gt;
As you can see, a simple three-step process lets you reduce your NSSet to a subset based on a predicate. 

&lt;p&gt;First, you create an initial NSSet, here with self.cards. 

&lt;p&gt;Second, you create a predicate. This example uses the slightly more complex %K=%@ invocation, which allows me to set the key for my predicate dynamically. What I'm really doing in this example is 'type=%@,thisValue'.

&lt;p&gt;Third, you use the NSSet's filteredSetUsingPredicate: message to turn your original NSSet and your NSPredicate in a smaller NSSet subset.

&lt;p&gt;With this example in hand you can now see how it integrates with the previous example, which let me get the worth of just a subset of all my cards.
&lt;h3&gt;Key Paths &amp;amp; NSSets&lt;/h3&gt;
&lt;em&gt;iPhone in Action&lt;/em&gt; doesn't discuss key-value coding, but it's a handy way to quickly apply operators to an entire collection of objects. This means that for NSArrays and NSSets you can compute averages, sums, maxes, minimums, counts, and lots more. You should take a look at Apple's &lt;a href="http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/KeyValueCoding/Concepts/ArrayOperators.html"&gt;Key-Value Coding Guide&lt;/a&gt; for more information.

&lt;p&gt;The earlier NSEnumerator example could have been done with key-value coding and a @sum operator (but I left it as was so that I could show off NSEnumerator). Here's a very similar example that instead uses a key-value path:
&lt;blockquote&gt;&lt;p&gt;
-(NSNumber *)selectedWorth {&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSSet *filteredCards = [self cardsSelected];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSString *keyPath = [NSString stringWithFormat:@"@sum.worth"];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; NSNumber *worthSum = [filteredCards valueForKeyPath:keyPath];&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return worthSum;&lt;/p&gt;

&lt;p&gt;}
&lt;/p&gt;

&lt;/blockquote&gt;
As you can see, you create a key path as an NSString. It must have an operator, which begins with an @ symbol, followed by the property that the operator is working on. Thus, here, we're summing the value of the worth property. You then can apply that to an NSSet with a valueForKeyPath: message. That's surely easier than digging through the entire NSSet as I did the first time through.

&lt;p&gt;This example also shows how you can stack up these different NSSet methods, as my original 'filteredSet' was created with an NSPredicate operation (in the cardsSelected method, not shown).

&lt;p&gt;A more complex keyPath might look something like this:
&lt;blockquote&gt;
cards.@sum.worth
&lt;/blockquote&gt;
This shows a different way to invoke a key path. You're putting a property name &lt;em&gt;before&lt;/em&gt; the @operator, to dig down through a hierarchy of properties. In this example, the key path wll be operating directly on the self object (the CardStack). It digs down to the cards property, and that's the set that it actually operates on. There it again looks for the @sum of the worth (thus showing a third way to calculate worth using NSSets).
&lt;h3&gt;Conclusion&lt;/h3&gt;
You can do pretty powerful things with NSSets without turning them into NSArrays. This article showed three primary ways to do things: by enumerating an NSSet, by filtering it through an NSPredicate, and by operating upon it with a key value. There's considerable more that you can do with NSPredicates and key values, and you should take a look at Apple's documents on them if you want to know more, but this should get you started.&lt;/div&gt;
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-two-core-data-integration.html</feedburner:origLink></entry>
    <entry>
        <title>NSSet, Part One: The Basics</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/zxI2v9Wk5m4/nsset-part-one-the-basics.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-one-the-basics.html" thr:count="0" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c01287602709a970c</id>
        <published>2009-12-02T14:18:59-08:00</published>
        <updated>2009-12-02T14:18:59-08:00</updated>
        <summary>Thus far in approaching the "SDK Missing Classes" that we didn't cover in iPhone in Action, I've talked about UI class objects, since they're uniquely iPhone classes that you're unlikely to have encountered elsewhere. In this article and the next,...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="SDK Missing Classes" />
        
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml">Thus far in approaching the "SDK Missing Classes" that we didn't cover in <em>iPhone in Action</em>, I've talked about UI class objects, since they're uniquely iPhone classes that you're unlikely to have encountered elsewhere. In this article and the next, however, I'm going to take a step back and instead talk about an NS class. 

<p>There are many NS classes like NSArray and NSDictionary which we used throughout <em>iPhone in Action</em>, but which required little extra explanation because they matched up with standard variable types--such as arrays and associative arrays--that you've probably used in other programming languages. The NS class that we're going to talk about here, NSSet, is slightly more unique however, and thus I've decided to give it some coverage all of its own.
</p><h3>Why NSSet?</h3>
In NSArray and NSDictionary you've already got two perfectly acceptable data storage classes. So, why do you need another? The answer is efficiency. If you always use the right class for the right job, then it's more likely that your programs will run cleanly and quickly.

<p>NSSet is specifically designed for the storage of <em>unique</em>, <em>unordered</em> data. However where you actually get efficiency gains is when you do arbitrary lookups from your data storage. Where you'd have to program an O(n^2) lookup by hand for your NSArray, an NSSet can automatically deliver you an O(n) lookup. 

</p>

<p><a href="http://cocoawithlove.com/2008/08/nsarray-or-nsset-nsdictionary-or.html">Cocoa with Love</a> has an interesting article on the topic which runs some benchmarks that show, not surprisingly, that NSArray is better at iterating contents and NSSet is better at testing for inclusion. Matt Gallagher goes further than that, however, saying that NSSet is so much more efficient that if you need to both iterate data storage <em>and</em> test it for inclusion, you should use an NSSet.

</p>

<p>So, that's <em>why</em> NSSet. How does it work?
</p><h3>Simple Solutions: Any and All</h3>
<p>In your iPhone programming, you've probably already used NSSets when working with UITouch objects. Our event reporter program in <em>iPhone in Action</em> showed an example of how to iterate through an NSSet using a for ... loop (see pg. 248). You can also send the messages 'anyObject' or 'allObjects' to an NSSet for easy lookup.

</p>

<p>anyObject just returns a random object from the NSSet. I find it particularly helpful when I'm expecting there to be only a single object in an NSSet:

</p><blockquote>
UITouch *thisTouch = [touches anyObject];
</blockquote>

<p>allObjects essentially turns your NSSet into an array, which you can then use via your normal array methods:

</p><blockquote>
NSArray *touchesArray = [touches allObjects];
</blockquote>

<p>Though these methods are certainly convenient, neither one really speaks to NSSet's greatest strength: inclusion testing.
</p><h3>Needles in NSSet Haystacks</h3>
<p>The best method in NSSet is probably containsObject:, which returns a Boolean response if an object is in a set. The following example shows it in simple use. It looks at whether a specific deck of cards is listed in the activeDecks NSSet of cards:
</p><blockquote><p>
-(BOOL)isActiveDeck:(CardStack *)thisDeck {<br />
    return [activeDecks containsObject:thisDeck];<br />
}
</p>
</blockquote>

<p>
There are numerous more complex NSSet methods which you can use for set comparison, among them isSubsetofSet:, insertsectsSet:, and isEqualToSet:. You should look them up in the NSSet Class Reference is one of them applies to your specific work. Generally, this proliferation of set-related classes outlines how much NSSet is the preferred class when you're doing this type of work.</p>

<h3>Creating NSSets</h3>

<p>I haven't talked about the creation of NSSets thus far because I figure that in many cases you'll be getting an NSSet of UITouch objects (as noted in this article) or an NSSet from Core Data (as noted in the next article). </p>

<p>However, if you create your own NSSet, you can easily do so with initWithArray:, initWithSet:, or initWithObjects:, all of which work like you'd expect. You may also find a NSMutableSet quite useful for dynamic use, and you can create that with the normal initWithCapacity: used by all the NSMutable classes.</p>

<h3>Conclusion</h3>

<p>The main purpose of this article was to get you familiar with NSSet as an alternate form of data storage and with the specific advantages that it offers. The actual method calls described in this article are  pretty rudimentary--but they were enough for my own purposes until the last couple of months.</p>

<p>It's only been since I've been using Core Data (as described in my <a href="http://iphoneinaction.manning.com/iphone_in_action/core-data/">Core Data</a> articles) that I've had to do more complex things with NSSet. I'm going to be describing those more in-depth, with examples from the card program that I'm just finishing up, next week in <em>NSSet, Part Two: Core Data Integration</em>.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/12/nsset-part-one-the-basics.html</feedburner:origLink></entry>
    <entry>
        <title>The iPhone Simulator &amp; Performance</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/j9mSX7EF2tM/the-iphone-simulator-performance.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/11/the-iphone-simulator-performance.html" thr:count="0" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a6b33bf4970b</id>
        <published>2009-11-18T15:15:49-08:00</published>
        <updated>2009-11-18T15:15:49-08:00</updated>
        <summary>In iPhone in Action we talk about some about using the iPhone Simulator as a testing &amp; debugging facility for your iPhone programs. It's certainly an easy and convenient way to work on your programs. You hit command-r and with...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="iPhone in Action Commentary" />
        
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml"><p>In <em>iPhone in Action</em> we talk about some about using the iPhone Simulator as a testing &amp; debugging facility for your iPhone programs. It's certainly an easy and convenient way to work on your programs. You hit command-r and with no additional work on your part, your program compiles, the Simulator starts up, and everything runs.</p><p>However, in <em>iPhone in Action</em>, we also talk a bit about the places where the iPhone Simulator comes up short. It includes: using the accelerometers, using the location manager (though you can do simple tests as the Simulator reports back Apple's Silicon Valley headquarters), and downloading streaming audio. </p><p>In the last two months I've been working on a card game, which I expect to write about more here when we're ready to release. It's shown me another pretty grave short-coming in the Simulator: performance. The issue? It's too good.</p><p>I mean, we all know that the iPhone is a mobile platform, and that by nature it'll ultimately be limited in its CPU capabilities. But, it's easy to forget that with all of the sexy animations and graphics that Apple pushes back and forth around the screen. Indeed, if you're just making simple use of Apple's more front-facing frameworks, you may not hit performance problems at all.</p><p>The problem arises when you start using more in-depth frameworks like Core Data and Core Graphics. You may end up with programs which work <em>great</em> on the Simulator but which seriously bog down when you put it out to a real iPhone or iPod Touch device.</p><p>Here were the top two performance problems that I hit when working on my card game:</p><ul>
<li><strong>Rounded Corners.</strong> My cards are laid out as CALayers. When I used the new 3.0 property, cornerRadius, to round the corners of my cards, I discovered that a real iPhone got dragged to a blinking, laggy halt. I thought I was just going to need to square my corners as long as I used CALayers, but eventually discovered that if I rounded the corners myself, using a clipping area on the CALayer's context, everything worked pretty good.</li>
<li><strong>Too Much Core Data Writing.</strong> At one point, I accidentally set my program to rewrite the Core Data ordering property for my cards any time a deck was touched, rather than only when they were actually reordered. Until I resolved the inefficiency, my game felt like it was moving through molasses.</li>
</ul>
<p>The important fact that I intend to convey here is: these problems did not show up in the Simulator, only on an actual device. This was particularly frustrating for the second problem, which I discovered after a half-day or so of programming <em>lots</em> of different changes.</p><p>So the moral? If you're using simple frameworks, don't worry about it, But, if you're doing more complex work, every couple of compiles, send one over to an actual hardware device. The first time you hit a performance problem that didn't show up in the Simulator, you'll be happy you did.</p><p><strong>Next Up:</strong> I'll be back after the Thanksgiving holiday, probably talking about NSSets: how they work, why you'd want to use them, and how they integrate with Core Data.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/11/the-iphone-simulator-performance.html</feedburner:origLink></entry>
    <entry>
        <title>Creating an Ad Hoc Distribution</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/YLhhSUebZBo/creating-an-ad-hoc-distribution.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/11/creating-an-ad-hoc-distribution.html" thr:count="4" thr:updated="2010-02-23T13:50:48-08:00" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a657f6e2970b</id>
        <published>2009-11-05T13:37:19-08:00</published>
        <updated>2009-11-05T13:37:19-08:00</updated>
        <summary>In iPhone in Action we only briefly touch upon distribution methodology (see pages 429-431), mainly because Apple maintains extensive documents on their whole "Program Portal". However in today's post I'm going to supplement our distribution information a bit by highlighting...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="iPhone Major Article" />
        
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml"><p>In <em>iPhone in Action</em> we only briefly touch upon distribution methodology (see pages 429-431), mainly because Apple maintains extensive documents on their whole "Program Portal". However in today's post I'm going to supplement our distribution information a bit by highlighting how you create an Ad Hoc Distribution.</p><h3>Why Ad Hoc?</h3><p>If you're distributing through the Apple iPhone Store, you might think that you'll never need to release via the ad hoc mehcanism ... and that's probably not correct. There are a number of good reasons to create an ad hoc distribution:</p><ul>
<li>It lets you easily send a program to other team members, without them having to compile the program.</li>
<li>It allows you to send pre-release copies of a program to a licensor, for their approval.</li>
<li>It offers a way to get your App to reviewers prior to release.</li>
</ul>
<p>
The last point is particularly important if you're trying to get on the top-100-program escalator to success--though I personally have grave concerns over the economics of advertising costs versus top 100 returns. But if you decide to go that route you want to get copies of your program out to reviewers so that they can release reviews on the day of your release (or very close thereafter).</p><h3>The Ad Hoc Process</h3><p>The ad hoc process is described thoroughly in the "Program Portal User Guide" which can be found in your "iPhone Developer Program Portal" at developer.apple.com. What follows is largely a summary of the material contained in pages 50, 56-58, and 65 of that book.</p><p>Here's what all you need to do:</p><ol>
<li><em>Prepare for a Provisioning Profile.</em> This generally means that you need to follow the steps from Appendix C of <em>iPhone in Action</em>. You must have already created a distribution certificate, which you'll use to sign the profile; you must have chosen an AppID for your program; and you must have entered UUIDs for any devices that you want your program to run on. You should already be familiar with these items, and have them in hand, from the work you did to either create a developmental provisional profile or an app store distribution provisional profile. The only notable difference here is that you'll probably need to enter some new UUIDs, since you need to enter the data for <em>every </em>device that you want your program to run on--which means the devices of reviewers, licensors, co-workers, and whoever else you're working with.</li>
<li><em>Create a Distribution Provisioning Profile.</em> Click the "Provisioning" option in the Program Portal, then the "Distribution" tab. Choose "ad hoc" as your distribution method, then enter data on your certificate, app id, and devices, as appropriate.</li>
<li><em>Create a new Ad Hoc Distribution Profile in Your Project.</em> This relatively simple process is described at length on pages 51-56 of the Portal Guide. In essence, you duplicate the "Release" profile, then set it to use your new ad hoc profile as its code signing identity. You've probably already done the other work of this section, such as setting up your project to use your app id.</li>
<li><em>Create an Entitlements File.</em> This is the major new element required to prepare an app for ad hoc distribution, and it's described on pages 56-58 of the Portal Guide, which you should read at length. In essence: you create a new "Code Signing" file of type "entitlements." Then you uncheck the "get-task-allow" property of your new file. Finally you go to the Build tab of your target and enter your new file into the "Code Signing Entitlements" section of the "Code Signing" setting.</li>
<li><em>Build Your Project.</em> Now you can build. You'll of course want to make sure that you've set Xcode to compile for a <em>device</em> of the correct OS version, using your ad hoc distribution profile.</li>
</ol>
<p>
That should produce an ad hoc version of your project that's ready to go ...</p><h3>Distributing Your Ad Hoc Program</h3><p>If all of your potential ad hoc users have their iPhones or iPod Touches hooked up to Macs, you can just send the compiled product (program.app) <em>and </em>the provisioning profile. Your users can drag the two files to the iTunes icon on their doc, and the program will automatically copy into iTunes, then download onto their device as soon as they sync.</p><p>However, if a user has an iPod Touch hooked up to a Windows machine, the above will probably fail. The .app file will simply refuse to drop on iTunes. At the time of this writing, you need to create a special .ipa file as a replacement for the .app file for Windows users. This turns out to be just a .zip file with a specific structure.</p><p>To create an .ipa file, you need to go to the directory containing your ad-hoc-compiled app. You can find that by clicking on the app in Xcode, then right-clicking to choose "Reveal in Finder". Alternatively, it should be easily accessible in a special "ad hoc" subdirectory of your project directory's "build" directory.</p><p>In either case, once you're there run the following commands, substituting your app's name for "program":</p><blockquote><p>
 mkdir Payload<br />mv program.app Payload<br />zip -r ~/Desktop/program.ipa Payload
</p></blockquote><p>
(Thanks to the folks on the iphonesdk list for solving this problem, and in particularly to David Morris, who offered the above script.)</p><p>This should create a .ipa file on your desktop, which you can send out. A windows user will then be able to install your program by dragging the provisioning profile <em>and</em> the .ipa file to their iTunes icon.</p><p>As it happens, Mac users can use the .ipa file fine too, so if you ever need to create one because some user has a Windows machine, you might as well just send the .ipa file and the provisioning file to everyone, rather than sending the .app file out to any one.</p><p>Last step: sit back and wait for the comments to come in.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/11/creating-an-ad-hoc-distribution.html</feedburner:origLink></entry>
    <entry>
        <title>Core Data, Part 6: There's More than One Way to Do It</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/_in8XOPEc4I/core-data-part-six-theres-more-than-one-way-to-do-it.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/10/core-data-part-six-theres-more-than-one-way-to-do-it.html" thr:count="0" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a6084a9b970b</id>
        <published>2009-10-20T13:59:58-07:00</published>
        <updated>2009-10-20T14:23:21-07:00</updated>
        <summary>In my previous articles on Core Data, I frequently offered comparisons back to MySQL, since that's the environment that I presume many readers will be coming from. It's a great starting place, but as you come to understand Core Data...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="Core Data" />
        <category scheme="http://www.sixapart.com/ns/types#category" term="iPhone OS 3.0" />
        
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml"><p>In my previous articles on Core Data, I frequently offered comparisons back to MySQL, since that's the environment that I presume many readers will be coming from. It's a great starting place, but as you come to understand Core Data better, you may find that there are cleaner ways to do certain types of lookups. I won't promise they're more efficient, since that falls upon the backend's coding, but they will often better map the abstracted objects that you've created in your Core Data projects.</p><p>To exemplify what I mean I'm going to offer a few examples using the card game model that I outlined in <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html">part two</a>
of this series. If you look at that model you'll see that I have a
"CardStack" object (which could be a deck, a draw pile, or a hand)
which contains a number of "Card" objects. This connection is
maintained by a one-to-many relationship called "cards" in the
CardStack object and by a one-to-one relationship called "location" in the
Card object. </p><p>This article will show how using those relationships can offer cleaner ways to access linked data than doing new Core Data lookups.</p><h3>Two Ways to Lookup</h3><p>Coming from an SQL background, the most obvious way to list the cards in the deck is something like this:</p><blockquote><p>-(NSArray *)contentsOfHand:(CardStack *)thisDeck </p><p>    sortBy:(NSArray *)sorting {</p><p>    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];<br />    NSEntityDescription *entity = [NSEntityDescription</p><p>        entityForName:@"Card" <br />        inManagedObjectContext:self.managedObjectContext];<br />    [fetchRequest setEntity:entity];</p><p>    NSPredicate *predicate = [NSPredicate<br />                              predicateWithFormat:@"location=%@",thisDeck];<br />    [fetchRequest setPredicate:predicate];</p><p>    if (sorting) {<br />        NSMutableArray *sortArray = [NSMutableArray</p><p>            arrayWithCapacity:[sorting count]];</p><p>        for (int i = 0; i &lt; [sorting count]; i++) {<br />            NSSortDescriptor *sort = [[NSSortDescriptor alloc] <br />                initWithKey:[sorting objectAtIndex:i] ascending:YES];<br />            [sortArray addObject:sort];<br />            [sort release];<br />        }</p><p>        [fetchRequest setSortDescriptors:sortArray];<br />    }</p><p>    NSError *error;<br />    NSArray *items = [self.managedObjectContext <br />        executeFetchRequest:fetchRequest error:&amp;error];<br />    [fetchRequest release];<br />    return items;<br />}</p></blockquote><p>This should look familiar because it's almost identical to the retrieval example I gave in <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-3-retrieving-data.html">part three</a> of this Core Data series. You create a fetch request for the Card entity, then make a predicate that limits lookups to the correct Deck location, and then sort it as you see fit.</p><p>However, someone more familiar with Core Data would probably take the opposite tactic, beginning with the Deck instead of searching through the Cards.</p><p>Here's what that would look like:</p><blockquote><p>NSArray *theseCards = [[thisDeck cards] allObjects];</p></blockquote><p>The "cards" relationship lookup generates an NSSet and the allObjects method call turns that into an array. Seems a bit easier, doesn't it? That's the power of relationships in Core Data. </p><p>However, there's a catch too: as I said, when you retrieve a one-to-many relationship, you get back an NSSet, and NSSets are innately unordered. There are ways around this, which I'm going to talk about in an upcoming article (or two) about NSSets, but the end result is that when you care more about ordering, you may want to do a direct retrieval from Core Data, rather than using a relationship.</p><p>Neither of my examples uses a predicate to <em>further</em> limit a lookup. You can use an NSPredicate to limit either a Core Data lookup <em>or</em> an NSSet directly, but again those are going to be topics for future articles.</p><h3>Two Ways to Count</h3><p>I think that in the previous example it's a pretty clear win to use the relationship reference rather than the Core Data lookup if you don't want to do any sorting. The code is shorter, it's clearer, and I could even attach it directly to my "CardStack" object if I wanted, to maintain an easy, well abstracted method for retrieving an NSArray of a deck's cards.</p><p>However, I've already admitted there are situations where it might not be optimal. Before I close out this article, I want to offer another example that's an even clearer win: getting a count of one of my Core Data decks.</p><p>Here's what's probably the most exhaustive way to do it, using Core Data:</p><blockquote><p>-(int)countCardsInDeck:(CardStack *)thisDeck {</p><p>    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];<br />    NSEntityDescription *entity = [NSEntityDescription</p><p>        entityForName:@"Card" <br />        inManagedObjectContext:self.managedObjectContext];<br />    [fetchRequest setEntity:entity];</p><p>    NSPredicate *predicate = [NSPredicate<br />                              predicateWithFormat:@"location=%@",thisDeck];<br />    [fetchRequest setPredicate:predicate];</p><p>    NSError *error;<br />    NSArray *items = [self.managedObjectContext<br />        executeFetchRequest:fetchRequest error:&amp;error];<br />    [fetchRequest release];</p><p>    return [items count];</p><p>}</p></blockquote><p>If you're now thinking about the "Core Data" way to do things, as opposed to the "SQL" way, you might already have the alternative method, which I offer here as an instance method in the CardStack object:</p><blockquote><p>-(int)count {</p><p>    return [self.cards count];<br />}</p></blockquote><p>As we've already seen, a one-to-many relationship returns a NSSet. "count" is a method call that's supported by that NSSet. In this situation I suspect there's no reason to ever go with the more cumbersome SQL-influenced Core Data call.</p><h3>Conclusion</h3><p>In my series on Core Data thus far I've encouraged an understanding of it based on SQL. Thinking about rows, columns, and tables make it easy to get started with Apple's data framework. However, as you delve further into Core Data, you should think about the relationships that you can create between objects. They aren't just superfluous modeling details; they're real elements that you can use to make your usage of Core Data simpler.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/10/core-data-part-six-theres-more-than-one-way-to-do-it.html</feedburner:origLink></entry>
    <entry>
        <title>Core Data, Part 5: Prefilling Data</title>
        <link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/typepad/iphone_in_action/~3/vrvNzZE8glI/core-data-part-5-prefilling-data.html" />
        <link rel="replies" type="text/html" href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-5-prefilling-data.html" thr:count="11" thr:updated="2010-03-13T11:36:54-08:00" />
        <id>tag:typepad.com,2003:post-6a010535e1becf970c0120a58118ae970b</id>
        <published>2009-09-18T13:35:32-07:00</published>
        <updated>2009-09-18T13:35:32-07:00</updated>
        <summary>In previous articles in this series, I've talked about how to dynamically create, access, and modify information using Core Data. However that all misses one vital component. I haven't yet talked about how to prefill your persistent storage. Now, maybe...</summary>
        <author>
            <name>Shannon Appelcline</name>
        </author>
        <category scheme="http://www.sixapart.com/ns/types#category" term="Core Data" />
        <category scheme="http://www.sixapart.com/ns/types#category" term="iPhone OS 3.0" />
        
        
<content type="xhtml" xml:lang="en-US" xml:base="http://iphoneinaction.manning.com/iphone_in_action/">
<div xmlns="http://www.w3.org/1999/xhtml"><p>In previous articles in this series, I've talked about how to dynamically create, access, and modify information using Core Data. However that all misses one vital component. I haven't yet talked about how to prefill your persistent storage.</p><p>Now, maybe this isn't actually an issue for you. If you're using Core Data to store a high score list or a selection of favorites, then you don't care about prefilling. Your user will supply all the content. However, there are many situations where you want to have something stored away before a user ever touches your program. </p><p>Throughout this series I've been using as examples some card-game classes which I've been building. When using these classes, I want to prefill my starting deck of cards, even though a lot of data (such as the order of those cards and later who's them) doesn't occur until the program goes live. It's still important to know what your 52 (or 54 or 104 or whatever) cards <em>are</em> before you get started. Similarly you might want to prefill a database of places, a listing of help topics, or many other things that you could use Core Data to store.</p><p>So how do you do so?</p><h3>It Ain't Easy</h3><p>Unfortunately, there are no simple answers. Following is discussion of two relatively simple methods that <em>aren't </em>possible using Core Data (but which I looked into before I arrived at a correct solution).</p><p><em>You Can't Use a Nifty UI.</em> I kind of expected a pretty user interface where I could just input data and save it. It'd be a nice match to the <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html">Data UI</a> that you use to create your managed object model. Alas, there's nothing like this yet, though perhaps Apple will support it someday.</p><p><em>You Can't Create Your Peristent Store By Hand.</em> When I was still programming with <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/07/skdatabase-11-a-sqlite-library-for-the-iphone.html">SQLite</a>, I'd typically create a prefilled database by hand, then copy it into my project. If you try to do this when using Core Data <em>everything will break</em>. </p><p>The reason is that Core Data puts a lot of extra junk into your persistent store to model internal IDs, joins, and other things. The result is a lot more complicated than the simple managed object model that you see on the surface. </p><p>Because you can't create all of the connective tissue that Core Data requires on your own, you have to let Core Data to it on its own. Which means that you <em>must</em> prefill your data programatically.</p><h3>Prefilling in Objective-C</h3><p>If you want to prefill your data, you probably have two objectives. First, you want to make it easy to update the prefilled contents of your persistent store. Second, you want take the burden/complexity of parsing your initial data out of the program that your users will be running.</p><p>I thus suggest the following five-step process:</p><ol>
<li>Create your data in a comma-separated file, typically placing each row of data (an entity) in a row of the file and separating different columns (its attributes) by commas.</li>
<li>Write a standalone program and copy in your .xcdatamodel file from your main project.</li>
<li>Write code in your new program that parses your comma-separated file and inserts the information into a Core Data persistent store that should be identical to the persistent store in your main project.</li>
<li>Run the program in the Simulator</li>
<li>Copy your data from the Simulator's documents directory into your actual project's bundle.</li>
</ol>
<h4>A Prefilling Example</h4><p>
Here's an example of a few comma-separated lines of data for my current card game:</p><blockquote><p>1,A$20,Australian Dollars,20,aussie-20.png<br />
2,R$20,Brazilian Reals,20,brasil-20.png
</p></blockquote><p>After creating that complete CSV file, I then made a new Core Data project. Whereas my original program was called "Money", this new one was called "MoneyCreateCards". I made sure to copy in Money.xcdatamodel. I then edited the peristentStoreCoordinator method in my app delegate so that it'd output to a file using the same name as my original program:</p><blockquote><p> NSURL *storeUrl = [NSURL fileURLWithPath:<br />    [[self applicationDocumentsDirectory]<br />        stringByAppendingPathComponent: @"Money.sqlite"]];
</p></blockquote><p>I'm pretty sure this isn't strictly necessary, but when you're dealing with data abstractions doing super secret things, it's better to cover all your bases.</p><p>Then I wrote some code to read everything from my CSV and output it to my sqlite file:</p><blockquote><p>- (void)setupCards {</p><p>    NSString *paths = [[NSBundle mainBundle] resourcePath];<br />    NSString *bundlePath = [paths stringByAppendingPathComponent:@"cards.csv"];<br />    NSString *dataFile = [[NSString alloc] initWithContentsOfFile:bundlePath];</p><p>    NSArray *dataRows = [dataFile componentsSeparatedByString:@"\n"];<br />    [dataFile release];</p><p>    Card *card;<br />    for (int i = 0 ; i &lt; [dataRows count] ; i++) {<br />        NSArray *dataElements = [[dataRows objectAtIndex:i] <br />            componentsSeparatedByString:@","];<br />        if ([dataElements count] &gt;= 4) {<br />            card = (Card *)[NSEntityDescription insertNewObjectForEntityForName:@"Card" <br />                inManagedObjectContext:[self managedObjectContext]];</p><p>            [card setId:[NSNumber numberWithInt:i]];<br />            [card setName:[dataElements objectAtIndex:1]];<br />            [card setType:[dataElements objectAtIndex:2]];<br />            [card setWorth:[NSNumber numberWithInt:<br />                [[dataElements objectAtIndex:3] intValue]]];<br />            [card setImages:[NSSet setWithObject:<br />                [self setupCardPic:[dataElements objectAtIndex:4]]]];<br />            [self saveAction:self];<br />        }<br />    }</p><p>}</p></blockquote><p>The parsing was pretty simple. I just separated rows by \ns and columns by ,s. It's totally non-robust, but since I'm creating the CSV file, that's OK.</p><p>Afterward, I followed the methodology that I explained for <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-4-inserts-updates-deletes.html">inserting data</a> in the last article. I created a new entity, set its attributes, and saved the managed object context. </p><h4>An Aside on Relationship Creation</h4><p>Note in particular the setImages: message. It's a nice addendum to my previous article, about inserting. If you look back at my article on the <a href="http://iphoneinaction.manning.com/iphone_in_action/2009/08/core-data-part-2-the-data-model.html">data model</a> you'll see that images is a one-to-many relationship between the Card entity and the CardPics entity. To set this relationship attribute, I had to do two things.</p><p>First, I created a CardPic (unless the same CardPic had already been created for an earlier card):</p><blockquote><p>- (CardPics *)setupCardPic:(NSString *)fileName {<br />    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];<br />    NSEntityDescription *entity = [NSEntityDescription entityForName:@"CardPics" <br />                                              inManagedObjectContext:self.managedObjectContext];<br />    [fetchRequest setEntity:entity];</p><p>    NSPredicate *predicate = [NSPredicate<br />                              predicateWithFormat:@"name=%@",fileName];<br />    [fetchRequest setPredicate:predicate];</p><p>    NSError *error;<br />    NSArray *items = [self.managedObjectContext<br />        executeFetchRequest:fetchRequest error:&amp;error];<br />    [fetchRequest release];</p><p>    if ([items count] &gt;= 1) {<br />        return [items objectAtIndex:0];<br />    } else {<br />        CardPics *newPic = (CardPics *)[NSEntityDescription insertNewObjectForEntityForName:@"CardPics" inManagedObjectContext:[self managedObjectContext]];<br />        [newPic setName:fileName];<br />        [newPic setSize:[NSNumber numberWithInt:150]];<br />        [self saveAction:self];<br />        return newPic;<br />    }        <br />}</p></blockquote><p>Note the search I do before the creation, offering another example of Core Data programming.</p><p>Second, I set the Card's relationship attribute to be an NSSet containing the CardPic as we saw in the previous example. Note that the use of NSSet in this manner is always required to set a one-to-many relationship's attribute.</p><h4>Finishing Up</h4><p>That's pretty much it. When I was all done I copied the resulting Money.sqlite file from my card-creation program to my card-playing program.</p><p>Whenever I want to make a change, I just modify my CSV file, delete my MoneyCreateCards program, and rerun it. (If I'd wanted to be fancier I could have had the program empty its database and recreate it every time, but I'm less inclined to spend much effort on a utility program of this sort.) The only thing I have to be careful about is making sure that my MoneyCreateCards program's .xcdatamodel stays synced with that in my Money program. If it doesn't, you can get bizarre errors.<span style="font-style: italic;"><span style="font-weight: bold;"><br /><br /></span></span><strong><em>Next Up:</em></strong> This is actually the last of my planned article on Core Data. If you haven't read them all, I suggest you click on the "Core Data" tag, just below. Also, if there are Core Data topics that you'd particularly like to learn more about, feel free to drop me a line in the comments. If it's something I've already done work with, I'm happy to expand on it in some future article.</p></div>
</content>


    <feedburner:origLink>http://iphoneinaction.manning.com/iphone_in_action/2009/09/core-data-part-5-prefilling-data.html</feedburner:origLink></entry>
 
</feed><!-- ph=1 --><!-- nhm:dynamic-ssi -->
