<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace V5 Site Server v5.13.156 (http://www.squarespace.com) on Sun, 19 May 2013 12:25:09 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Blog</title><link>http://www.escortmissions.com/blog/</link><description></description><lastBuildDate>Sun, 22 Jul 2012 04:04:37 +0000</lastBuildDate><copyright></copyright><language>en-US</language><generator>Squarespace V5 Site Server v5.13.156 (http://www.squarespace.com)</generator><item><title>Finding relevant WWDC videos</title><category>Mobile App Dev</category><category>Programming</category><category>WWDC</category><category>education</category><category>iDevBlogADay</category><category>iOS</category><category>videos</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 22 Jul 2012 04:04:36 +0000</pubDate><link>http://www.escortmissions.com/blog/2012/7/22/finding-relevant-wwdc-videos.html</link><guid isPermaLink="false">892456:10432592:19852548</guid><description><![CDATA[<p>As I've said before, <a href="http://www.escortmissions.com/blog/2012/6/10/my-top-5-factors-for-ios-contracting-success.html">I find the WWDC videos to be invaluable</a> and I try watch all of them eventually.  But there are a lot of them, and it can be hard to find what's relevant.  And a lot of them I go back and watch again when I start working with a different part of a project.</p>

<p>So I've developed a trick, and I thought I'd share it with you all.</p>

<p>I go to the <a href="https://developer.apple.com/videos/wwdc/2012/">site where the videos are hosted</a> and click on the "view all in iTunes button".  From iTunes, I download all the slides (Click a track like "Essentials", then click "Slides" just above the list, and then click the "Get Tracks" button in the header).</p>

<p>I keep all the slides for WWDC 2010, 2011 and 2012 in subdirectories of a folder named "WWDC slides" in my Documents directory.  It's indexed by Spotlight on my Mac.</p>

<p>From then on, when I'm working on a project, and I'm having trouble with something, or trying to remember something I might have seen, I open up that folder in Finder, and type the Class or Method names of the Classes I'm working with, and Spotlight will tell me the session names of the videos I might want to watch.</p>

<p>So, for example, if I type 'NSFetchRequest', the first result is "Session 214 - Core Data Best Practices" from WWDC2012.  I type 'registerNib:', and I get "Session 125 - UITableView Changes, Tips, Tricks" from WWDC2011 (among others).</p>

<p>Then I just go to iTunes or the website, and I know which video to go watch.</p>

<p>It's a handy trick (and I use it to search through all my eBooks on programming, as well), and when I've recommended specific videos to people, I've had several of them ask me how I keep the videos straight.  </p>

<p>So hopefully it's useful to some of you.</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-19852548.xml</wfw:commentRss></item><item><title>New Work In Progress - Million Words: Multiplayer Crossword Game for Parents and Kids that Grades on a Curve</title><category>Gaming</category><category>Indie Development</category><category>Million Words</category><category>Parenting</category><category>education</category><category>educational</category><category>gaming</category><category>iDevBlogADay</category><category>iOS</category><category>new game</category><dc:creator>Carl Brown</dc:creator><pubDate>Sat, 07 Jul 2012 22:46:20 +0000</pubDate><link>http://www.escortmissions.com/blog/2012/7/7/new-work-in-progress-million-words-multiplayer-crossword-gam.html</link><guid isPermaLink="false">892456:10432592:17451474</guid><description><![CDATA[<p>Although I do <a href="http://www.escortmissions.com/blog/2012/6/10/my-top-5-factors-for-ios-contracting-success.html">iOS Contracting</a> to pay my bills (at least to date), I hope one day to earn a living from my own apps, and, although it's not ready for release, the time has come to unveil my new project.</p>

<p><img src="http://www.escortmissions.com/resource/GamePlay1.png?fileId=19154575" alt="GamePlay Example" title="GamePlay1.png" border="0" width="231" height="308" style="float:right;" /><a href="http://www.millionwordsapp.com">Million Words</a> is a turn-based crossword game where you're scored not by what letters you managed to get into your word, but by the grade level of your word, relative to your age.  This way my six-year-old daughter could play "HELLO" and I could play "HELICOPTER" and we would get the same number of points (more or less).  </p>

<h2>The Problem</h2>

<p>When I got my retina iPad, my iPad 2 became my wife's iPad, and my first generation iPad got freed up for my six-year-old (when I'm not using it to test how my code runs on old hardware).  I erased the data and gave it to her so she could set it up as "hers".  Being six, she uses it primarily to play games, and I was frustrated to notice that those games fell into two categories:</p>

<ul>
<li>Educational Games, whose content she would exhaust in short order and lose interest in, and</li>
<li>Fun, Endless games that she could play over and over, but that had limited educational value (think PopCap).</li>
</ul>

<p>So I started trying to think of what kind of game would keep her interest and teach her something, and thought that, like the console First Person Shooters, a multiplayer game might keep her interested, and I thought it would be fun to play a turn-based game with my daughter while I'm stuck at work.  But I couldn't find one, so I decided I'd make one.</p>

<h2>My Attempted Solution</h2>

<p>So a turn-based crossword game seemed a natural fit (remember, I want it to be educational, and spelling is a place she (and I think most kids in the SMS-generation) could use some practice).  But the existing ones don't work well for younger kids.  First of all, they get crushed by the bigger words that parents can spell.  Secondly, they get frustrated when they have a pile of letters that don't spell a word (and don't we all).  </p>

<p>I licensed educational word lists from an American University for the content (American English only so far, but I might do UK/Australia as well if I can find a source).  This also has the benefit of excluding those stupid 2-letter and 3-letter so-called "words" that people memorize just to play in word games and never use in conversation or composition.</p>

<p>So I decided the game would give you an adjusted score based on the grade-level of the word and your age.  And I decided that (at least for kids) the game would make sure that there was at least one word at your level that could be spelled with the letters you were given (which can be done in a computer game, but not with letter tiles in a bag).  That also makes it possible to make a "hint" system, so it can keep them from getting stuck (and maybe even teach them new words).</p>

<p><img src="http://www.escortmissions.com/resource/GamePlayCrash1.png?fileId=19154576" alt="Board Became Too Unbalanced" title="GamePlayCrash1.png" border="0" width="231" height="308" style="float:left; margin-right:10px;" />Of course, that creates a problem that I can't end the game when the "bag of letters" is empty - because there isn't one.  So I came up with a different way:  I'm hooking the letters to a <a href="http://chipmunk-physics.net/">Physics Engine</a> and letting gravity end the game.  </p>

<p>There are two cool things about this (aside from the visuals): First, if you intentionally play words that connect other words (which is an additional level of difficulty), then you can keep the board "stable" and play longer.  Second, it enables an interesting "Solitaire" variant, where you are playing by yourself, just trying to see how large a board you can construct before it crashes.  And, just maybe, it's an interesting enough aspect that adults might like to play against each other, as well.<img src="http://www.escortmissions.com/resource/GamePlayFortified.png?fileId=19154577" alt="Board Where Words Interlock" title="GamePlayFortified.png" border="0" width="231" height="308" style="float:right;" /></p>

<h2>The possibilities</h2>

<p>And there are lots of other things I have on the drawing board: letting parents put their children's current spelling lists in the game, using the iOS5 dictionary to make "suggestions" when words are misspelled and to show the definitions of words.</p>

<p>And the most interesting possibility, I got from the name.  My six-year-old told me I should call it "A Million Words" because it sounded cool to her.  I told her the game didn't have that many words in it, but she insisted. And, honestly, I haven't thought of a name I like better (and I've tried, believe me).  So I decided to take the other perspective and try to figure out what I could do to make the game fit the name.  And what I decided was that I was going to track, on the website, the total number of words spelled by all the players of the game, and have a countdown to when A Million Words had been spelled, aggregate, in-game.  And once that milestone was reached (as it hopefully will be), then the countdown would start being broken down by demographics: which age group would reach a Million Words spelled first: the kids or the adults?  I think if I do that right, it could be an interesting marketing opportunity.</p>

<h2>The future</h2>

<p><img src="http://www.escortmissions.com/resource/MillionWords-VINES-Screen-Smaller.png?fileId=19154579" alt="VINES Theme" title="MillionWords-VINES-Screen-Smaller.png" border="0" width="231" height="308" style="float:left;margin-right:10px;" />So, obviously, I'm not done, yet.  I hope to be done by the holidays this year, but we'll see what happens.  I still have a lot to do:</p>

<ol>
<li><p><strong>Game balancing</strong> - getting the scoring right so different ages are competitive</p></li>
<li><p><strong>Monetization</strong> - I think now I want to make it Freemium and sell themed and power-ups like <a href="https://www.facebook.com/TempleRun">Temple Run</a>, but I want to avoid the <a href="http://www.maclife.com/article/news/8yearold_girl_racks_1400_bill_buying_smurfberries_smurfs_village">Smurfberry Fiasco</a></p></li>
<li><p><strong>In-game chat and Matchmaking</strong> - How do I allow that within a family, but don't let strangers chat with your kids.</p></li>
</ol>

<p>And to get all that right, I'm going to need play testers of all different ages, and that means people have to know about the game.  And I'm far more worried about the game launching to obscurity than the idea being stolen.  So I decided to unveil the game and start talking about it.</p>

<h2>TL;DR (In Conclusion)</h2>

<p>I'm writing a crossword game where people of different educational levels can compete on a level playing field (so to speak).  I'm hoping it will be done late this year, and I'm trying to validate that it's the kind of game people might want to play.  I hope that, if you're interested, you'll <a href="http://www.millionwordsapp.com">Sign up for the mailing list</a>.</p>]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-17451474.xml</wfw:commentRss></item><item><title>My Top 5 factors for iOS Contracting Success</title><category>360iDev</category><category>Business</category><category>Careers</category><category>Consulting</category><category>Indie</category><category>Indie Development</category><category>conferences</category><category>iDevBlogADay</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 10 Jun 2012 04:54:01 +0000</pubDate><link>http://www.escortmissions.com/blog/2012/6/10/my-top-5-factors-for-ios-contracting-success.html</link><guid isPermaLink="false">892456:10432592:16655157</guid><description><![CDATA[About a year ago now, I was contemplating leaving my day job and becoming an indie* iOS developer.  Looking back, I can think of 5 things that I did that I think contributed most to that success, and I wanted to take this opportunity to share them with you all.]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-16655157.xml</wfw:commentRss></item><item><title>What I Learned During my Mac App Store Review</title><category>AppStore</category><category>Design</category><category>Mac App Development</category><category>Mac App Store</category><category>Mobile App Dev</category><category>OS X</category><category>Review Process</category><category>UX</category><category>User Experience</category><category>iDevBlogADay</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 19 Feb 2012 00:42:53 +0000</pubDate><link>http://www.escortmissions.com/blog/2012/2/18/what-i-learned-during-my-mac-app-store-review.html</link><guid isPermaLink="false">892456:10432592:15094131</guid><description><![CDATA[<p>Two things happened on Thursday that made it obvious to me what I should write about this week.  Mountain Lion was announced, and <a href="http://www.pdagent.com/appdropota/">my first Mac App</a> was approved for the Mac App Store.  </p>

<p>Even though <a href="http://idevblogaday.com/">iDevBlogADay</a> is about iOS programming, more and more of us are moving from iOS to the Mac.  With the announcement that <a href="http://www.apple.com/macosx/mountain-lion/features.html#gamecenter">GameCenter will be coming to OS X</a>, I'm guessing that more iOS developers might be thinking about coding for the Mac now than might have been last week.</p>

<p>So today I'm going to talk about my experience in getting my first App on the Mac App Store and specifically the differences in the approval process between the Mac App Store and the iOS App Store.  </p>

<h3>I wasn't nearly as prepared as I thought</h3>

<p>I first submitted my Mac App on October 17th, so it took me a day short of 4 months to get my App approved.  That's at least 3 times longer than I ever took to get any of my iOS apps approved.  Partly because the MAS requirements are different, and part because I wasn't paying enough attention. I learned a lot in the process, and I thought I would try to help other people avoid (at least some of) the mistakes I made.  Hopefully this will help you avoid wasting both your time and the review team's time.</p>

<p>Note: I'm only going to focus on the general interest stuff in this post.  Since I wrote a developer tool whose primary purpose is to make things happen on a remote iOS device, it doesn't fit into the expected behavior of a "normal" OS X App.  So I'm going to ignore the issues I had that are specific to the type of App I wrote.</p>

<h3>You can't require 3rd-party Apps to be installed</h3>

<p>My App uses <a href="http://dropbox.com/">Dropbox</a> and <a href="http://boxcar.io/">Boxcar</a> to "push" an iOS App build to all my test devices wirelessly.  And my first rejection was because my app required third party products to be installed.  That was a surprise to me, because I have used several iOS apps that require 3rd party services (how many iOS Apps have you seen that do nothing until you log in with Facebook Connect? - I've seen several).  </p>

<p>So this required me to sit back and do a redesign (or sorts).  Since I had built the entire App intending to rely on those services, I didn't know what to do.  So I added a new preference so that, instead of Dropbox and push notifications, you could use local Web Sharing and send an email to your device with the link to click to install your test App.  It's not nearly as useful as the Dropbox/Boxcar method, and I feel there should be a different solution, but I haven't thought of a better way that could work inside the sandbox restrictions.</p>

<p>But the main thing is, my App is functional (even if in limited way) if you don't have Dropbox and Boxcar, so it got me past that hurdle. (Personal aside: I use both <a href="http://dropbox.com/">Dropbox</a> and <a href="http://boxcar.io/">Boxcar</a> on an almost daily basis and if you don't, and you have both a Mac and either an iPhone or iPad, I think you're missing out on two of the most useful tools available to you).</p>

<h3>The first rule of Sandbox is you don't talk about Sandbox</h3>

<p>Another rejection was because I had a description that said something like "To comply with Sandbox restrictions, if you use Dropbox, it must be installed in $HOME/Dropbox".  It seemed a reasonable thing to me at the time.  In order to write to the Dropbox folder (with sandboxing enabled), I have to put the Dropbox folder path in the temporary exceptions part of my entitlements file.  I understand why Apple doesn't want us doing that - it means that, if they change their policy, then our descriptions would become inaccurate. Also, most users don't understand such things, but hopefully all of mine do, since all this App's users are iOS developers.</p>

<p>I had read the review guidelines, but I would not have thought this wouldn't be okay.  The rule that this violates is: "3.3 Apps with descriptions not relevant to the application content and functionality will be rejected".  So keep in mind that talking about internal Apple procedures might be considered "not relevant" and earn you a rejection.</p>

<h3>Test on Macs with different configurations</h3>

<p>I was also rejected because my App crashed if run on a Mac that didn't have Xcode installed.  The reason for that is beyond the scope of this post (and wouldn't be relevant for most Apps), but it had never occurred to me to try to test my code on a machine without Xcode installed (all my Macs have Xcode - why wouldn't they - it's what I do all day).  I uninstalled Xcode from one of my machines, and sure enough, I got the crash.</p>

<p>It was easy enough to fix the crash, but the important thing I learned was: I needed to have tested on configurations that were more generic than what I normally use.</p>

<h3>They are serious about keeping the user informed</h3>

<p>I was rejected for not including a progress bar.</p>

<p>Well, not explicitly - but there was a point while using my App when there was a pause, and no feedback was being provided to the user.  Stuff was happening in the background, and I wasn't blocking the UI thread or anything, but I wasn't telling the user what the App was doing. It didn't seem (to me at least) that it lasted that long, but they rejected it.</p>

<p>So I put a progress bar on it and, you know what, it greatly improved the user experience. I'm really glad I got rejected for that, because I like it much better now.  </p>

<h3>They are serious about User Experience</h3>

<p>I also got rejected because I didn't specify a minimum window size.  Or at least, adding a minimum window size fixed the problem.</p>

<p>The rejection said that the user could resize the window so small that the app could no longer be used.  They were correct - that window exists to be a drag-and-drop target, and if you make the window small enough, then you can't drop your .app bundle onto it anymore.  My initial reaction was "well, the user shouldn't do that and still expect it to work".  But I was wrong.</p>

<p>The bottom line is that I hadn't even considered what I wanted the App to do if the user resized the window - windows don't get resized on mobile devices, so it hadn't entered my thought process.  After that rejection, I thought about what I wanted the App to do when a resize happened.  And it's a much better App for having thought that through.</p>

<h3>So, in conclusion: It's as much about design as code</h3>

<p>I would say that, more than anything else, I learned that the difference between the User Experience on OS X and iOS is at least as great, if not greater, than the difference between writing code for OS X and iOS.  When I was reading books and teaching myself about programming for the Mac, I tended to focus on the framework changes (e.g. NSView vs. UIView) and the new elements (NSMenu, NSDraggingDestination, NSTask, etc) and I mostly skimmed the design parts.  That was a mistake.  </p>

<p>Over the months, I got very frustrated with the review process.  There were times I thought that I was never going to get the App approved.  But even though people kept telling me that I should just withdraw it and sell it outside the App Store, I'm glad I didn't give up.  It's a much better App than it would have been if I hadn't done what it took to get it approved for the store.</p>

<h3>WARNING: Blatant Self Promotion Ahead</h3>

<p>Don't say I didn't warn you.</p>

<p>If you've read this far, and are an iOS developer, you might be interested in my new App, AppDropOTA. Which you can get for about the cost of the proverbial cup of Starbucks coffee <a href="http://itunes.apple.com/us/app/appdropota/id473083833?ls=1&amp;mt=12">here (App Store link)</a>.</p>

<p>After installing it, you configure it with your Boxcar email address and copy and paste a Dropbox Public folder URL into the Preferences panel. (Also, if you don't have it, you should go install the <a href="http://itunes.apple.com/us/app/boxcar/id321493542?mt=8">Boxcar App</a> and log in to it with your email address). </p>

<p>Now use Xcode to build an iOS App for the device, grab the .app bundle and drop it onto the AppDropOTA window.  Your .app bundle will be turned into an .ipa file and placed into your Dropbox Public folder so it's accessible via HTTP.  Then you'll get a push notification on the Boxcar app on your device(s).  Launch Boxcar (via Notification Center is the quickest way), open the notification, and tap the "View Original" link on the item detail screen. You'll get an alert pop-up prompting you to install your App. Click "Install" and you're done.</p>

<p>When I'm testing, I do this several times a day. I have 9 iOS devices I test with: an iPad 2, an iPhone 4S and an iPhone 4 running 5.0, an iPod Touch running 5.1 beta, an iPad 1, an iPhone 4 and an iPod touch running 4.3 and an iPhone 3G and a iPod Touch running 4.2. (Soon, I hope to convince my customers to drop 4.x support, but haven't, yet).  I learned the hard way that I needed to test on different hardware when I shipped an App update for a customer that immediately crashed on all armv6 devices because of <a href="http://stackoverflow.com/questions/5490432/building-with-llvm-and-any-optimization-causes-app-to-crash-on-startup">this Xcode bug</a>.  I wrote AppDropOTA to speed up the process of getting Apps on all my test devices.</p>

<p>Some people use <a href="http://testflightapp.com/">TestFlight</a> for this.   For me, TestFlight is too public to use for every test build. I use TestFlight for builds I'm sharing with my customers, but I never push something to TestFlight until I've run it on my own device first.  AppDropOTA is what I use for that (and it's faster that TestFlight, too).</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-15094131.xml</wfw:commentRss></item><item><title>Hey, iOS Devs, Nice AppStore. Would be a shame if something were to happen to it…</title><category>AppStore</category><category>Indie Development</category><category>Mobile App Dev</category><category>Programming on iOS</category><category>don't be evil</category><category>don't be scary</category><category>ethics</category><category>evil</category><category>trust</category><dc:creator>Carl Brown</dc:creator><pubDate>Wed, 08 Feb 2012 18:24:34 +0000</pubDate><link>http://www.escortmissions.com/blog/2012/2/8/hey-ios-devs-nice-appstore-would-be-a-shame-if-something-wer.html</link><guid isPermaLink="false">892456:10432592:14933511</guid><description><![CDATA[<p>So, breaking iOS AppStore news this afternoon: <a href="http://mclov.in/2012/02/08/path-uploads-your-entire-address-book-to-their-servers.html">Path uploads your entire iPhone address book to its servers</a>.</p>
<p>This sucks, and I'm pissed off, but not because my data is so precious, but because I'm scared of where this could end up.</p>
<p><a href="http://cheezburger.com/eyedoc/lolz/View/1904797952"><img id="_r_a_1904797952" class="event-item-lol-image" title="Danger!!! Will Robinson! Danger!!!" src="http://images.icanhascheezburger.com/completestore/2009/3/20/128820521566218212.jpg" alt="Danger!!! Will Robinson! Danger!!!" /></a></p>
<p>Many of us in the iOS development community make our living off writing mobile apps.  Even more developers dream of one day being able to write apps as a profession.  One (probably overstated) estimate out this week says <a href="http://gigaom.com/2012/02/07/app-economy-has-created-almost-half-a-million-jobs/">half a million jobs have been created</a>. For those of us that can write code (or are wanting to learn).  Even if that number is inflated, this is still a great thing.</p>
<p>I just got back from the <a href="http://www.360macdev.com/">360MacDev conference</a> in Denver (a spin-off of the <a href="http://360idev.com/">360iDev conference</a> I've attended and loved the last two years).  It was fantastic, and I had a great time.  There's a great community of developers out there who are not just willing but genuinely happy to share what they know with anyone who will listen (although <a href="http://www.cimgf.com/2011/06/03/why-so-serious/">there is the occasional exception</a>).</p>
<p>There's exactly one reason why this is possible - because the ecosystem is still growing, and <a href="http://twitter.com/drance/status/166957191767654400">there are plenty of people who want to pay to get an App written</a>, which is, of course, because <a href="http://www.insidemobileapps.com/2012/01/24/ios-app-downloads-pass-x-x-billion-xxx-billion-paid-to-developers/">Apps are generating a lot of money</a>.</p>
<p>But all is not well.  As the app stores grow more crowded, <a href="http://www.tuaw.com/2012/02/06/apple-warns-of-crackdown-on-app-store-rankings-manipulation/">people are cheating to try to stand out</a>, and worse, users are discovering that <a href="http://www.pcmag.com/article2/0,2817,2383943,00.asp">their iPhones are tracking them everywhere they go</a>, <a href="http://news.cnet.com/8301-13506_3-57333652-17/android-handsets-secretly-logging-keystrokes-sms-messages/">their Android Phones are logging all their keystrokes</a>, <a href="http://www.forbes.com/sites/andygreenberg/2012/02/06/evolving-android-malware-shows-how-evil-apps-will-evade-googles-scans/">malware has invaded the Android market</a> and <a href="http://thenextweb.com/apple/2011/11/25/iphone-will-not-be-safe-from-malware-even-with-apples-rigid-policies-expert-says/">even the iPhone isn't safe from malware</a>.</p>
<p>And when <a href="http://www.infoworld.com/t/microsoft-windows/microsofts-own-numbers-suggest-declining-windows-market-share-855">the size of the market starts shrinking</a>, then <a href="http://www.osnews.com/story/24846/Windows_8_HTML5_JS_Comment_Causes_Panic_Among_Developers">everyone starts to panic</a>, and before long <a href="http://blog.expensify.com/2011/03/25/ceo-friday-why-we-dont-hire-net-programmers/">people don't want to hire you</a> and then <a href="http://open.salon.com/blog/mytechjob/2011/08/14/offshore_outsourcing_is_killing_the_american_dream">the knives come out</a>.</p>
<p>There is one thing that we, as a development community, cannot afford - and that is for the people that download and use our software to be scared of that software.  Because then the need for apps starts to dry up, and the need for mobile programmers will start to drop.</p>
<p>Some of us are old enough that we remember trying to sell shareware on the PC <a href="http://www.atarimagazines.com/compute/issue149/70_The_great_virus_scar.php">back when viruses were rampant</a>.  It was a tough sell.  And some of us remember how hard it was to sell mobile software (for PalmOS or Windows Mobile) in the pre-AppStore world.  Back then, it was a real undertaking just convincing a user that downloading any third-party program was worth their time.  We don't want to go back to that.</p>
<p>This is the golden age of the indie developer (or at least the most golden age so far).  When else in history could  <a href="http://www.iphonesavior.com/2009/02/iphone-developer-one-month-half-a-million-dollars-richer.html">a single person make half a million dollars in a month</a>, or  <a href="http://www.gamasutra.com/view/news/31837/How_One_Man_With_An_Idea_And_1000_Made_The_Global_iOS_Hit_Trainyard.php">make a world-wide hit while commuting</a> or  <a href="https://s3.amazonaws.com/nbpromo/dearzynga.jpg">could 3 people beat a company with almost 1000x more employees</a>?  It's certainly not something I expected a "geek" to be able to do while I was growing up.</p>
<p>And for that to continue, we need our users to trust us, and the easiest and best way to do that is to be worthy of their trust.  There will alway be rogue actors and  <a href="http://forums.toucharcade.com/showthread.php?threadid=121626">assholes that try to scam users</a>.  But those apps are <a href="http://venturebeat.com/2012/02/07/apple-pulls-cloned-games-from-app-store/">short-lived</a> (although not short enough), <a href="http://applenapps.com/feature/why-do-bad-apps-make-it-to-the-top-of-the-charts-temple-run-vs-temple-jump">poorly reviewed</a>, and there's very little we can do about individual fraudsters, or <a href="http://twitter.com/NickSheinberg/status/165475877596045312">users who don't pay attention</a> to which developer an app came from.</p>
<p>But when a respectable, well-written App like Path can't be trusted, then we all have a problem.  The <a href="http://theultralinx.com/2011/12/path-beautiful-social-journal-android-ios-app.html">app is beautiful</a>, <a href="http://news.cnet.com/8301-19882_3-57333449-250/new-path-2.0-automatically-chronicles-shares-your-life/">obviously professionally designed and written</a>, and <a href="http://www.zdnet.com/blog/feeds/how-path-became-my-favorite-social-app-of-2011/4440">well reviewed</a>.  It didn't need to be slimy to be successful.</p>
<p>And what we, as professional mobile app developers, of whatever flavor, need to take to heart, in my opinion, is this: <strong>Don' t Be Scary</strong>.</p>
<p>If the professional, successful App Designers and Programmers agree to put what's best for the ecosystem first, then companies will stop risking all of our long-term success, for a short-term advantage.</p>
<p>Yes, it's less work to <a href="http://www.whoishostingthis.com/blog/2010/03/31/quip-privacy-fail-private-photos/">store your users' pictures unencrypted and unprotected on a server</a> or <a href="http://www.digitaltrends.com/mobile/viaforensics-10-pct-of-ios-android-apps-store-clear-text-passwords/">store plain-text passwords in your app</a>, and if you want your app to be more popular, it's tempting to <a href="http://mashable.com/2008/07/24/iphone-game-security/">harvest your users' contact info</a>, or <a href="http://forums.toucharcade.com/showthread.php?t=121800">jack up your App ranking</a>,  but, even if you have <a href="http://community.nuance.com/blogs/dragon/archive/2009/12/08/what-dragon-dictation-for-the-iphone-does-and-doesn-t-do-with-your-contacts.aspx">a legitimate non-spammy reason for uploading your customers' info</a>, just don't.  Please, please, please always err on the side of earning your users' trust.  Yes, it might be more work for your current app, but remember, your current users are the potential users for all our apps, and whatever app you're working on next.</p>
<p>And yes, some of us will piss off some people who want us to make apps for them by refusing to scare our users, but there will be other people who want us to build apps.</p>
<p>We will hopefully all be writing apps for years… Unless our users stop being our users.</p>
<p>Don't forget that very few mobile apps are "necessary."  They're a luxury - and many (if not most) <a href="http://www.miasmi.com/2011/09/appstore-side-effect-software-as-an-impulse-purchase/">app purchases are quick impulse buys</a>.  It probably won't take much fear on the part of an individual user before he or she decides that, even if the App is worth 99 cents, it <a href="http://twitter.com/#!/singer/status/167052551726964737">isn't worth the risk that it might steal their data</a>.</p>
<p>Then we all lose.</p>
<p>(Path Story link Via <a href="http://twitter.com/mattgemmell/status/166965305560666112">@mattgemmell</a>.)</p>]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-14933511.xml</wfw:commentRss></item><item><title>HTTP Testing to the edge on iOS: The School of Hard Mocks</title><category>Mobile App Dev</category><category>Unit Testing</category><category>iDevBlogADay</category><category>iOS</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 30 Oct 2011 04:52:56 +0000</pubDate><link>http://www.escortmissions.com/blog/2011/10/30/http-testing-to-the-edge-on-ios-the-school-of-hard-mocks.html</link><guid isPermaLink="false">892456:10432592:13522039</guid><description><![CDATA[<p>I'm a big fan of Automated Testing, even on iOS projects, but even when I was doing mostly Ruby, Java and C# work, I was never a big user of mock objects.</p>

<p>Now, I'll admit that Mock objects can be useful under some circumstances, but I've seen them used too often in cases where a bunch of different developers each build their own little fiefdoms of their own code surrounded by Mock Objects where they interact with anything else.  Each developer's code runs perfectly when being tested against Mock input, but when you put all that code together, you can't get a transaction working end-to-end, because the real world doesn't obey the assumptions inherent in the Mocks.</p>

<p>So the Automated tests I write have more of a tendency to be more like what are called "Integration Tests", even though I use "Unit Testing Frameworks" to write them.</p>

<p>When you combine that with the fact that I write a lot of iOS apps that talk to web servers, I want a way to test how my code talks to HTTP. And I want to know that my code handles things even when any library I happen to be using hands me errors to deal with.</p>

<p>When I first solved this problem years ago, we were using the <a href="http://code.google.com/p/google-toolbox-for-mac/">Google Toolbox for Mac</a> as our unit test framework, because SenTest didn't work well back then.  So, at the time, I built a solution based on GTM, but I went recently to try to recreate that solution for a new customer, and I realized that the files I had used had been deleted from GTM.</p>

<p>So I went spelunking back in the history of GTM, and pulled out the last version of the the files I needed before they were removed, and put them up on github in a new repository I'm calling <a href="https://github.com/carlbrown/SyntheticServerTest">SyntheticServerTest</a>.</p>

<p>The way you use it is to look at the <a href="https://github.com/carlbrown/SyntheticServerTest/blob/master/SyntheticServerTestTests/SyntheticServerTestTests.m">example test file</a>.</p>

<p>You just have to run:</p>

<blockquote>
<pre><code>[testServer startServerWithDocumentRoot:]
</code></pre>
</blockquote>

<p>With a document root directory that contains web content (I usually use 'curl -O' to pull known pages (either good or errors) from the server and write them to that directory), and have a mechanism so, that, while your test is running, the host part of the URL gets replaced with </p>

<blockquote>
  <p>@"localhost:%d",[testServer port]</p>
</blockquote>

<p>and the test HTTP server, running in the background (in the simulator or on the device), will get the HTTP request and hand you back the test data file in response.  </p>

<p>This way, you can test your App's entire HTTP stack, including any parsing libraries you may be using, with both real data (that doesn't require you to be on line) and with bad data, to make sure you are correctly handling whatever errors your parsing or network library is throwing off.</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-13522039.xml</wfw:commentRss></item><item><title>Using Regular Expressions Part 2 - The Cocoa Connection</title><category>Cocoa</category><category>github</category><category>iDevBlogADay</category><category>regex</category><category>regular expressions</category><dc:creator>Carl Brown</dc:creator><pubDate>Sat, 15 Oct 2011 21:10:15 +0000</pubDate><link>http://www.escortmissions.com/blog/2011/10/15/using-regular-expressions-part-2-the-cocoa-connection.html</link><guid isPermaLink="false">892456:10432592:13286186</guid><description><![CDATA[<p>Last time, in <a href="http://www.escortmissions.com/blog/2011/10/2/using-regular-expressions-and-retaining-your-sanity.html">Part 1</a> of this series, I wrote about the basics of regular
expressions, and the phrases I tend to use. Today, I'm going to talk about the
mechanics of how I use Regular Expressions in Cocoa.</p>

<h2>But first, an historical diversion</h2>

<p>In my opinion there are, two different ways that programming languages
implement Regular Expressions: The perl/ruby way, and the Java/C#/Python/Cocoa
way.</p>

<p>In ruby and perl, regexes are implemented directly on the String type, whereas
in the other languages, there a separate object that contains the
functionality. Here's what you need to know to do a regex substitution on a
string in ruby:</p>

<pre><code>myString.sub('pattern','replacement')
</code></pre>

<p>clean, easy, and immediately useable if you know what pattern you want to use.</p>

<p>Here's what you need to know to do the same thing in Cocoa:</p>

<pre><code>+[NSRegularExpression regularExpressionWithPattern:(NSString *) pattern 
    options:(NSRegularExpressionOptions)options error:(NSError **) error]

-[NSRegularExpression replaceMatchesInString:(NSMutableString *) string 
    options:(NSMatchingOptions)options range:(NSRange)range 
    withTemplate:(NSString *)template]
</code></pre>

<p>which is not clean, not easy and contains a bunch of stuff you have to go look
up to be able to get started. What are <code>NSRegularExpressionOptions</code> and
<code>NSMatchingOptions</code>? What's a <code>template</code>? Do I <em>really</em> have to create an
<code>NSRange</code> for this? And that leads to the obvious question: <strong>Is all this
effort really worth it?</strong></p>

<p>Now I don't know about you, but I don't want to spend any effort remembering
any of those option parameters, and I don't want to take the time to look them
up any time I want to use a regular expression. To me, the beauty of
Objective-C is that it gives us the ability to build most of what you need to
know directly into the method signatures.</p>

<h2>Let's simplify things a little</h2>

<p>So that's what I did. For the rest of this post, I'll be using the categories
on NSString found in a repo I wrote on github called <a href="https://github.com/carlbrown/RegexOnNSString">RegexOnNString</a>.</p>

<p>There are three basic methods I wrote:</p>

<pre><code>-(NSString *) [NSString stringByReplacingRegexPattern:(NSString *)regex 
    withString:(NSString *) replacement]
</code></pre>

<p>which takes a string, finds the occurrences of the <code>regex</code> pattern and
replaces them with the string <code>replacement</code>.</p>

<pre><code>-(NSArray *) [NSString stringsByExtractingGroupsUsingRegexPattern:(NSString *)regex]
</code></pre>

<p>which gives you an array of all the pattern groups (things in parentheses) it
found in your string, and</p>

<pre><code>-(BOOL) [NSString matchesPatternRegexPattern:(NSString *)regex]
</code></pre>

<p>which just tells you whether a pattern is present in your string or not.</p>

<p>There are two additional, optional parameters that you can add,
<code>caseInsensitive:(BOOL) ignoreCase</code> and <code>treatAsOneLine:(BOOL)
assumeMultiLine</code>.</p>

<p><code>caseInsensitive</code> is hopefully self explanatory, and <code>treatAsOneLine</code> just
means that you expect that your string has (or might have) newline (<code>\n</code>)
characters in it, and you want them to be treated like any other character.</p>

<p>To get them, you just need to grab the MIT-licensed code <a href="https://github.com/carlbrown/RegexOnNSString">from github</a>, include <code>NSString+PDRegex.h</code> and <code>NSString+PDRegex.m</code> in your project, and put </p>

<pre><code>#import "NSString+PDRegex.h"
</code></pre>

<p>in the top of your source file.</p>

<h2>How about some examples?</h2>

<p>The simplest of these is the one that returns the boolean, like so:</p>

<pre><code>if(![emailAddress matchesPatternRegexPattern:@"@.*\\\\..*"]) {
    NSLog(@"If the user is going to give us a fake email address" \
          @" they could at least try and make it look like one" \
          @" by making sure it has an at-sign and a dot in it.");
}
</code></pre>

<p>I use this a lot for string validation.  No sense in trying to send an email if there isn't an at-sign in it, and no use trying to convert an <code>NSString</code> to an <code>NSURL</code> if the string doesn't at least contain '<code>://</code>'. (Note that I have to use two backslashes there because a <code>@"@.*\\."</code> will cause Xcode to generate a: <code>Lexical or Preprocessor Issue: Unknown escape sequence '\\.'</code> warning).</p>

<p>The one I use next most often is the one that returns an <code>NSString</code>.  I use this one for extracting substrings.  For example, in:</p>

<p>&lt;Warning: Shamless Plug&gt; a Mac application I recently released as an Open Beta that <a href="http://www.pdagent.com/AppDropOTA/">helps iOS developers deploy Apps to their test devices without having to use a USB cable</a>  &lt;End Shamless Plug&gt; </p>

<p>I'm getting a string that is the path of the .app file that the user dragged-and-dropped onto my App (and it's either a path if they dropped it onto the App Icon in the Dock, or a URL if they dropped it onto the Window).  From that string, I need to figure out what their iOS App is named (so I can use that name in the notification).  I use the <code>stringByReplacingRegexPattern</code> method for that.  I could use <code>[[NSString lastPathComponent] stringByDeletingPathExtension]</code> for that, but by using regexes, I don't have to go look up the path component methods, like I just did to put them in this post.  But an even better example from that app is:</p>

<pre><code>NSString *dSYMPath = [droppedPath stringByReplacingRegexPattern:@"\\\\.app$" withString:@".dSYM"];
</code></pre>

<p>So that I can save off the dSYMs so that the user can get to the symbol data for that build if they need it later.</p>

<p>I also use it so that, in order for my App to get the user's Dropbox's public URL, I can let the user drop any Public URL that Dropbox gives them into the preferences panel, and I can use:</p>

<pre><code> NSString *dbPublicRoot=[pastedLink stringByReplacingRegexPattern:
    @"^(http://dl.dropbox.com/u/[0-9][0-9]*)[^0-9]*.*$" withString:@"$1" caseInsensitive:NO];
</code></pre>

<p>so that I don't have to rely on the user to correctly truncate the URL at the right place, and the user doesn't have to think about it.</p>

<p>The last method, the one that returns the <code>NSArray</code>, I don't use as often, but when I do, it can save me a lot of effort.  For example, recently I was implementing a Tic-Tac-Toe game as a programming exercise as part of an interview process.  So when I was shipping turns between the two players, I was actually sending one string:</p>

<pre><code>NSString *stringForThisMove = [NSString stringWithFormat:
      @"Move %@=Player %@ to Square %@\n",
      [move TurnNumber],
      playerThatMoved,
      [move SquarePlayed]];
</code></pre>

<p>and then on the receiving end, I used:</p>

<pre><code>NSArray *extractedStrings=[moveString
       stringsByExtractingGroupsUsingRegexPattern:
       @" *^Move  *([0-9]) *= *Player  *([X|O])  *to  *Square  *([0-9]) *$"
       caseInsensitive:YES treatAsOneLine:YES];
</code></pre>

<p>from which <code>[extractedStrings objectAtIndex:0]</code> was the move number, <code>[extractedStrings objectAtIndex:1]</code> was the player (@"X" or @"O") and <code>[extractedStrings objectAtIndex:2]</code> was the number of the square they moved to (where the first row of the board was 1-2-3 and the last row was 7-8-9).</p>

<p>Now, there are many other ways I could have encoded that, but the nice thing about using strings for it was that anyone looking at the intermediate value (in the debugger or logs) could easily tell what move was being talked about at that point, and if I were ever to need to come back to this code later, @"Move 1=Player X to Square 1" will make sense to me (after all, that kind of notation has been of use in the Chess world for hundreds, if not thousands of years).</p>

<h2>But aren't Regular Expressions slower?</h2>

<p>Well, define slow :-).</p>

<p>In the test suite for my <a href="https://github.com/carlbrown/RegexOnNSString">RegexOnNString</a> category, I have a test that does 1000 string replaces:</p>

<pre><code>for (uint i=0; i&amp;lt; 1000; i++) {
    if (lastTimeString) {
        NSString *currentNumberString=[NSString stringWithFormat:@"%u",i];
        NSString *replacementString=[lastTimeString stringByReplacingRegexPattern:@"[0-9][0-9]*" withString:currentNumberString caseInsensitive:NO];
        STAssertEqualObjects(replacementString, currentNumberString, @"regex replace failed");
    }
    lastTimeString=[NSString stringWithFormat:@"%u",i];
    i++;
}
</code></pre>

<p>Now each of those regex's is different (by design), so I can't compile them, and I'm creating and throwing away my <code>NSRegularExpression</code> object and a temporary <code>NSString</code> every run.  So it's near a worst-case scenario. By way of comparison, I do another loop of 1000 replaces, using <code>[NSString stringByReplacingOccurrencesOfString: withString:]</code> to see how much slower the regex makes the task.</p>

<p>The output from running the test on my 4thGen iPod touch is:</p>

<pre><code>2011-10-15 17:23:00.748 RegexOnNSStringIOSExample[224:607] 1000 regex replaces took 0.167364 seconds
2011-10-15 17:23:00.776 RegexOnNSStringIOSExample[224:607] 1000 String replaces took 0.025167 seconds
2011-10-15 17:23:00.777 RegexOnNSStringIOSExample[224:607] Simple String substitution 6.650140 times faster
</code></pre>

<p>and on my daughter's 2nd Gen iPod touch, the output is:</p>

<pre><code>2011-10-15 17:33:37.631 RegexOnNSStringIOSExample[183:307] 1000 regex replaces took 0.641442 seconds
2011-10-15 17:33:37.756 RegexOnNSStringIOSExample[183:307] 1000 String replaces took 0.119230 seconds
2011-10-15 17:33:37.768 RegexOnNSStringIOSExample[183:307] Simple String substitution 5.379869 times faster
</code></pre>

<p>So yes, it's slower.  It takes 0.17 milliseconds on a 4th-gen touch and 0.64 milliseconds on a 2nd-gen touch.  And it's between 5 and 7 times slower than <code>stringByReplacingOccurrencesOfString:withString</code>.  If 0.52 ms really matters in your code when running on a 2nd-gen touch, then you should use <code>stringByReplacingOccurrencesOfString:withString</code> instead.</p>

<h3>So, in conclusion,</h3>

<p>I hope you found this post useful.  If you need to do string manipulation, Regular Expressions are a time-tested way to do that, and I hope the extra methods I've talked about here will simplify things if you want to do string manipulation in your Cocoa code.</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-13286186.xml</wfw:commentRss></item><item><title>Using Regular Expressions and Retaining your Sanity</title><category>iDevBlogADay</category><category>regex</category><category>regular expressions</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 02 Oct 2011 05:40:11 +0000</pubDate><link>http://www.escortmissions.com/blog/2011/10/2/using-regular-expressions-and-retaining-your-sanity.html</link><guid isPermaLink="false">892456:10432592:13049722</guid><description><![CDATA[<p>At a recent Austin, Texas <a href="http://www.cocoacoder.org/CocoaCoder.org/Hello.html">Cocoacoder</a> meeting, I made an offhand comment giving someone a regular expression that would help with a problem they were having. That led to two things. First, I was asked to put together a presentation (which I&#8217;ve been working on) on using regular expressions to give at an upcoming CocoaCoder meeting, and second, I was asked why on Earth anyone would use something as opaque and unmaintainable as a regular expression in this day and age.</p>

<blockquote>
<p><a href="http://regex.info/blog/2006-09-15/247">Some people, when confronted with a problem, think
“I know, I&#8217;ll use regular expressions.” Now they have two problems.</a> </p>
</blockquote>

<p>Or so goes the old saying. Personally, I rarely find this to be true. On the occasions when I can identify with that quote, it&#8217;s because I&#8217;m trying to deal with a regex written by someone who, in my opinion, tried to do far too much at once.</p>

<p>I have a certain philosophy that I try use regular expressions that seems to keep me out of trouble. In this post, I&#8217;m going to try to make a set of rules out of that philosophy. They are:</p>

<ol>
<li>Limit yourself to only the basic meta-characters.</li>
<li>Favor clarity over brevity.</li>
<li>Take more smaller bites.</li>
<li>Beware of greedy matching</li>
</ol>

<p>Let&#8217;s break these down.</p>

<h2 id="limityourselftoonlythebasicmeta-characters.">1. Limit yourself to only the basic meta-characters.</h2>

<p>Pretty much every regex tutorial or man page has a giant laundry list of what characters in a regular expression match what characters in the string you&#8217;re trying to match. I ignore most of these and look them up when I have to (which is only when I&#8217;m looking at other people&#8217;s code). I use a few &#8220;phrases&#8221; over and over, so let me go through some of those to try to give you some examples:</p>

<h4 id="meansthejunktotheleftofwhatiwant">^.* means &#8220;the junk to the left of what I want&#8221;</h4>

<p>This breaks down as <strong>^</strong> (the beginning of the string) followed by <strong>.*</strong> any number of any character. Likewise:</p>

<h4 id="meansthejunktotherightofwhatiwant">.*$ means &#8220;the junk to the right of what I want&#8221;</h4>

<p>This breaks down as any number of any character <strong>.*</strong> followed by <strong>$</strong> (the end of the string)</p>

<h4 id="meansanumberwithatleastonedigit">[0&#8211;9][0&#8211;9]* means &#8220;a number with at least one digit&#8221;</h4>

<p>The brackets (<strong>[</strong> and <strong>]</strong>) mean &#8220;any of the characters contained within the brackets&#8221;. So this means 1 character of 0&#8211;9 (so 0 1 2 3 4 5 6 7 8 or 9) followed by zero or more of the same character.</p>

<h4 id="a-za-zmeansanycharacterthatsnotaletter">[^A-Za-z] means &#8220;any character that&#8217;s not a letter&#8221;</h4>

<p>The <strong>^</strong> as the first character inside the brackets reverses means &#8220;not&#8221; so instead of meaning &#8220;any letter&#8221; it means &#8220;anything that isn&#8217;t a letter&#8221;. Likewise, <strong>[^0-9]</strong> means &#8220;anything that isn&#8217;t a number&#8221;.</p>

<h4 id="aliteraldot">\. a literal dot</h4>

<p>So this is what you&#8217;d use to match the <strong>.</strong> in <strong>.com</strong></p>

<h4 id="stuffstuffiwanttorefertolater"><span class="math">\( …stuff… \)</span> stuff I want to refer to later</h4>

<p>This causes the string matched inside the parenthesis to be retrieved later.</p>

<h2 id="favorclarityoverbrevity">2. Favor Clarity Over Brevity</h2>

<p>There are a lot of shortcuts you can take, like <strong>\w</strong> means &#8220;any character that appears in a word&#8221; (I know because I just looked it up). Don&#8217;t use it or things like it. Because <strong>\W</strong> (that&#8217;s a capital &#8216;W&#8217;) means &#8220;not a word&#8221; and they look too much alike. Also, the mnemonic is rubbish, does &#8220;W&#8221; stand for &#8220;Word&#8221; or &#8220;Whitespace&#8221;? Use [A-Za-z] instead. It&#8217;s clearer when you&#8217;re writing it, and clearer when you look at it later. It&#8217;s more keystrokes, but it&#8217;s worth it. Likewise there&#8217;s a &#8216;+&#8217; which means &#8220;one or more&#8221; so [0&#8211;9]+ is equivalent of [0&#8211;9][0&#8211;9]<em>, but if you always do it the second way, there&#8217;s one less special character to remember and you won&#8217;t ever accidentally type [0&#8211;9]</em> when you meant [0&#8211;9]+ and accidentally match nothing.</p>

<h2 id="takemoresmallerbites.">3. Take more smaller bites.</h2>

<p>This is really the core of it. I often use several different regular expressions to get one string I want. It&#8217;s more typing and it may potentially create some intermediate strings that have to be thrown away, but it&#8217;s much easier to read. So if I were trying to extract an HREF link from an HTML document, for example, I&#8217;d use two regular expressions:</p>

<blockquote>
<p>^.*href=[&quot;&#8217;]</p>
</blockquote>

<p>and</p>

<blockquote>
<p>[&quot;&#8217;].*$</p>
</blockquote>

<p>The first one of those matches everything up to the single or double quote before the URL, and the second one matches from the quote after the URL through the rest of the string. I use a substitute mechanism to throw both of those parts of the string away, and I&#8217;m left with the URL I want.
*(Note - Those regex&#8217;s are simplified for illustration purposes. For example, the <strong>=</strong> sign might have whitespace around it, etc.) </p>

<h2 id="bewaregreedymatching">4. Beware greedy matching</h2>

<p>People get themselves in trouble by forgetting about <strong>greedy matching</strong> which is the requirement that a <strong>*</strong> in a pattern matches as much as it can. So let&#8217;s say we were doing URL extraction again, and you used the pattern:</p>

<h4 id="href..">^.<em>href=&#8220;<span class="math">\(.*\)</span>&#8221;.</em>$</h4>

<p>In theory, that should say (out of the whole string, from beginning (<strong>^</strong>) to end (<strong>$</strong>) grab the thing in between the quotes right after the string <strong>href=&quot;</strong> and remember it. However, if I gave you the string <strong>&lt;a href=&#8220;http://1.example.com/&#8221;&gt;This is a link&lt;/a&gt; but &lt;a href=&#8220;http://2.example.com/&#8221;&gt;This is a link, too.&lt;/a&gt;</strong> and you ran your regex against it, you&#8217;d get <strong>http://1.example.com/&#8220;&gt;This is a link&lt;/a&gt; but &lt;a href=&#8221;http://2.example.com/</strong> as what your regex remembered, because the <strong>&#8220;.*&#8221;</strong> grabbed everything between the very first quote and the very last quote. In this case, either use <strong>^.<em>href=&#8220;<span class="math">\([^"]*\)</span>&#8221;.</em>$</strong> (replacing the <strong>.*</strong> with <strong>[^&quot;]</strong> so that the <strong>.*</strong> doesn&#8217;t match quotes) or use more regex&#8217;s, and take a smaller bite with each.</p>

<p>That&#8217;s a long enough post for now. Next time, I&#8217;ll introduce an Objective C category I&#8217;m working on and will hopefully have done by then which will simplify using NSRegularExpression, and we'll work through more examples.</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-13049722.xml</wfw:commentRss></item><item><title>360iDev Conference Notes, or How I Spent my September Vacation</title><category>360iDev</category><category>Indie Development</category><category>Mobile App Dev</category><category>conferences</category><category>iDevBlogADay</category><dc:creator>Carl Brown</dc:creator><pubDate>Sun, 18 Sep 2011 02:36:32 +0000</pubDate><link>http://www.escortmissions.com/blog/2011/9/17/360idev-conference-notes-or-how-i-spent-my-september-vacatio.html</link><guid isPermaLink="false">892456:10432592:12897662</guid><description><![CDATA[<p>This Thursday, I got back home after four days at 360iDev 2011 in Denver.  I went last year, which was easy for me because it was in Austin where I live.  I was concerned about the extra time and extra money it was going to take to go this year, since it was in Denver.  Now that I'm back, I'm so glad I went.  I have no hesitation about recommending it to other people, so that's what I'm about to do. This post is going to be long, because there was a lot going on, so feel free to skim the headlines and skip the things that aren't relevant to you.</p>

<h2>Let's start with value.</h2>

<p><img src="http://www.escortmissions.com/resource/pow2.png?fileId=14202479" alt="Pow screen from Mike Berg class" title="pow2.png" border="0" width="253" height="337" style="float:right;" /></p>

<p>My total out-of-pocket (not including food) for this 3-day conference plus one day of workshop was $1215.96.  $299 for the conference ticket, $638.57 for the hotel, $195.40 for plane tickets (from Southwest Airlines) and some misc stuff like cab fare.  By contrast, two days plus a workshop of an iOS conference coming up in a couple of months is $895 for just the conference+workshop (no lodging or travel) - and that's the early bird pricing.</p>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-12897662.xml</wfw:commentRss></item><item><title>Steal This Code and Protect Their Data: Simplifying KeyChain Access</title><category>Bindings</category><category>Cocoa</category><category>Keychain</category><category>Mac App Development</category><category>Mobile App Dev</category><category>Open Source</category><category>Security</category><category>Security Programming</category><category>github</category><category>iDevBlogADay</category><dc:creator>Carl Brown</dc:creator><pubDate>Sat, 03 Sep 2011 18:46:59 +0000</pubDate><link>http://www.escortmissions.com/blog/2011/9/3/steal-this-code-and-protect-their-data-simplifying-keychain.html</link><guid isPermaLink="false">892456:10432592:12721510</guid><description><![CDATA[<p><a href="http://twitter.com/invalidname/status/107106415839162368"><img style="float: left;" title="invalidname Meet iPhone Explorer smaller.png" src="http://www.escortmissions.com/resource/invalidname%20Meet%20iPhone%20Explorer%20smaller.png?fileId=13975932" border="0" alt="Invalidname Meet iPhone Explorer" width="259" height="125" /></a> <a href="http://twitter.com/invalidname/status/107106591857328128"><img style="float: left;" title="invalidname Learn Keychain smaller.png" src="http://www.escortmissions.com/resource/invalidname%20Learn%20Keychain%20smaller.png?fileId=13975936" border="0" alt="Invalidname Learn Keychain" width="268" height="106" /></a> <a href="http://twitter.com/noel_llopis/status/109091397302370304"><img style="float: left;" title="Noel Llopis Keychain is Obtuse smaller.png" src="http://www.escortmissions.com/resource/Noel%20Llopis%20Keychain%20is%20Obtuse%20smaller.png?fileId=13975938" border="0" alt="Noel Llopis Keychain is Obtuse" width="264" height="70" /></a></p>

<p> </p>

<div style="clear: both;">
<p> </p>
<h2>The Code</h2>
<p>The last couple of months, I've been working on my first Mac App (more on that in a later post).  As part of this App, I'm calling a REST API that requires that I have the user's password for that service to use in the API calls.  Although that API is a minor part of the App, and although the service doesn't have horrible consequences if someone gets the user's password for it (in my opinion at least), there was no way I was going to store that password on disk unencrypted.  After all, users have a bad tendency to use the same password for multiple services, and one of those other services might contain important information.</p>
<p>So I dug into the Keychain documentation, and it took me a while to figure it out.  Meanwhile, I was learning Bindings for the Mac App, since in my time programming iOS, I'd never had the chance to use Bindings before.  And I decided that it was a good opportunity for me to combine the two and learn something, and maybe help someone else along the way. I fought with it off and on for a month or so, and released it under the MIT license at the end of July.</p>
<p><a href="https://github.com/carlbrown/PDKeychainBindingsController">This is the result</a>.  It's a project that simplifies using the Keychain by making it accessible through methods patterned after NSUserDefaults.</p>
<h2>Their Data</h2>
<p>So here's the problem, anything you persist in your App unencrypted can easily be extracted by a program like <a href="http://www.macroplant.com/iphoneexplorer/">this</a>,   If you put your own encryption in your App, you could run afoul of Apple's encryption policies and potentially Law Enforcement Organizations.  The KeyChain makes it possible to protect the data that you persist from (all but the most determined) prying eyes.</p>
<p>Now many programmers don't think they're persisting any data that they need to protect, because they don't get passwords from their users.  But think for a minute about other information the user might not want anyone to be able to see.  And then think about any data that you wouldn't want the user to be able to read (or alter).  I don't write games myself, but when I talk to my friends that do, I hear them complain a lot about people "cheating" by trying to hack their save games.  While you wouldn't want to stick a huge amount of data in the keychain, some strategically selected pieces of data (current amount of "gold" the user has, or maximum hit points) might be appropriate to store in a safer location than in a file on disk.</p>
<h2>How to Use it</h2>
<p>I intentionally wanted to write this library to be as easy to use as possible, so I decided to make it match the semantics of NSUserDefaults, since that's in every iOS programming book I've ever seen, so in theory, it should be well known to anyone needing it.</p>
<p>To install it, check it out from <a href="https://github.com/carlbrown/PDKeychainBindingsController">github</a>, grab the 4 files in the <a href="https://github.com/carlbrown/PDKeychainBindingsController/tree/master/PDKeychainBindingsController">PDKeychainBindingsController folder</a> (the .h and .m files for PDKeychainBindings and <span style="white-space: pre;"> </span>PDKeychainBindingsController) and drag them into your project in XCode.</p>
<p>Then, when you would normally have used:</p>
<p><span style="font-family: 'Courier New'; font-size: 12px;"><strong>[NSUserDefaults standardUserDefaults]</strong></span></p>
<p>You should be able to call</p>
<p><strong><span style="font-family: 'Courier New'; font-size: 12px;">[PDKeychainBindings sharedKeychainBindings]</span><br /></strong></p>
<p>instead (at least for the most common methods).  If you're doing an OS X App, and you're binding a NSTextField or the like, then where you would have called</p>
<p><span style="font-family: 'Courier New'; font-size: 12px;">[NSUserDefaultsController sharedUserDefaultsController]</span></p>
<p>use</p>
<p><span style="font-family: 'Courier New'; font-size: 12px;">[PDKeychainBindingsController sharedKeychainBindingsController]</span></p>
<p>instead (again, at least for the most common methods).</p>
<p>There are two differences, the first is that the Keychain API only wants to work with Strings (well, NSStrings).  So if you want to store something else in there, <strong>you need to convert it to a string yourself</strong> before you put it in the keychain (and change it back it when you take it out).</p>
<p>The second is that, in order to simplify it, I took out the need to run the synchronize method.  As soon as you call the set method, it gets persisted.</p>
<p>I'd like to thank <a href="http://twitter.com/invalidname">Chris Adamson</a> and <a href="http://twitter.com/noel_llopis">Noel Llopis</a> for unwittingly helping me decide on the topic for this post.</p>
</div>
]]></description><wfw:commentRss>http://www.escortmissions.com/blog/rss-comments-entry-12721510.xml</wfw:commentRss></item></channel></rss>