<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"> <channel><title>The CodeCropper</title> <link>http://blog.codecropper.com</link> <description>Will code for food</description> <lastBuildDate>Fri, 16 Mar 2012 02:10:26 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/TheCodecropper" /><feedburner:info uri="thecodecropper" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>TheCodecropper</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><title>GitHub 2 Evernote – Making the watch button useful again.</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/iUH0cHjHqxE/</link> <comments>http://blog.codecropper.com/2012/02/github-2-evernote-making-the-watch-button-useful-again/#comments</comments> <pubDate>Tue, 28 Feb 2012 18:10:51 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[django]]></category> <category><![CDATA[evernote]]></category> <category><![CDATA[github]]></category> <category><![CDATA[python]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=432</guid> <description><![CDATA[I love GitHub. But there was a feature that was never very useful to me (and it seems I&#8217;m not alone at this): watched repositories. When I see a repo that I might be remotely interested in, I start watching it. Sort of a bookmark since GitHub does not have a &#8220;Like&#8221; button. But then [...]]]></description> <content:encoded><![CDATA[<p>I love <a
title="GitHub" href="https://github.com" target="_blank">GitHub</a>. But there was a feature that was never very useful to me (and it seems <a
title="HN discussion on GitHub" href="http://news.ycombinator.com/item?id=3640856" target="_blank">I&#8217;m not alone</a> at this): watched repositories.</p><p>When I see a repo that I might be remotely interested in, I start watching it. Sort of a bookmark since GitHub does not have a &#8220;Like&#8221; button. But then what? One day I want to use a library I&#8217;m sure I&#8217;ve added to my watched repos but&#8230; what was the name again? Damn these non descriptive project names! Well, <a
title="WTF???" href="https://github.com/gpambrozio/GusUtils" target="_blank">I&#8217;m guilty of that one too</a>&#8230;</p><p>There should be a solution to this but I could not find any. And being a developer, avid user of <a
title="Evernote" href="http://www.evernote.com/" target="_blank">Evernote</a> and wanting a project to use as an exercise to learn Django I decided to take matters into my own hands and do it myself.</p><p>So I made a Django app that will take every watched repositories of a GitHub user (or even more than one), scrape their readmes and add them as notes in an Evernote notebook.</p><p>I&#8217;ve been testing it with my GitHub repos and my Evernote for a few weeks and it really changed the way I work with GitHub. I&#8217;m using Evernote to find &#8220;lost&#8221; repos almost every day now and I started watching even more repos than before. I had 100 watched repositories when I started and now I&#8217;m at 130.</p><p
style="text-align: left;">So I decided it was time to release <a
title="GitHub 2 Evernote" href="http://www.gustavo.eng.br/gh2evernote/" target="_blank">my baby</a> in the wild. After a few days waiting for GitHub to give me their blessing (I wanted to make sure I was not violating any TOU) and authorize me to use their logo (I made a very cute octophant but they did not like that and I had to replace it with their regular octocat) now I can release it. And it&#8217;s the right day for it because a lot of <a
title="HN thread about GitHub watched repos" href="http://news.ycombinator.com/item?id=3640856" target="_blank">people are complaining about the watch button on HN</a>. I&#8217;m limiting registrations to 100 users so I can see how my server reacts but since I&#8217;m using Heroku for hosting I think I can just scale up if there&#8217;s need for it. I&#8217;ll release more spots as soon as I can guarantee the server can handle.</p><p>The process is simple: just <a
title="GitHub 2 Evernote" href="http://www.gustavo.eng.br/gh2evernote/" target="_blank">authorize</a> access to your Evernote account (you have one, don&#8217;t you?), enter your GitHub user name, choose an Evernote notebook (I recommend you create a new one just for this) and you&#8217;re done. The readme of every watched project you have will be added as a note to your chosen Evernote notebook. This is done every now and again so when you start watching a new repo it&#8217;ll eventually find its way into your notebook. After you register and configure your account you should see notes being added to your notebook in a few minutes.</p><p>I&#8217;m thinking about open sourcing the app but I would have to reorganize the code to remove my Evernote API keys for example.</p><p>I hope you like the service and start making good use of your watched repos. I might even have <a
title="My GitHub account" href="https://github.com/gpambrozio/" target="_blank">some</a> you might want to watch&#8230;.</p><p>And if you think this is worth a couple of bucks, just buy a copy of <a
title="Snap iPhone camera" href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a>, my iPhone camera app.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iUH0cHjHqxE:bG9ha-9TPbg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iUH0cHjHqxE:bG9ha-9TPbg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=iUH0cHjHqxE:bG9ha-9TPbg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iUH0cHjHqxE:bG9ha-9TPbg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iUH0cHjHqxE:bG9ha-9TPbg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=iUH0cHjHqxE:bG9ha-9TPbg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/iUH0cHjHqxE" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2012/02/github-2-evernote-making-the-watch-button-useful-again/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2012/02/github-2-evernote-making-the-watch-button-useful-again/</feedburner:origLink></item> <item><title>Python’s documentation at your fingertips</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/pCgikuvgOLc/</link> <comments>http://blog.codecropper.com/2012/02/pythons-documentation-at-your-fingertips/#comments</comments> <pubDate>Mon, 20 Feb 2012 17:31:38 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=409</guid> <description><![CDATA[The pain As I mentioned in my last blog post, I started learning Python some time ago and fell in love with it. But, as with any new programming language, I spent a lot of time browsing through the documentation to find out the correct name of the method to find a substring within a [...]]]></description> <content:encoded><![CDATA[<h2>The pain</h2><p><img
class=" wp-image-413 alignright" title="Python" src="http://blog.codecropper.com/wp-content/uploads/2012/02/Python.gif" alt="" width="190" height="64" />As I mentioned in <a
title="Python script to compose iPhone marketing images" href="http://blog.codecropper.com/2012/02/python-script-to-compose-iphone-marketing-images/">my last blog post</a>, I started learning Python some time ago and fell in love with it. But, as with any new programming language, I spent a lot of time browsing through the documentation to find out the correct name of the method to find a substring within a string for example. Is it indexOf, find, rangeOfString, locate??? Off I went to the (very well done, btw) online Python docs to look for the right method in the string module.</p><p><a
href="http://kapeli.com/dash/"><img
class="alignright size-full wp-image-414" title="Dash" src="http://blog.codecropper.com/wp-content/uploads/2012/02/Dash.png" alt="" width="128" height="128" /></a>In the meantime I also fell in love with another tool: <a
title="Dash" href="http://kapeli.com/dash/" target="_blank">Dash</a>. If you&#8217;re an iOS developer and don&#8217;t have Dash you should go get it right now! It&#8217;s one of the most useful tools in my tool belt at the moment. And for the very lowprice of <em>free</em> you just can&#8217;t go wrong. As I said to the author, I&#8217;d gladly pay good money for it.</p><p>Dash&#8217;s first use for me was to browse inside iOS&#8217; documentation. I never liked XCode Organizer&#8217;s documentation browser. The search is incredibly slow, pages take forever to load, there&#8217;s no easy way to jump to a method&#8217;s documentation, you name it&#8230;</p><p>Dash is the complete opposite:</p><ul><li>The search is amazingly fast;</li><li>Once you find the class you&#8217;re looking for it builds a list of all the methods so you can quickly jump there;</li><li>If you click on a method&#8217;s declaration it automatically copies it to your clipboard. It&#8217;s now a breeze to create delegate methods;</li><li>You can search inside a class documentation just as easily;</li></ul><p>Not to mention other very nice features, such as a collector of code snippets and as a text auto expansion tool. Even if you&#8217;re not an iOS or OSX developer Dash can be a great tool just to collect snippets and auto expand text. Enough praise, let&#8217;s go back to the problem.</p><p>Dash can be used to browse through any documentation that has been bundled in <a
title="Documentation set guide" href="https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/Documentation_Sets/000-Introduction/introduction.html" target="_blank">Apple&#8217;s docset format</a>. When I learned this, one of those flashbulbs appeared over my head and I immediately started to scour the web for a version of Python&#8217;s documentation in docset format only to find that such a thing either does not exist or is very well hidden.</p><h2>Using the snake to help the snake</h2><p>So I decided to take matters into my own hands and build this documentation myself. Using Python, of course.</p><p>With the help of Dash&#8217;s author I learned <a
title="How to build docsets" href="http://kapeli.com/docsets/" target="_blank">how to build docsets</a> that were easily searchable inside Dash. After a few hours of coding, reading Apple&#8217;s documentation and building regexes to collect all the information I thought should be in the documentation, I managed to create a docset, configure Dash to use it and, voilá, instant Python documentation search!</p><p><img
class="alignnone size-full wp-image-429" title="Window" src="http://blog.codecropper.com/wp-content/uploads/2012/02/Window.png" alt="" width="580" height="372" /></p><p>I managed to generate documentation for Python <a
href="http://s3.gustavo.eng.br/python.2.7.2.docset.zip">2.7.2</a> and for <a
href="http://s3.gustavo.eng.br/python.3.2.2.docset.zip">3.2.2</a>, the latest versions at this time. Click the links to download and feel free to use them. You&#8217;ll have to unzip the file and put the resulting .docset bundle somewhere. I would recommend putting them in ~/Library/Developer/Shared/Documentation/DocSets as this is the place XCode will look for when searching for docsets. I believe Dash will look in this folder too or at least is the default folder for when you try to add new docsets to it.</p><p>And I&#8217;m proud to say that Dash&#8217;s author will bundle this bundle (the 2.7.2 version) with Dash&#8217;s new version. If you want to have documentation for version 3.2.2 you can download my version and use that instead. Oh, and before I forget, Dash now comes with a lot of docsets created by the author. Currently Android, Java, Perl, Python, PHP, Ruby, jQuery and Cocos2D docsets are included.</p><p>Plus, I&#8217;m adding this script to my <a
href="https://github.com/gpambrozio/PythonScripts" target="_blank">PythonScripts</a> github repository. Feel free to grab it, fork it, use it and improve it. I love getting pull requests with improvements on <a
href="https://github.com/gpambrozio" target="_blank">my repos</a>.</p><p>To use the script you&#8217;ll need to have the <a
href="http://www.crummy.com/software/BeautifulSoup/" target="_blank">BeautifulSoup</a> module installed (sudo pip install beautifulsoup4). I use it to parse the documentation&#8217;s HTML so I can find all interesting methods, functions, classes to grab. I also had to add anchor tags to all html files so Dash could jump to the correct place inside the HTML.</p><p>This is what you have to do to generate a new version of the documentation from the HTML version:</p><ol><li>Download the documentation for the version you want <a
href="http://www.python.org/doc/versions/" target="_blank">here</a>. You should download the zip file for the HTML version of the docs.</li><li>Expand the documentation somewhere.</li><li>Open terminal and cd to the folder where you expanded the docs.</li><li>Run the script from this folder.</li><li>The script will create a python.docset bundle with all the necessary files.</li><li>Move the python.docset bundle to some folder. Again, I recommend ~/Library/Developer/Shared/Documentation/DocSets</li><li>Use it!</li></ol><h2>Conclusion</h2><p>This is my first contribution to the Python community. I hope you like it and that using <a
href="http://kapeli.com/dash/" target="_blank">Dash</a> with this docset makes your lives easier. It has certainly made mine. If you have any comments about this docset leave a comment below.</p><p>The docset does not have the complete documentation (it does not have the tutorials and howto for example) as I personally use it only as a reference. But, as I said before, feel free to change the script to include more stuff and make a pull request so I can add it to my repo.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pCgikuvgOLc:ihyD9jsl0GI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pCgikuvgOLc:ihyD9jsl0GI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=pCgikuvgOLc:ihyD9jsl0GI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pCgikuvgOLc:ihyD9jsl0GI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pCgikuvgOLc:ihyD9jsl0GI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=pCgikuvgOLc:ihyD9jsl0GI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/pCgikuvgOLc" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2012/02/pythons-documentation-at-your-fingertips/feed/</wfw:commentRss> <slash:comments>14</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2012/02/pythons-documentation-at-your-fingertips/</feedburner:origLink></item> <item><title>Python script to compose iPhone marketing images</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/NTjOWrTewtk/</link> <comments>http://blog.codecropper.com/2012/02/python-script-to-compose-iphone-marketing-images/#comments</comments> <pubDate>Tue, 14 Feb 2012 18:04:30 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[python]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=396</guid> <description><![CDATA[An excuse to use Python I consider myself a polyglot programmer and try to learn a new language every now and again. My latest is Python and I can say that I love it! It&#8217;s easy to learn, has a HUGE library, very good support for lists and dictionaries and is flexible enough to be an [...]]]></description> <content:encoded><![CDATA[<h2>An excuse to use Python</h2><p>I consider myself a polyglot programmer and try to learn a new language every now and again. My latest is Python and I can say that I love it! It&#8217;s easy to learn, has a HUGE library, very good support for lists and dictionaries and is flexible enough to be an ideal choice from small scripts to large frameworks.</p><p>I&#8217;ve been doing a lot of Python scripts for all sorts of small jobs and my latest script might be of interest to some of the readers of this blog.</p><p>I was creating a press kit for <a
title="Kush" href="http://www.iwantkush.com" target="_blank">my latest app</a> and I wanted to get some screenshots of the app and compose them inside an iPhone image.</p><p>So, I wanted to get the image on the left and create the one on the right:</p><p><img
class="alignnone size-medium wp-image-399" title="ss_Push-3" src="http://blog.codecropper.com/wp-content/uploads/2012/02/ss_Push-3-201x300.png" alt="" width="201" height="300" />    <img
class="alignnone size-medium wp-image-398" title="after" src="http://blog.codecropper.com/wp-content/uploads/2012/02/ss_Push-Screen-154x300.png" alt="" width="154" height="300" /></p><p>Of course I could use PhotoShop or Pixelmator and do this all manually but I had 8 of these and a craving for Python. So I fired up <a
title="CodeRunner" href="http://itunes.apple.com/us/app/coderunner/id433335799?mt=12" target="_blank">CodeRunner</a> and started writing a Python script. Turns out that, with the use of the incredible <a
title="Python Imaging Library" href="http://www.pythonware.com/products/pil/" target="_blank">Python Imaging Library</a> it was a breeze.</p><p>So I decided to open source this so everyone could use it: <a
href="https://github.com/gpambrozio/PythonScripts" target="_blank">https://github.com/gpambrozio/PythonScripts</a>. Feel free to grab it, fork it, improve it and make a pull request.</p><h2>Pre-requisites</h2><p>This script uses PIL. The easiest way to install PIL is using pip:</p><blockquote><p>sudo pip install PIL</p></blockquote><h2>Using the script</h2><p>To use the script place your screenshot files in the same folder as the script and the EmptyiPhone.png file and run it. The script will create new files with ss_ prefixes for all .png files found in the folder.</p><h2>Changing the iPhone image</h2><p>To use a different image or to adapt the script for an iPad screen for example, change the EmptyiPhone.png image or the name of the image in the script and change the coordinates used to paste the original screen shots. I plan to automate this step by analyzing the image and finding the transparent rectangle in the middle but so far this is a manual step.</p><p>Hope you like it.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=NTjOWrTewtk:fEq231ZHbT0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=NTjOWrTewtk:fEq231ZHbT0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=NTjOWrTewtk:fEq231ZHbT0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=NTjOWrTewtk:fEq231ZHbT0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=NTjOWrTewtk:fEq231ZHbT0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=NTjOWrTewtk:fEq231ZHbT0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/NTjOWrTewtk" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2012/02/python-script-to-compose-iphone-marketing-images/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2012/02/python-script-to-compose-iphone-marketing-images/</feedburner:origLink></item> <item><title>Making an App Out of Love</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/dUi9hs79DeM/</link> <comments>http://blog.codecropper.com/2012/02/making-an-app-out-of-love/#comments</comments> <pubDate>Mon, 13 Feb 2012 14:33:52 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Testimonials]]></category> <category><![CDATA[ios]]></category> <category><![CDATA[kush]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=357</guid> <description><![CDATA[The developer&#8217;s mind As a developer I&#8217;m always thinking about ways to use software to solve a problem. So, when something happens in my personal life that prompts me to think &#8220;damn, there should be a (better) way to do this&#8221;, I immediately start thinking about ways to solve this with software. And this is [...]]]></description> <content:encoded><![CDATA[<p><img
class="alignright size-thumbnail wp-image-378" title="A developer's brain" src="http://blog.codecropper.com/wp-content/uploads/2012/02/761AA6C6-C6E8-176D-448469AAB2E93BEF_1-150x150.jpg" alt="" width="150" height="150" /></p><h2>The developer&#8217;s mind</h2><p>As a developer I&#8217;m always thinking about ways to use software to solve a problem. So, when something happens in my personal life that prompts me to think &#8220;damn, there should be a (better) way to do this&#8221;, I immediately start thinking about ways to solve this with software.</p><p>And this is exactly how <a
title="Kush" href="http://www.iwantkush.com/" target="_blank">Kush</a> got started.</p><h2>The problem</h2><p>One day I went to the gym with my wife. While she was in the weight room I was running in the treadmill. The treadmills are on a balcony overlooking the weight room downstairs so I could see my wife from the treadmill depending on where she was.</p><p><img
class="alignleft  wp-image-381" title="Brain_Exercise" src="http://blog.codecropper.com/wp-content/uploads/2012/02/Brain_Exercise-249x300.jpg" alt="" width="149" height="180" />We both work out with our iPhones playing music or podcasts and at one point I wanted to send her a message to let her know I could see her and I was thinking about her, just to make her laugh. But have you tried running in a treadmill and texting at the same time? It&#8217;s way harder than while driving (just kidding, I don&#8217;t text and drive). And so the thought inevitably came to my head: &#8220;There should be a better way to do this&#8221;. And <a
title="Kush" href="http://www.iwantkush.com/" target="_blank">Kush</a> was born.</p><p>I laid out the idea in my head and started thinking about ways to make an iPhone app that was easy to use (required very little touches) but, at the same time, had the power to send meaningful messages to your significant other. And that was very nice to look at!</p><h2>The solution</h2><p>A couple of days later I had a rough prototype. I installed it on our iPhones and we started using it in our daily lives. The app had a different sentence maker with fewer sentences but already had most kissing sounds it has now.</p><p>As we started using Kush it was evident that this was an app worth making not just for our own use but something others could benefit from. Because of the unique kissing sounds, you immediately know when a message arrives it’s from your partner. Knowing that someone was thinking of you is a great feeling. Even though the messages are all pre-made there&#8217;s so many to choose from you can see the person chose that message just for you.</p><p><img
class="alignleft  wp-image-387" title="texting" src="http://blog.codecropper.com/wp-content/uploads/2012/02/dreamstime_xs_188973831-300x216.png" alt="" width="189" height="136" />Kush has made this type of short and sweet communication more frequent among us. Before Kush I remember thinking many times a day about sending her a quick &#8220;Hello&#8221; but wouldn&#8217;t, either because I was too busy to type a message or because just a &#8220;Hello&#8221; would be stupid and I couldn&#8217;t come up with something that was much different to an &#8220;I love you&#8221;.</p><p>I contacted a designer who is a friend of mine and we started working on the look of the app. As I was thinking about ways to promote the app I just remembered that Valentine&#8217;s day was just a couple of weeks away! The thought was not obvious to me before because in Brazil Valentine&#8217;s day is in June, not February (we already have Carnival in February&#8230;)</p><h2>The deadline</h2><p>We decided to try to release this on Valentine&#8217;s day. Working on the code like crazy, my wife was writing romantic phrases for the sentence composer and my designer started to draw and produce all graphical elements. We submitted the app for Apple to approve Thursday morning and asked for an expedited review saying it was an app for couples and that we would love to have it for sale by Valentine&#8217;s day. They granted me an exception (thanks Apple) and the app is <a
title="iTunes store" href="http://itunes.iwantkush.com/" target="_blank">now available in the App Store</a>! We also managed to make a <a
title="Kush YouTube video" href="http://video.iwantkush.com" target="_blank">very nice video explaining Kush</a>. Thanks to my designer for the video and his girlfriend for the voice over.</p><p><a
href="http://www.iwantkush.com/"><img
class="wp-image-389 alignleft" title="Kush" src="http://blog.codecropper.com/wp-content/uploads/2012/02/iTunesArtwork-150x150.png" alt="" width="108" height="108" /></a>We&#8217;re really anxious to see what&#8217;s going to happen now. I hope that the app gets used by many many couples; and that they also benefit from <a
href="http://www.iwantkush.com/" target="_blank">Kush</a> the way my wife and I do. One thing I can vouch for personally is: your wife may leave home angry about something, but after a &#8220;<a
title="Kush" href="http://www.iwantkush.com/" target="_blank">Kush</a>&#8221; she will come home happy to be your wife ;]</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=dUi9hs79DeM:hB9I-65xzaQ:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=dUi9hs79DeM:hB9I-65xzaQ:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=dUi9hs79DeM:hB9I-65xzaQ:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=dUi9hs79DeM:hB9I-65xzaQ:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=dUi9hs79DeM:hB9I-65xzaQ:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=dUi9hs79DeM:hB9I-65xzaQ:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/dUi9hs79DeM" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2012/02/making-an-app-out-of-love/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2012/02/making-an-app-out-of-love/</feedburner:origLink></item> <item><title>Replicating TweetBot’s Alerts and Action Sheets</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/fgUCMAUmRYw/</link> <comments>http://blog.codecropper.com/2012/01/replicating-tweetbot-alerts-and-action-sheets/#comments</comments> <pubDate>Fri, 20 Jan 2012 23:51:47 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[ios]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=323</guid> <description><![CDATA[How it all started: A love and hate story. Since the first time I had to use an UIActionSheet or UIAlertView in an app I disliked the way it was implemented. It was a pain if you had two kinds of alerts in the same class for example as everything is done by invoking a [...]]]></description> <content:encoded><![CDATA[<h1>How it all started: A love and hate story.</h1><p>Since the first time I had to use an UIActionSheet or UIAlertView in an app I disliked the way it was implemented. It was a pain if you had two kinds of alerts in the same class for example as everything is done by invoking a delegate method. I also disliked the fact that the code that should be executed in the event of a button was almost always in a separate place in your source code. The code needs a lot of constants, switches and you need to tag your UIAlertView&#8230;. I hated it!</p><p>But on the other hand they are very useful for asking information in a modal way so I kept using them when it was appropriate.</p><p>And then I found <a
title="PSFoundation" href="https://github.com/steipete/PSFoundation/tree/master/Utils" target="_blank">PSFoundation</a> a library of very nice iOS utilities by <a
href="https://github.com/steipete" target="_blank">Peter Steinberger</a>. It has a LOT of useful utility classes but two stood out for me as a relief for my hatred: <a
href="https://github.com/steipete/PSFoundation/blob/master/Utils/PSActionSheet.m" target="_blank">PSActionSheet</a> and <a
href="https://github.com/steipete/PSFoundation/blob/master/Utils/PSAlertView.m" target="_blank">PSAlertView</a>.</p><p>To see an explanation on how they work, take a look at the blog post that originated PSActionSheet and inspired PSAlertView: <a
href="http://landonf.bikemonkey.org/code/iphone/Using_Blocks_1.20090704.html" target="_blank">&#8220;Using Blocks&#8221; by Landon Fuller</a> who apparently hates UIActionSheets as much as I do.</p><p>Since I found these classes I&#8217;ve incorporated them into every one of my projects. And when I took over as lead developer for <a
title="Arrived" href="http://www.getarrived.com/">Arrived&#8217;s</a> <a
title="Arrived iPhone app" href="http://itunes.apple.com/app/id439811947?mt=8">iPhone app</a> I took a few hours right at the beginning of the project to convert every UIActionSheet and every UIAlertView into a BlockActionSheet and BlockAlertView (I renamed the classes to make the name more memorable and descriptive).</p><h1>A new kind of hate</h1><p><a
title="Arrived" href="http://www.getarrived.com/">Arrived</a> has a very distinctive look. I love the design of the app, with lots of textures, the red carpet over the pictures on the stream, the custom buttons, the title, even the tab bar is customized to look unique. So, in the middle of all this very nice color scheme whenever I had to use an Alert View or an Action Sheet I was punched in the face by a freaking blue Alert! How I hated those Alert Views ruining the look of the app.</p><p>And then I got <a
href="http://tapbots.com/software/tweetbot/">TweetBot</a>. What a nice app, what a unique interface and&#8230;. what the hell? They customized their Alert Views! Super cool. Right then I thought: I gotta have this&#8230;.</p><h1>Hate is a very effective motivator</h1><p>We then decided to terminate every instance of default Alert View and Action Sheet. Since I already had every call to those wrapped with my own Block* classes, it was just a matter of changing these classes and everything should work as before, but with a much better look.</p><p>And so we did it and we decided to open source it. And let me tell you they look great!</p><p><img
class="alignnone size-medium wp-image-341" title="iOS Simulator Screen shot Jan 20, 2012 4.28.18 PM" src="http://blog.codecropper.com/wp-content/uploads/2012/01/iOS-Simulator-Screen-shot-Jan-20-2012-4.28.18-PM-200x300.png" alt="" width="200" height="300" />  <img
class="alignnone size-medium wp-image-342" title="iOS Simulator Screen shot Jan 20, 2012 4.28.23 PM" src="http://blog.codecropper.com/wp-content/uploads/2012/01/iOS-Simulator-Screen-shot-Jan-20-2012-4.28.23-PM-200x300.png" alt="" width="200" height="300" /></p><p>But before I send you over to our repository to download this baby, let me tell you how they work and what are the current limitations.</p><h1>Using the library</h1><p>If you&#8217;re familiar with the above mentioned PLActionSheet and PLAlertView you will have no problems adjusting to these classes as I didn&#8217;t change their methods at all. I added some methods to make the class even better but everything that used the old classes worked with no modifications.</p><p>You&#8217;ll need to import 6 files into your project: 4 for both classes (BlockActionSheet.(h|m) and BlockAlertView.(h|m)) and 2 for another view that serves as the background for the alerts and action sheets, obscuring the window to make it look very modal and make the user focus more on the dialog (BlockBackground.(h|m)). You&#8217;ll never have to use this third class directly though as everything is handled by the two main classes. You&#8217;ll also need the image assets that we se to draw the view, such as the buttons and background.</p><p>To create an alert view you use:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;">BlockAlertView <span style="color: #002200;">*</span>alert <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>BlockAlertView alertWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert Title&quot;</span> message<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is a very long message, designed just to show you how smart this class is&quot;</span><span style="color: #002200;">&#93;</span>;</pre></div></div><p>Then for every button you want you call:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>alert addButtonWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Do something cool&quot;</span> block<span style="color: #002200;">:^</span><span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Do something cool when this button is pressed</span>
<span style="color: #002200;">&#125;</span><span style="color: #002200;">&#93;</span>;</pre></div></div><p>You can also add a &#8220;Cancel&#8221; button and a &#8220;Destructive&#8221; button (this is one of the improvements that UIAlertView can&#8217;t even do):</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>alert setCancelButtonWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Please, don't do this&quot;</span> block<span style="color: #002200;">:^</span><span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Do something or nothing.... This block can even be nil!</span>
<span style="color: #002200;">&#125;</span><span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #002200;">&#91;</span>alert setDestructiveButtonWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Kill, Kill&quot;</span> block<span style="color: #002200;">:^</span><span style="color: #002200;">&#123;</span>
    <span style="color: #11740a; font-style: italic;">// Do something nasty when this button is pressed</span>
<span style="color: #002200;">&#125;</span><span style="color: #002200;">&#93;</span>;</pre></div></div><p>When all your buttons are in place, just show:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>alert show<span style="color: #002200;">&#93;</span>;</pre></div></div><p>That&#8217;s it! Showing an Action Sheet works almost exactly the same. I won&#8217;t bore you here with more code but the repository has a demo project with everything you&#8217;ll need.</p><p>You can even have more than one cancel and destructive button, despite the fact that the methods are prefixed <em>set</em> and not <em>add</em>, but this is because I wanted to keep the same names I used in the original libraries where you could only have one cancel button. Feel free to rename those if you don&#8217;t have any legacy code as I had.</p><p>Another cool thing we did was add an animation when showing and hiding the new views as Tweetbot does. This is another area where you can go nuts and add all kinds of animation.</p><p>The look of the alerts and action sheets is made of a few assets for the background and the buttons so if you want to change the color scheme all you need is a little time to change ours. Check out the included assets and just change them if they don&#8217;t work for you.</p><p>The only limitation these classes have so far is with device rotation. As <a
title="Arrived" href="http://www.getarrived.com">Arrived</a> only works in portrait this is not a problem I needed to solve. And it&#8217;s not that trivial because you&#8217;d have to reposition the buttons and text because the window now has a different size and the alert might be too tall to hold a long message in landscape. And you might need to add a scroll for some action sheets too. But feel free to fork and fix this!</p><h1>Gimme that!</h1><p>You can get the everything you need from out <a
href="https://github.com/gpambrozio/BlockAlertsAnd-ActionSheets">GitHub repository</a>. There&#8217;s a demo project with lots of buttons to trigger alerts and action sheets until you get sick of them.</p><p>Another thing that&#8217;s included in the project but that you might need to roll your own are the graphical assets for the buttons and backgrounds. You can use ours but they might not fit the look of your app.</p><p>Now <a
href="https://github.com/gpambrozio/BlockAlertsAnd-ActionSheets">go get the project</a> and have fun with it. Feel free to fork and add pull requests so we can incorporate your changes for everyone.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=fgUCMAUmRYw:m3-Vp2JeYHE:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=fgUCMAUmRYw:m3-Vp2JeYHE:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=fgUCMAUmRYw:m3-Vp2JeYHE:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=fgUCMAUmRYw:m3-Vp2JeYHE:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=fgUCMAUmRYw:m3-Vp2JeYHE:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=fgUCMAUmRYw:m3-Vp2JeYHE:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/fgUCMAUmRYw" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2012/01/replicating-tweetbot-alerts-and-action-sheets/feed/</wfw:commentRss> <slash:comments>47</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2012/01/replicating-tweetbot-alerts-and-action-sheets/</feedburner:origLink></item> <item><title>The PhotoAppLink library story</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/iHPtSkcwTgQ/</link> <comments>http://blog.codecropper.com/2011/09/the-photoapplink-library-story/#comments</comments> <pubDate>Thu, 01 Sep 2011 17:46:36 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Testimonials]]></category> <category><![CDATA[ios]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=313</guid> <description><![CDATA[Launching Today is the day os the official launch of the PhotoAppLink library. The library is a joint effort of me and Hendrik Kueck from PocketPixels, maker of the ever top selling ColorSplash. We have a website if you want to know the latest about this. This post is to tell the story behind this. [...]]]></description> <content:encoded><![CDATA[<h2></h2><h2>Launching</h2><p>Today is the day os the official launch of the PhotoAppLink library. The library is a joint effort of me and Hendrik Kueck from <a
href="http://www.pocketpixels.com/" target="_blank">PocketPixels</a>, maker of the ever top selling <a
href="http://www.pocketpixels.com/ColorSplash.html" target="_blank">ColorSplash</a>. We have a <a
href="http://www.photoapplink.com/" target="_blank">website</a> if you want to know the latest about this. This post is to tell the story behind this.</p><h2>The problem</h2><p>Since the first version of my first iPhone camera app, <a
title="Snap iPhone camera app" href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a>, I wanted my users to be able to share their annotated images with as many services as possible. I did the obvious: Twitter, Facebook, Tumblr and I still want to add more to this list.</p><p>But one thing was still not possible: how could I share the images with another app? How can I send an image from Snap to Instagram so that users can apply some filters and share? How could I send it to AppX so that users could add filters, frames and a lot more that AppX might offer?</p><p>And also the other way around. What if a user takes a picture with AppX and wants to add some text on top of it? AppX might not offer this, but <a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> does. Wouldn&#8217;t it be nice if AppX could open <a
title="Snap" href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> with an image, <a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> could add notes to it and then send the result back to AppX? There is just no way of doing this. Or at least not until right now.</p><h2>The proposal</h2><p>What I wanted (you&#8217;ll understand the past tense in a moment) to propose was really quite simple, but quite ingenious (or so I thought).</p><p>The iOS API allows us to <a
href="http://developer.apple.com/library/ios/documentation/iphone/conceptual/iphoneosprogrammingguide/StandardBehaviors/StandardBehaviors.html#//apple_ref/doc/uid/TP40007072-CH4-SW50" target="_blank">Implement Custom URL Schemes</a>. I wanted every camera or image processing app to implement a custom URL scheme so that we can all exchange images with each other.</p><p>So I hashed up a way to Base64 encode an image and send it to another app using these custom URL schemes. It worked well in some tests so I wrote a library and started sharing it with some top devs in the photography section of the app store.</p><p>Some people didn&#8217;t even respond, but Hendrik Kueck from <a
href="http://www.pocketpixels.com/" target="_blank">PocketPixels</a>, maker of the ever top selling and very fun <a
href="http://www.pocketpixels.com/ColorSplash.html" target="_blank">ColorSplash</a> responded telling me he had a similar idea over a year ago (and I thought my idea was so original&#8230;) but he didn&#8217;t get a lot of people on board so he kinda forgot about it.</p><p>He sent me his code and I think my email made him regain his enthusiasm so we decided to iron out a few missing things in the library that would make adoption much easier and try to get more people on board.</p><p>So when I checked his library I saw that his idea, even tough it was using custom URL schemes, was to use a custom pasteboard to pass data around from one app to the other. WAY better than Base64 encoding everything. What a revelation that was.</p><p>So I threw away most of my code and ported my app to use his code in about an hour. It&#8217;s called PhotoAppLink (mine would be called iOSImageShare, even his name is better&#8230; damn&#8230;.) and he even registered a domain for it.</p><h2>How does it work?</h2><p>There&#8217;s a <a
title="PhotoAppLink Library tutorial" href="https://github.com/pocketpixels/PhotoAppLink#readme">Readme file</a> with code and a step by step tutorial on how to implement this into your app but first let me explain how it works. It&#8217;s really very simple.</p><p>When you want to send an image to another app, we just create a custom pasteboard with a common name and paste the image NSData (jpeg encoded to a very high quality) to this pasteboard. We then open a custom url registered by another app.</p><p>The system then opens this other app that knows is being called to open a custom url. The app checks the shared pasteboard, gets the image from there and then&#8230; well, that&#8217;s up to the app. In the case of Snap, I&#8217;ll open the annotation screen so that the user can add notes. In ColoSplash it will open the app and prepare it for processing just as if you were getting an image from your Camera roll.</p><p>So, all very simple, right? Well, if you&#8217;re paying attention there&#8217;s one thing that&#8217;s missing here: how do I know what URL to open?</p><h2>Who wants to play?</h2><p><img
style="float: right;" title="share01.png" src="http://blog.codecropper.com/wp-content/uploads/2011/05/share01.png" alt="Share01" width="240" height="346" border="0" /></p><p>So, you decided to implement PhotoAppLink on your &#8220;soon to be the best&#8221; camera app but you feel lonely. You don&#8217;t really know to what other apps you can send your images to. Well, not to worry my friendly app, we got a solution for you.</p><p>We will host a plist on our photoapplink.com website called photoapplink.plist. This file will contain information about all compatible apps. If you implement PhotoAppLink in your app you just have to send us an email about it with all your info and we&#8217;ll add your app to this file.</p><p>Our library then simply downloads this file and uses UIApplication&#8217;s <a
href="http://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html#//apple_ref/occ/instm/UIApplication/canOpenURL:" target="_blank">canOpenURL:</a> to check if the app is installed. The library will also download all the compatible apps&#8217; icons (and cache it) automatically on the background.</p><p>When your user wants to send a picture to another app you can use an UIViewController from the library that handles everything, from showing compatible apps to sending your image.</p><p>But if you don&#8217;t like the interface we built or if it doesn&#8217;t fit your app, no problem. The library can provide all the information about compatible apps so that you can build your own interface. Or just change the interface we provide to fit your app.</p><p><span
style="font-size: 20px; font-weight: bold;">That&#8217;s it?</span></p><p><img
style="float: right;" title="moreapps.png" src="http://blog.codecropper.com/wp-content/uploads/2011/05/moreapps.png" alt="Moreapps" width="240" height="346" border="0" /></p><p>Well, not quite. If you&#8217;re still not convinced that implementing this in your app was a good idea I think this will make you change your mind.</p><p>When we present a list of compatible apps to the user we can check what apps the user has installed but we also now have a bunch of apps that the user does not know about. So, in our UIViewController we have a button for &#8220;More apps&#8221;. This button will present a list of all the compatible apps the user still doesn&#8217;t have in a nice table with a nice button to get the app.</p><p>This button will open the AppStore app so the user can get this app immediately! AND it uses a link with your Linkshare site ID so you even get a commission on the sale.</p><p>So, your app can get more revenue selling other apps AND your app can now be discovered by users of other PhoneAppLink compatible apps. How cool is this!!!!!</p><p>And, again, if you don&#8217;t like our interface, just change it or roll your own using the information gathered by the library.</p><h2>Let&#8217;s play?</h2><p>Convinced? Great. There&#8217;s a very quick <a
href="https://github.com/pocketpixels/PhotoAppLink#readme">tutorial</a> on how to implement PhotoAppLink in your app. It will take you about an hour if you use the controls we provide there and there&#8217;s a test app you can use to test interaction with your app. The whole process should not take more than 4 hours, with testing!</p><p><a
href="https://github.com/pocketpixels/PhotoAppLink#readme">Check it</a> out and let&#8217;s start playing together!</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iHPtSkcwTgQ:wmrC8XbeASA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iHPtSkcwTgQ:wmrC8XbeASA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=iHPtSkcwTgQ:wmrC8XbeASA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iHPtSkcwTgQ:wmrC8XbeASA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=iHPtSkcwTgQ:wmrC8XbeASA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=iHPtSkcwTgQ:wmrC8XbeASA:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/iHPtSkcwTgQ" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2011/09/the-photoapplink-library-story/feed/</wfw:commentRss> <slash:comments>7</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2011/09/the-photoapplink-library-story/</feedburner:origLink></item> <item><title>Two small iOS tricks</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/mMSTuKf1_T4/</link> <comments>http://blog.codecropper.com/2011/06/two-small-ios-tricks/#comments</comments> <pubDate>Sat, 25 Jun 2011 16:39:58 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[ios]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=296</guid> <description><![CDATA[Sorry Well, I got back from WWDC and there was just too much to do, so I&#8217;ve been neglecting my blog a little bit. But since I already missed one post on AltDevBlogADay and today I was about to miss another (3 strikes and I&#8217;m out???) I decided to get something quick but maybe useful [...]]]></description> <content:encoded><![CDATA[<h2>Sorry</h2><p>Well, I got back from WWDC and there was just too much to do, so I&#8217;ve been neglecting my blog a little bit. But since I already missed one post on <a
href="http://altdevblogaday.org/" target="_blank">AltDevBlogADay</a> and today I was about to miss another (3 strikes and I&#8217;m out???) I decided to get something quick but maybe useful for all you iOS devs out there.</p><p>I&#8217;ll share two tricks I recently had to use for <a
title="Snap" href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a>. One I learned during one of the labs at WWDC and it&#8217;s an old but very hidden trick that&#8217;s not covered by NDA so I can share. The other is something that I hacked on my own but got somewhat validated by an Apple engineer I showed to, so not I feel more confident in showing this in public&#8230;</p><h2>First trick</h2><p><a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> is a camera app and my users were asking me to implement zooming. I studied the API a bit and there was no way to tell the camera to zoom. What I came up with (and Apple&#8217;s engineers that work with this API have said it&#8217;s the right thing to do) was to change the frame of the camera preview layer so that it would &#8220;bleed&#8221; out of the view and then give the illusion of zoom. After taking the picture I have to crop but that&#8217;s another story.</p><p>My problem was that when I changed the frame of the layer, even though I was not applying any animation, the system would animate my change and the interface felt a little weird. It felt like the zoom was &#8220;bouncing&#8221;. It&#8217;s hard to explain but the result was not good and I could not figure out how to remove this animation.</p><p>During one the the labs I asked an Apple engineer about this and as he was about to go looking for the answer another attendee from across the table who overheard me said he knew how to do this and very quickly guided us to the documentation where this little trick is hidden.</p><p>So, inside the &#8220;<a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Transactions.html#//apple_ref/doc/uid/TP40006096-SW1" target="_blank">Transactions</a>&#8221; section of &#8220;<a
href="http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html" target="_blank">Introduction to Core Animation Programming Guide</a>&#8221; there&#8217;s a header that says &#8220;<a
href="http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Transactions.html#//apple_ref/doc/uid/TP40006096-SW6" target="_blank">Temporarily Disabling Layer Actions</a>&#8220;:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>CATransaction begin<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>CATransaction setValue<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>kCFBooleanTrue
                 forKey<span style="color: #002200;">:</span>kCATransactionDisableActions<span style="color: #002200;">&#93;</span>;
<span style="color: #11740a; font-style: italic;">// Do what you want with your layer</span>
<span style="color: #002200;">&#91;</span>CATransaction commit<span style="color: #002200;">&#93;</span>;</pre></div></div><p>So there you have it. Very obscure but it works. You can also change the duration if this is what you want:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>CATransaction begin<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>CATransaction setValue<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span>10.0f<span style="color: #002200;">&#93;</span>
                 forKey<span style="color: #002200;">:</span>kCATransactionAnimationDuration<span style="color: #002200;">&#93;</span>;
<span style="color: #11740a; font-style: italic;">// Do whatever you want with your layer</span>
<span style="color: #002200;">&#91;</span>CATransaction commit<span style="color: #002200;">&#93;</span>;</pre></div></div><h2>Second trick</h2><p>Another problem I faced with Snap was that, even though the saving of the image takes place mostly on the background using block and GCD (more about this on another post&#8230;), in order to compose the image I still had to make the user wait. I can do it on the background but that would involve copying a lot of memory and I didn&#8217;t want to do this on the iPhone. And it&#8217;s fast enough not to be a problem but I didn&#8217;t like that the interface froze when I was composing the image with the notes and the user was just staring at an unresponsive device.</p><p>So, I decided to use <a
href="https://github.com/jdg/MBProgressHUD" target="_blank">MBProgressHUD</a> to at least show something to the user. My problem was that I had a lot of calls to the method that generates the image and the caller expects to get the UIImage back. As the calls are made on the main run loop and the method takes too long the interface froze and the HUD would not show.</p><p>Yes, I could have refactored everything to use GCD and callback blocks but I had to release an update and didn&#8217;t have much time. So, I decided to pump the main queue myself:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;">    <span style="color: #11740a; font-style: italic;">// Will return my image here</span>
    __block UIImage <span style="color: #002200;">*</span>img <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
    <span style="color: #11740a; font-style: italic;">// To indicate the work has finished</span>
    __block <span style="color: #a61390;">BOOL</span> finished <span style="color: #002200;">=</span> <span style="color: #a61390;">NO</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// This will execute on another thread. High priority so it's fast!</span>
    dispatch_async<span style="color: #002200;">&#40;</span>dispatch_get_global_queue<span style="color: #002200;">&#40;</span>DISPATCH_QUEUE_PRIORITY_HIGH, <span style="color: #2400d9;">0</span><span style="color: #002200;">&#41;</span>, <span style="color: #002200;">^</span><span style="color: #002200;">&#123;</span>
        <span style="color: #11740a; font-style: italic;">// Call my very long method and indicated we're finished</span>
        img <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self annotatedImage<span style="color: #002200;">&#93;</span> retain<span style="color: #002200;">&#93;</span>;
        finished <span style="color: #002200;">=</span> <span style="color: #a61390;">YES</span>;
    <span style="color: #002200;">&#125;</span><span style="color: #002200;">&#41;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// This will probably execute even before my image method above</span>
    MBProgressHUD <span style="color: #002200;">*</span>hud <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>MBProgressHUD showHUDAddedTo<span style="color: #002200;">:</span>view animated<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
    hud.labelText <span style="color: #002200;">=</span> label;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Get the main run loop</span>
    <span style="color: #400080;">NSRunLoop</span> <span style="color: #002200;">*</span>runLoop <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSRunLoop</span> currentRunLoop<span style="color: #002200;">&#93;</span>;
    <span style="color: #11740a; font-style: italic;">// Run until finished</span>
    <span style="color: #a61390;">while</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span>finished<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
        <span style="color: #002200;">&#91;</span>runLoop runUntilDate<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSDate</span> dateWithTimeIntervalSinceNow<span style="color: #002200;">:</span>0.01f<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
    <span style="color: #11740a; font-style: italic;">// Hide the HUD</span>
    <span style="color: #002200;">&#91;</span>MBProgressHUD hideHUDForView<span style="color: #002200;">:</span>view animated<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
&nbsp;
    <span style="color: #11740a; font-style: italic;">// Return my image that is now composed.</span>
    <span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>img autorelease<span style="color: #002200;">&#93;</span>;</pre></div></div><p>Even though it&#8217;s kind of an ugly hack it can be used in situations where you&#8217;ll really have to make the user wait and a synchronous call on the main thread is what you already have or what it&#8217;s faster for you to implement.</p><p>I don&#8217;t recommend this for every situation. There are situations where this might lead to a deadlock in your app, so test this a lot if you decide to use it. It worked for me. And, as I said, I showed this to an Apple engineer during one of the labs and he said it was a good solution to the problem.</p><p>I have a <a
href="https://github.com/gpambrozio/MBProgressHUD" target="_blank">fork of MBProgressHUD</a> and have used these principles to build a category for MBProgressHUD that does this AND can even be cancelled by the user. This version is even hackier so I won&#8217;t go into it right now for lack of time but if someone wants to read about it just ask in the comments and I&#8217;ll do it.</p><h2>An afterthought about WWDC</h2><p>One of the things I learned during last year&#8217;s WWDC is that, even though the sessions are great, the labs are even better. And as the sessions are not opened for questions and they&#8217;re usually out on iTunes for you to watch less than 2 weeks after the event this year my main priority were the labs. I went to every lab that I could think of and even went to some twice.</p><p>So, my advice to any WWDC attendees: Forget the sessions and go to the labs! The sessions you can watch later at home but you only have access to these great engineers that are building the stuff we use for these 5 days, so make the most of this. Even if you have a stupid question, don&#8217;t be shy and go to a lab and ask the question. These guys are great and are always willing to help. This is consulting from Apple that is well worth the US$1600 bucks. I dare to even say that 1600 is cheap! (don&#8217;t tell Apple though&#8230;)</p><p>I even bumped into a guy that helped me  last year that remembered me, my problem and tried to help me again this year even though my problem now was not at all related to his expertise. Nice guy. Thanks again Sam. See you next year.</p><p><a
href="http://www.codecrop.com/snap/index.html"><img
class="size-full wp-image-64 alignleft" src="http://blog.codecropper.com/wp-content/uploads/2011/04/SnapIcon75.png" alt="Snap iPhone camera app" width="75" height="75" /></a></p><p>Oh, and have I mentioned that you should get <strong><a
href="http://www.codecrop.com/snap/index.html">Snap</a></strong> for your iPhone? Check it out. You don&#8217;t know how useful and fun your iPhone camera can be until you have <strong><a
href="http://www.codecrop.com/snap/index.html">Snap</a></strong>!</p><p>Well, that&#8217;s it. Sorry for the quick post. I&#8217;ll come up with something better next time. And if you have any comments on this post please leave them here and I&#8217;ll try to respond and correct whatever you guys come up with.</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=mMSTuKf1_T4:5IQar0BFA60:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=mMSTuKf1_T4:5IQar0BFA60:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=mMSTuKf1_T4:5IQar0BFA60:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=mMSTuKf1_T4:5IQar0BFA60:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=mMSTuKf1_T4:5IQar0BFA60:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=mMSTuKf1_T4:5IQar0BFA60:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/mMSTuKf1_T4" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2011/06/two-small-ios-tricks/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2011/06/two-small-ios-tricks/</feedburner:origLink></item> <item><title>Getting metadata from images on iOS</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/pE9FGrYXw8I/</link> <comments>http://blog.codecropper.com/2011/05/getting-metadata-from-images-on-ios/#comments</comments> <pubDate>Thu, 26 May 2011 17:00:38 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[ios]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=167</guid> <description><![CDATA[Recap My latest post was on how to write image metadata on iOS. I got a lot of good feedback from it so I think people are interested in this kind of stuff. I got 33 people watching my repo on GitHub. Cool, I got code stalkers! One thing was missing from the post though: [...]]]></description> <content:encoded><![CDATA[<h2>Recap</h2><p><img
class="alignright size-thumbnail wp-image-132" title="TIFF metadata" src="http://blog.codecropper.com/wp-content/uploads/2011/05/Screen-shot-2011-05-10-at-3.18.11-PM-150x150.png" alt="" width="150" height="150" /></p><p>My latest post was on <a
title="Adding metadata to iOS images the easy way" href="http://blog.codecropper.com/2011/05/adding-metadata-to-ios-images-the-easy-way/" target="_blank">how to write image metadata on iOS</a>. I got a lot of good feedback from it so I think people are interested in this kind of stuff. I got 33 people watching <a
href="https://github.com/gpambrozio/GusUtils" target="_blank">my repo on GitHub</a>. Cool, I got code stalkers!</p><p>One thing was missing from the post though: how to get metadata from existing images. In this post I&#8217;ll show you a few methods to do this as well as how to use my <a
href="https://github.com/gpambrozio/GusUtils/blob/master/GusUtils/NSMutableDictionary+ImageMetadata.m" target="_blank">NSMutableDictionary</a> category to do this.</p><h2>Getting images using UIImagePickerController</h2><p>If you&#8217;re getting images from an UIImagePickerController you have to implement this delegate method:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>imagePickerController<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIImagePickerController <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>picker didFinishPickingMediaWithInfo<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>info</pre></div></div><p>In iOS 4.1 or greater your info dictionary has a key called UIImagePickerControllerReferenceURL (for images from the library) or UIImagePickerControllerMediaMetadata (for images taken from the camera). If your info has the UIImagePickerControllerMediaMetadata key, then you just have to initialize your NSMutableDictionary with the NSDictionary you get from the info dictionary:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> initWithDictionary<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span>info objectForKey<span style="color: #002200;">:</span>UIImagePickerControllerMediaMetadata<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#93;</span>;</pre></div></div><p>But if you took an image from the library things are a little more complicated and not obvious at first sight. All you get in a NSURL object. How to get the metadata from this?? Using the AssetsLibrary framework, that&#8217;s how!</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>imageMetadata <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
<span style="color: #400080;">NSURL</span> <span style="color: #002200;">*</span>assetURL <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span>info objectForKey<span style="color: #002200;">:</span>UIImagePickerControllerReferenceURL<span style="color: #002200;">&#93;</span>;
&nbsp;
ALAssetsLibrary <span style="color: #002200;">*</span>library <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>ALAssetsLibrary alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>library assetForURL<span style="color: #002200;">:</span>assetURL
    resultBlock<span style="color: #002200;">:^</span><span style="color: #002200;">&#40;</span>ALAsset <span style="color: #002200;">*</span>asset<span style="color: #002200;">&#41;</span>  <span style="color: #002200;">&#123;</span>
        <span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> asset.defaultRepresentation.metadata;
        imageMetadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> initWithDictionary<span style="color: #002200;">:</span>metadata<span style="color: #002200;">&#93;</span>;
        <span style="color: #002200;">&#91;</span>self addEntriesFromDictionary<span style="color: #002200;">:</span>metadata<span style="color: #002200;">&#93;</span>;
    <span style="color: #002200;">&#125;</span>
    failureBlock<span style="color: #002200;">:^</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSError</span> <span style="color: #002200;">*</span>error<span style="color: #002200;">&#41;</span> <span style="color: #002200;">&#123;</span>
    <span style="color: #002200;">&#125;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>library autorelease<span style="color: #002200;">&#93;</span>;</pre></div></div><p>One caveat on using this: because it uses blocks, there&#8217;s no guarantee that your imageMetadata dictionary will be populated when this code runs. In some testing I&#8217;ve done it sometimes runs the code inside the block even before the [library autorelease] is executed. But the first time you run this, the code inside the block will only run on another cycle of the apps main loop. So, if you need to use this info right away, it&#8217;s better to schedule a method on the run queue for later with:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">&#91;</span>self performSelectorOnMainThread<span style="color: #002200;">:</span>SELECTOR withObject<span style="color: #002200;">:</span>SOME_OBJECT waitUntilDone<span style="color: #002200;">:</span><span style="color: #a61390;">NO</span><span style="color: #002200;">&#93;</span>;</pre></div></div><p>To make things easier, I&#8217;ve created an init method to my category:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithInfoFromImagePicker<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>info;</pre></div></div><p>You just have to add the NSMutableDictionary+ImageMetadata.h to your file and then use:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> initWithInfoFromImagePicker<span style="color: #002200;">:</span>info<span style="color: #002200;">&#93;</span>;</pre></div></div><p>And you&#8217;re done! The category checks for the iOS version and for the correct keys and does everything for you. Just be careful about the issue with blocks I mentioned above.</p><h2>Reading from the asset library</h2><p>Well, I kinda spoiled the answer to this one already. If you&#8217;re using the AssetsLibrary to read images, you can use the method above, with the same caveat: it might not be accessible until some time after the method is called.</p><p>Again I created an init method in my category:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initFromAssetURL<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSURL</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>assetURL;</pre></div></div><h2>Using AVFoundation</h2><p>iOS 4.0 introduced AVFoundation. AVFoundation gives us a lot of possibilities to work with pictures and the camera. Before iOS 4 if you wanted to take a picture you&#8217;d have to use an UIImagePickerController. Now you can use AVFoundation and have a lot of control over the camera, the flash, the preview, etc&#8230;</p><p>If you use AVFoundation to capture photos you&#8217;ll probably use <a
href="http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVCaptureStillImageOutput_Class/Reference/Reference.html" target="_blank">AVCaptureStillImageOutput</a>&#8216;s:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>captureStillImageAsynchronouslyFromConnection<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>AVCaptureConnection <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>connection 
                                    completionHandler<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">^</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#40;</span>CMSampleBufferRef imageDataSampleBuffer, <span style="color: #400080;">NSError</span> <span style="color: #002200;">*</span>error<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>handler</pre></div></div><p>The completion handler gives you a CMSampleBufferRef that has the metadata. But how to get it out f there is not clear from the documentation. It turns out it&#8217;s really simple:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;">CFDictionaryRef metadataDict <span style="color: #002200;">=</span> CMCopyDictionaryOfAttachments<span style="color: #002200;">&#40;</span><span style="color: #a61390;">NULL</span>, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate<span style="color: #002200;">&#41;</span>;</pre></div></div><p>Since CFDictionaryRef is toll free bridged with NSDictionary, the whole process would look like this:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;">CFDictionaryRef metadataDict <span style="color: #002200;">=</span> CMCopyDictionaryOfAttachments<span style="color: #002200;">&#40;</span><span style="color: #a61390;">NULL</span>, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate<span style="color: #002200;">&#41;</span>;
<span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> initWithDictionary<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDictionary</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>metadataDict<span style="color: #002200;">&#93;</span>;
CFRelease<span style="color: #002200;">&#40;</span>metadataDict<span style="color: #002200;">&#41;</span>;</pre></div></div><p>At the risk of repeating myself, I again created an init method for this:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithImageSampleBuffer<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CMSampleBufferRef<span style="color: #002200;">&#41;</span> imageDataSampleBuffer;</pre></div></div><h2>Wrapping up</h2><p>So, there you have it, now you can read and write metadata.</p><p>What&#8217;s still missing are some methods to easily extract information from this dictionary. I have already created another method to extract the CLLocation information from it. As I now have a way to get and set this information I even converted it to a @property on the category, giving our NSMutableDictionary a nice way to access the location using the dot notation.</p><p>It&#8217;s very easy to add getter methods for every property but I have not done so yet. Feel free to fork <a
href="https://github.com/gpambrozio/GusUtils" target="_blank">my repo on GitHub</a> and send pull requests for me to incorporate.</p><p>I also added another method to add the image&#8217;s digital zoom as the next update of <strong><a
title="Get Snap now!" href="http://www.codecrop.com/snap/index.html">Snap</a></strong> will have digital zoom and I&#8217;m writing this information to the pictures as well.</p><p><a
href="http://www.codecrop.com/snap/index.html"><img
class="size-full wp-image-64 alignleft" title="SnapIcon75" src="http://blog.codecropper.com/wp-content/uploads/2011/04/SnapIcon75.png" alt="Snap iPhone camera app" width="75" height="75" /></a></p><p>Oh, and have I mentioned that you should get <strong><a
href="http://www.codecrop.com/snap/index.html">Snap</a></strong> for your iPhone? Check it out. You don&#8217;t know how useful and fun your iPhone camera can be until you have <strong><a
href="http://www.codecrop.com/snap/index.html">Snap</a></strong>!</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pE9FGrYXw8I:QletShNh7X0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pE9FGrYXw8I:QletShNh7X0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=pE9FGrYXw8I:QletShNh7X0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pE9FGrYXw8I:QletShNh7X0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=pE9FGrYXw8I:QletShNh7X0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=pE9FGrYXw8I:QletShNh7X0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/pE9FGrYXw8I" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2011/05/getting-metadata-from-images-on-ios/feed/</wfw:commentRss> <slash:comments>11</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2011/05/getting-metadata-from-images-on-ios/</feedburner:origLink></item> <item><title>Adding metadata to iOS images the easy way</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/6LEd2HR3Onw/</link> <comments>http://blog.codecropper.com/2011/05/adding-metadata-to-ios-images-the-easy-way/#comments</comments> <pubDate>Wed, 11 May 2011 10:00:51 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Sample code]]></category> <category><![CDATA[ios]]></category> <category><![CDATA[iphone]]></category> <category><![CDATA[snap]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=41</guid> <description><![CDATA[Does it have to be so hard? Are you writing a camera app or image editing app for iOS but are clueless on how to add geolocation to your pictures? Baffled by the lack of information in the otherwise very thorough XCode documentation? I feel your pain my friend. Or actually, felt, cause I got [...]]]></description> <content:encoded><![CDATA[<h2>Does it have to be so hard?</h2><p><img
class="alignright size-full wp-image-135" title="computersmash" src="http://blog.codecropper.com/wp-content/uploads/2011/05/computersmash.gif" alt="" width="200" height="213" />Are you writing a camera app or image editing app for iOS but are clueless on how to add geolocation to your pictures? Baffled by the lack of information in the otherwise very thorough XCode documentation? I feel your pain my friend. Or actually, felt, cause I got your meds right here.</p><p>When developing <a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> I wanted to add this feature so that it could actually replace the built-in camera app. And since the built-in camera app adds geolocation, along with a lot of other metadata to the images, <a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> had to do this too.</p><p>I present to you my NSMutableDictionary category that will solve all your problems. Ok, maybe not all, but the ones related to image metadata on iOS anyway.</p><p>For those with no patience, here&#8217;s the GitHub repo: <a
href="https://github.com/gpambrozio/GusUtils" target="_blank">https://github.com/gpambrozio/GusUtils</a>. The repo contains an XCode project that should compile a nice static library for you to use on your projects. I plan on add a lot of utility classes here, so you might just want to pick and choose whatever you need to use instead of using the whole library.</p><p>The category is easy enough to use if you check out the code, but I&#8217;ll explain a few things on how to use it for those that never had to deal with image metadata on iOS before.</p><h2>Who is this metadata person anyway?</h2><p>For those of you that have no idea what I&#8217;m talking about, image metadata is most commonly known as <a
href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format" target="_blank">EXIF</a> data, even though that&#8217;s slightly wrong because EXIF data is only one type of metadata that can be embedded in an image file. My category deals with <a
href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format" target="_blank">EXIF</a> metadata, as well as with <a
href="http://en.wikipedia.org/wiki/Tagged_Image_File_Format" target="_blank">TIFF</a> and <a
href="http://en.wikipedia.org/wiki/IPTC_Information_Interchange_Model" target="_blank">IPTC</a> metadata, depending on what kind of information you want to add to the image.</p><p><img
class="alignright size-medium wp-image-132" title="TIFF metadata" src="http://blog.codecropper.com/wp-content/uploads/2011/05/Screen-shot-2011-05-10-at-3.18.11-PM-256x300.png" alt="" width="256" height="300" /></p><p>For example, the Original Date of an image can be embedded inside an EXIF property or inside a TIFF property. My category knows this and if you want to embed this date it will set both properties for you.</p><p>You can see all this metadata using most image viewers. On OSX, if you press cmd-i on the Preview app you can see an image&#8217;s metadata.</p><h2>How does it work on iOS?</h2><p>iOS SDK 4.1 introduced some methods that allowed an app to write image metadata in an image. One example is ALAssetsLibrary&#8217;s:</p><p><a
href="http://developer.apple.com/library/ios/documentation/AssetsLibrary/Reference/ALAssetsLibrary_Class/Reference/Reference.html#//apple_ref/occ/instm/ALAssetsLibrary/writeImageToSavedPhotosAlbum:metadata:completionBlock:" target="_blank">- (void)writeImageToSavedPhotosAlbum: metadata: completionBlock: completionBlock</a></p><p>That takes a NSDictionary as the metadata source. What the documentation doesn&#8217;t explain (or at least I could not find) is how this dictionary should be. I googled a lot and found some examples online that I used as a starting point for the category (sorry, can&#8217;t remember most of them&#8230;).</p><p>Turns out that this dictionary consists of a lot of other NSDictionaries with key/values that are dependent on the type of metadata you&#8217;re adding. You can find all the dictionaries that go inside this dictionary (I know&#8230;. even I&#8217;m getting confused with so many dictionaries&#8230;) in the<a
href="http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGImageProperties_Reference/Reference/reference.html" target="_blank"> CGImageProperties Reference</a> of the documentation.</p><p>I&#8217;ll try to explain with an example. Say you want to add a &#8220;Description&#8221; property in your image. This property sits inside the TIFF dictionary. So, in order to add this information to your metadata dictionary you can use this code:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>tiffMetadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>tiffMetadata setObject<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is my description&quot;</span> forKey<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>kCGImagePropertyTIFFImageDescription<span style="color: #002200;">&#93;</span>;
<span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>metadata setObject<span style="color: #002200;">:</span>tiffMetadata forKey<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>kCGImagePropertyTIFFDictionary<span style="color: #002200;">&#93;</span>;</pre></div></div><p>Why am I using NSMutableDictionary? Well, in this example you really don&#8217;t have to, but say you want to add another TIFF property to your metadata, with NSMutableDictionary you can just add another key/value to the tiffMetadata dictionary. If you used NSDictionary you&#8217;d have to create a new NSDictionary with the old key/values plus the new key/value. Not cool&#8230;.</p><p>Adding geolocation is even harder. Geolocation has it&#8217;s own dictionary with a <a
href="http://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGImageProperties_Reference/Reference/reference.html#//apple_ref/doc/constant_group/GPS_Dictionary_Keys" target="_blank">lot of possible values</a> that are NOT explained in the documentation. The best information I found about this was in <a
href="http://stackoverflow.com/questions/3884060/saving-geotag-info-with-photo-on-ios4-1" target="_blank">this StackOverflow question</a> that I used as the basis for my implementation.</p><h2>Please, help, I don&#8217;t want to do this&#8230;</h2><p>The <a
href="https://github.com/gpambrozio/GusUtils/blob/master/GusUtils/NSMutableDictionary+ImageMetadata.m" target="_blank">NSMutableDDictionary+ImageMetadata</a> category takes all this complexity away from your code. To add geolocation to your metadata dictionary, all you have to do is this:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>metadata <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>metadata setLocation<span style="color: #002200;">:</span>location<span style="color: #002200;">&#93;</span>;</pre></div></div><p>Where <em>location</em> is a <em>CLLocation</em> instance. That&#8217;s it. My category will create the appropriate dictionary and add it to your NSMutableDictionary with all the appropriate key/values. I&#8217;ve implemented some other interesting setters and there are some helper methods that make it very easy to add methods for other properties:</p><div
class="wp_syntax"><div
class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setLocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>CLLocation <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>currentLocation;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setUserComment<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>comment;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setDateOriginal<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>date;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setDateDigitized<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSDate</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>date;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setMake<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>make model<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>model software<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>software;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setDescription<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>description;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setKeywords<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span><span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>keywords;
<span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>setImageOrientarion<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>UIImageOrientation<span style="color: #002200;">&#41;</span>orientation;</pre></div></div><p>&nbsp;</p><p>After setting all your properties, you can call ALAssetsLibrary&#8217;s <a
href="http://developer.apple.com/library/ios/documentation/AssetsLibrary/Reference/ALAssetsLibrary_Class/Reference/Reference.html#//apple_ref/occ/instm/ALAssetsLibrary/writeImageDataToSavedPhotosAlbum:metadata:completionBlock:" target="_blank">– writeImageDataToSavedPhotosAlbum:metadata:completionBlock:</a> or <a
href="http://developer.apple.com/library/ios/documentation/AssetsLibrary/Reference/ALAssetsLibrary_Class/Reference/Reference.html#//apple_ref/occ/instm/ALAssetsLibrary/writeImageToSavedPhotosAlbum:metadata:completionBlock:" target="_blank">– writeImageToSavedPhotosAlbum:metadata:completionBlock:</a>. using your very special NSMutableDictionary and you&#8217;re all set!</p><h2>Getting metadata</h2><p>There&#8217;s another hard to find issue with metadata and that&#8217;s getting it from an image you just took using <a
href="http://developer.apple.com/library/ios/#documentation/uikit/reference/UIImagePickerController_Class/UIImagePickerController/UIImagePickerController.html" target="_blank">UIImagePickerController</a> or an <a
href="http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVCaptureStillImageOutput_Class/Reference/Reference.html" target="_blank">AVCaptureStillImageOutput</a>. I&#8217;ll deal with this problem in another post but rest assured that out friendly category will help you a lot too. (UPDATE: The reading part in on <a
href="http://blog.codecropper.com/2011/05/getting-metadata-from-images-on-ios/">this blog post</a>)</p><h2>Can I use this?</h2><p>Yes, use it, fork it, spread the word. And if you make any improvements to your fork, or if you found a bug or a better way to do things, please send me a pull request so that I can incorporate your improvements into the main branch.</p><p>And if you really want t help me out and get a nice app at the same time, get <a
href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> for your iPhone. Best 2 bucks you&#8217;ll spend today!</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6LEd2HR3Onw:KjHWtVvMlA4:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6LEd2HR3Onw:KjHWtVvMlA4:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=6LEd2HR3Onw:KjHWtVvMlA4:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6LEd2HR3Onw:KjHWtVvMlA4:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6LEd2HR3Onw:KjHWtVvMlA4:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=6LEd2HR3Onw:KjHWtVvMlA4:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/6LEd2HR3Onw" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2011/05/adding-metadata-to-ios-images-the-easy-way/feed/</wfw:commentRss> <slash:comments>36</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2011/05/adding-metadata-to-ios-images-the-easy-way/</feedburner:origLink></item> <item><title>Apple App Store user review frustration</title><link>http://feedproxy.google.com/~r/TheCodecropper/~3/6fJmZIB6cQY/</link> <comments>http://blog.codecropper.com/2011/04/apple-app-store-user-review-frustration/#comments</comments> <pubDate>Wed, 27 Apr 2011 05:49:21 +0000</pubDate> <dc:creator>Gustavo</dc:creator> <category><![CDATA[Marketing]]></category> <category><![CDATA[app store]]></category> <category><![CDATA[marketing]]></category> <category><![CDATA[snap]]></category> <guid isPermaLink="false">http://blog.codecropper.com/?p=7</guid> <description><![CDATA[No, it&#8217;s not another App Store rant A lot has been said about Apple&#8217;s app store, the review process, the whole walled garden stuff, etc&#8230; As an iOS developer I feel this pain sometimes, especially when my apps go into that state of &#8220;waiting for review&#8221;, but I tend to take this as a side [...]]]></description> <content:encoded><![CDATA[<h2>No, it&#8217;s not another App Store rant</h2><p><img
class="alignleft size-full wp-image-56" title="app-store" src="http://blog.codecropper.com/wp-content/uploads/2011/04/app-store1.png" alt="" width="130" height="131" />A lot has been said about Apple&#8217;s app store, the review process, the whole walled garden stuff, etc&#8230; As an iOS developer I feel this pain sometimes, especially when my apps go into that state of &#8220;waiting for review&#8221;, but I tend to take this as a side effect of a drug that makes more good than harm.</p><p>The fact is that Apple&#8217;s app store revolutionized the software industry and has changed the lives of a lot of independent developers that can now offer the fruits of their labor to millions of people. I know that I changed a lot in my life and, even if I still can&#8217;t rely only on my app sales, I have a firm belief that it will happen soon.</p><h2>The Problem</h2><p>But there&#8217;s one thing about Apple&#8217;s app store that I think needs changing and I have not read about it anywhere before: the user review process.</p><p>When something costs money, even when it&#8217;s under a dollar, people want some validation before buying it. And in the app store user reviews are a valuable source for this information. A lot of users (me included) read them before buying an app. I even do it for free apps sometimes so I don&#8217;t even waste my time on an app that has mostly bad reviews.</p><p>I got very lucky with <a
title="Snap" href="http://www.codecrop.com/snap/index.html" target="_blank">Snap</a> when I first released it. I had a nice review from <a
title="AppAdvice review of Snap" href="http://appadvice.com/appnn/2011/03/snap-updated-101-features-bug-fixes-chance-win-copy/" target="_blank">AppAdvice</a> and got featured by Apple in the new and noteworthy section of both the photography section and on the home page of iTunes in the US and some other countries. This gave me a lot of sales and a lot of happy customers. I had a lot of users asking for support but it was mostly feature suggestions or questions about using the app, but everybody was happy.</p><p>But then I received two user reviews that worried me. One said that the app didn&#8217;t work, that it was a rip off and the other said that the app locked in a screen with a &#8220;done&#8221; button (there&#8217;s no done button in my app&#8230;). I opened an issue using itunesconnect asking them to remove these two reviews, stating that I had more than 3000 sales and no complaints of this nature and NO done button but they replied saying that these reviews didn&#8217;t meet their standards for removal.</p><p><img
class="alignright size-full wp-image-25" title="itunes-reviews" src="http://blog.codecropper.com/wp-content/uploads/2011/04/itunes-reviews.png" alt="iTunes reviews" width="418" height="297" /></p><p>And to make matters worse, these two reviews got to the top of the list because a lot of people found them useful. Meaning two things: first, that people tend to &#8220;like&#8221; negative reviews more than positive ones; and second, a lot of people wouldn&#8217;t buy my app because they didn&#8217;t even see the lots of other good reviews I had.</p><p>So, at this point, there&#8217;s nothing I can do about this. These users could have sent me an email or clicked the support link that leads to a Zendesk site I use to provide support, but they didn&#8217;t. They just complained and gave me no way of helping them.</p><p>And that&#8217;s very frustrating. I really want to make this the best app I can make and I take user support very seriously but in this case there was nothing I could do. So, how can this be solved?</p><h2>A suggestion</h2><p>My suggestion would be to implement in itunesconnect a way for developers to reply to their customers. I don&#8217;t know exactly why Apple won&#8217;t give us these user&#8217;s emails, but let&#8217;s assume they have some valid reasons for this, like fearing that we can harass their users or try to bribe them to make them change their reviews. So, with an interface like this in itunesconnect we can send a message to these users without ever knowing their email. We write the reply and Apple sends an email to the user. The user can reply to this email and it would go back to itunesconnect without showing any emails.</p><p><img
class="alignright size-full wp-image-35" title="535px-5_stars-svg" src="http://blog.codecropper.com/wp-content/uploads/2011/04/535px-5_stars-svg.png" alt="" width="200" height="41" />And, as the whole process gets logged by Apple, they can give us some guidelines we&#8217;d have to follow, like never asking for an email or phone number. If a developer breaks these rules he gets banned from the app store or gets a warning about it. To help enforce these rules Apple can build some automated rules that &#8220;reads&#8221; the emails to try to determine if some rules are getting broken.</p><p>They could even give us a way to refund the customer automatically if we can&#8217;t resolve the issue for some odd reason. I would rather give a few bucks back to a user who&#8217;s unhappy with my app for some reason than have one unsatisfied cusomer giving me bad reviews.</p><h2>Conclusion</h2><p>I know that bashing Apple and the app store is very frequent among developers and bloggers but that&#8217;s not the case here. I believe Apple is doing a nice job with the whole iOS line and the app store and I&#8217;m happy to be able to be a part of it. But I believe the review process can be better and Apple can help us with a way to get in touch with our customers. I think it can even take some work off their own support staff that has to deal with a lot of refund requests and complaints about apps.</p><p>What do you guys think? Any other ideas?</p> <div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6fJmZIB6cQY:OYqfDirzAGw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6fJmZIB6cQY:OYqfDirzAGw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=6fJmZIB6cQY:OYqfDirzAGw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6fJmZIB6cQY:OYqfDirzAGw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/TheCodecropper?a=6fJmZIB6cQY:OYqfDirzAGw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/TheCodecropper?i=6fJmZIB6cQY:OYqfDirzAGw:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/TheCodecropper/~4/6fJmZIB6cQY" height="1" width="1"/>]]></content:encoded> <wfw:commentRss>http://blog.codecropper.com/2011/04/apple-app-store-user-review-frustration/feed/</wfw:commentRss> <slash:comments>6</slash:comments> <feedburner:origLink>http://blog.codecropper.com/2011/04/apple-app-store-user-review-frustration/</feedburner:origLink></item> </channel> </rss><!-- Dynamic page generated in 3.545 seconds. --><!-- Cached page generated by WP-Super-Cache on 2013-04-11 08:08:25 --><!-- Compression = gzip -->
