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

<channel>
	<title>i’m so full of ideas &#187; objective-c</title>
	<atom:link href="http://www.platinumball.net/blog/category/objective-c/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.platinumball.net/blog</link>
	<description>blog</description>
	<lastBuildDate>Wed, 26 May 2010 17:16:40 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>iPhone: nibless</title>
		<link>http://www.platinumball.net/blog/2010/02/28/iphone-nibless/</link>
		<comments>http://www.platinumball.net/blog/2010/02/28/iphone-nibless/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 23:07:07 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=327</guid>
		<description><![CDATA[I just had a look, and my blog is the number one hit on google for the search phrase &#8220;iphone nibless.&#8221; That leads to a blog post I wrote on the subject last year. I linked to another blog that explained how to accomplish such a goal, but that blog post has since been taken [...]]]></description>
			<content:encoded><![CDATA[<p>I just had a look, and my blog is the number one hit on google for the search phrase &#8220;iphone nibless.&#8221; That leads to a blog post I wrote on the subject last year. I linked to another blog that explained how to accomplish such a goal, but that blog post has since been taken down. Hrmph. Okay, I guess I have to cover this subject again.</p>
<p>Generally speaking, Apple makes beautiful apps that are elegant and easy to use. Interface Builder is a glaring exception. I can&#8217;t <i>stand</i> that thing. So unbelievably complicated. I can&#8217;t ever find what I&#8217;m looking for.</p>
<p>If you&#8217;re writing Mac apps, I guess you&#8217;re stuck with it. Most Mac windows contain a lot of controls, and you need a way to design them. If you&#8217;re writing iPhone apps, it&#8217;s a net loss. Most iPhone views contain a single control that takes up the entire view area, so Interface Builder is an unnecessary complication. So I&#8217;m going to tell you how to make an iPhone app that does not require any nibs at all. I am using Xcode 3.2.1 on Snow Leopard, but these instructions will likely work for older versions as well.</p>
<p>1) Start Xcode. From the File menu, pick &#8220;New Project.&#8221; In the window that opens, select the iPhone OS Application category on the left. In the group on the right, pick &#8220;Window-based Application.&#8221; This may work fine for the other project templates, but I haven&#8217;t tested that. Create the new project, name it whatever you want.</p>
<p>2) Remove MainWindow.xib from the project and put it into the trash. It is no longer needed. (Yay!)</p>
<p>3) Edit the Info.plist for your project by double-clicking on it. It will have a name similar to projectname-Info.plist. The plist file will have a key named &#8220;Main nib file base name,&#8221; with the value MainWindow. Remove this key completely: select it, and press the Delete key. Save the file.</p>
<p>4) Xcode will have created an app delegate class for your project, named something like niblessAppDelegate. Yuck, what a horrible name. Rename this class to AppController, by directly editing the header and source files for the class. You can of course pick a different name, or even skip this step altogether, but I&#8217;m going to assume from here on out that your app delegate class is called AppController.</p>
<p>5) At this point, you have destroyed the mechanism that iPhone OS normally uses to recognize the name of your app delegate class, which it needs to know to load your app. Fortunately, there is an easy way around this: you must pass your app delegate&#8217;s class name to UIApplicationMain(). Xcode created a file called main.m that contains your app&#8217;s main() function. Edit it now, and change main() so that it looks like this:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc, <span class="kw4">char</span> <span class="sy0">*</span>argv<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/"><span class="kw5">NSAutoreleasePool</span></a><span class="sy0">*</span> &nbsp;pool <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span><a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/"><span class="kw5">NSAutoreleasePool</span></a> alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span>;
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw4">int</span> retVal <span class="sy0">=</span> UIApplicationMain<span class="br0">&#40;</span>argc, argv, <span class="kw2">nil</span>, <span class="co3">@</span><span class="st0">&quot;AppController&quot;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="br0">&#91;</span>pool release<span class="br0">&#93;</span>;
&nbsp; &nbsp; pool <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> retVal;
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>That&#8217;s it, you&#8217;re done. You may continue modifying this project until you have a real application.</p>
<p>At this point, you might be thinking: Whoa, scary change. Is this really safe? Well, I can offer myself up as an example. I&#8217;ve submitted two of my own apps to the App Store that use this technique, both of which have been downloaded thousands of times. I&#8217;ve gotten hundreds of emails from users over various issues, but my apps not having nibs has never been a problem.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2010/02/28/iphone-nibless/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UIProgressHUD replacement</title>
		<link>http://www.platinumball.net/blog/2010/02/27/uiprogresshud-replacement/</link>
		<comments>http://www.platinumball.net/blog/2010/02/27/uiprogresshud-replacement/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 05:22:16 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=324</guid>
		<description><![CDATA[Dear internet: I have been searching for a UIProgressHUD replacement for many, many months. Why have you failed me? I don&#8217;t suppose it was because of that other, similarly named UIProgressHUD replacement? Which I am not going to link to or name, because it sucks. Sorry, yes I am a jerk, but it does. If [...]]]></description>
			<content:encoded><![CDATA[<p>Dear internet: I have been searching for a UIProgressHUD replacement for many, many months. Why have you failed me? I don&#8217;t suppose it was because of that other, similarly named UIProgressHUD replacement? Which I am not going to link to or name, because it sucks. Sorry, yes I am a jerk, but it does. If I have to explain to you why it&#8217;s a bad idea to make a progress view that&#8217;s <em>launching background tasks</em>, then there is no helping you.</p>
<div class="wp-caption alignleft" style="width: 211px"><a href="http://www.platinumball.net/blog/graphics/hud1.png"><img title="UIProgressHUD" src="http://www.platinumball.net/blog/graphics/hud1small.png" alt="" width="201" height="368" /></a><p class="wp-caption-text">UIProgressHUD</p></div>
<p>So, anyway. In case you&#8217;re new to this. UIKit has a nice control called UIProgressHUD for displaying a heads-up, semi-transparent view with a spinny-control on it, and a single line of text. It looks good, it works well, it&#8217;s easy. The only down side is that it&#8217;s undocumented, so you can&#8217;t use it in apps destined for the App Store.</p>
<p>I used UIProgressHUD in a project I was writing for a client a few months ago. This particular app was not destined for the App Store, so it seemed like a nice shortcut. Maybe that&#8217;s not such a hot idea, but they weren&#8217;t paying much, so I couldn&#8217;t justify a detour for writing a brand-new view. But now here I am again, needing the exact same thing for my card game, and google searches still only turn up that progress view that thinks it&#8217;s an app launcher. Hrmph. Time to write my own, I guess.</p>
<div class="wp-caption alignright" style="width: 214px"><a href="http://www.platinumball.net/blog/graphics/hud2.png"><img title="WBProgressHUD" src="http://www.platinumball.net/blog/graphics/hud2small.png" alt="" width="204" height="370" /></a><p class="wp-caption-text">WBProgressHUD</p></div>
<p>My goal was to write an exact, drop-in replacement for that view I can&#8217;t use. I&#8217;ve included screenshots of Apple&#8217;s original view, and my clone view. Pretty darn close, don&#8217;t you think? The only real differences are details that I don&#8217;t want to change. For example, I think they picked a font size that&#8217;s a bit excessive.</p>
<p>It would be great if I could just paste the source file and header file right into this post, for your amusement. My view is mercifully short, and would lend itself to that. Alas, it requires several support modules, so I had to make it into an example Xcode project. I&#8217;ve developed a huge library of iPhone support code by this point, so it doesn&#8217;t make sense to duplicate things in every single view and controller I write.</p>
<p>One clever feature of my demo project: you can change one line of code and it will use either UIProgressHUD or my own WBProgressHUD. No other code has to change, because the two views are <em>that</em> similar, dawg. It makes for a good test bed for developing a clone view such as this one.</p>
<p><a href="http://www.platinumball.net/blog/bin/wbprogresshud.zip">Download wbprogresshud.zip by clicking here</a>. If you like this project, how about hiring me to write more stuff like it? <a href="http://www.platinumball.net/blog/about/">My contact details are on my About page</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2010/02/27/uiprogresshud-replacement/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone: UIImage rotation and scaling</title>
		<link>http://www.platinumball.net/blog/2010/01/31/iphone-uiimage-rotation-and-scaling/</link>
		<comments>http://www.platinumball.net/blog/2010/01/31/iphone-uiimage-rotation-and-scaling/#comments</comments>
		<pubDate>Mon, 01 Feb 2010 02:03:10 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=247</guid>
		<description><![CDATA[Hello to my three remaining blog subscribers! Long time no see!
For my first post back after my long hiatus, I&#8217;m going to revisit the single most popular entry I&#8217;ve written to date, which was about UIImage rotation. I&#8217;ve used that code a great deal since I first wrote it. I&#8217;ve modified it several times. It&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>Hello to my three remaining blog subscribers! Long time no see!</p>
<p>For my first post back after my long hiatus, I&#8217;m going to revisit the single most popular entry I&#8217;ve written to date, which was about <a href="http://www.platinumball.net/blog/2009/03/30/iphone-uiimage-rotation-and-mirroring/">UIImage rotation</a>. I&#8217;ve used that code a great deal since I first wrote it. I&#8217;ve modified it several times. It&#8217;s pretty near perfect at this point.</p>
<p>The original code I modified for that earlier post was for dealing with photos taken with the iPhone camera. I stripped out a lot of that stuff, because I was only interested in rotating images that were embedded in the program. And then, wouldn&#8217;t you know it, I got a contract job that required me to deal with iPhone camera images as well. So I had to revisit the subject.</p>
<p>The original code from blog.logichigh.com had the rotation and scaling all lumped together in one chaotic function. I split it out into separate rotation and scaling methods, so they can be used independently. It also makes for easier code maintenance.</p>
<p>The code contains <tt>[UIImage rotate:]</tt>, which works the same as the last time around, but it has been streamlined a bit internally. It will rotate any <tt>UIImage</tt> to any orientation, with or without mirroring. Then we have two scaling methods, the simplest being <tt>[UIImage scaleWithMaxSize:]</tt>. You provide it with a float value, which is the largest width and/or height that you want the output image to have. If the input image is already smaller than that, it won&#8217;t be scaled.</p>
<p>Finally, the all-singing, all-dancing method for massaging photos from the iPhone camera: <tt>[UIImage rotateAndScaleFromCameraWithMaxSize:]</tt>. It examines the EXIF data in the image and, if needed, rotates it to the proper orientation. Then it scales the image to the maximum width and/or height supplied to the method.</p>
<p>This code has been thoroughly tested in several real-world iPhone projects. There are no known bugs. If you find one, I&#8217;d love to hear about it, so I can fix it.</p>
<p>Here&#8217;s the header file, WBImage.h:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// WBImage.h -- extra UIImage methods</span>
<span class="co2">// by allen brunson &nbsp;march 29 2009</span>

<span class="co1">#ifndef WBIMAGE_H</span>
<span class="co1">#define WBIMAGE_H</span>

<span class="co1">#import &lt;UIKit/UIKit.h&gt;</span>

<span class="kw1">@interface</span> UIImage <span class="br0">&#40;</span>WBImage<span class="br0">&#41;</span>

<span class="co2">// rotate UIImage to any angle</span>
<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotate<span class="sy0">:</span><span class="br0">&#40;</span>UIImageOrientation<span class="br0">&#41;</span>orient;

<span class="co2">// rotate and scale image from iphone camera</span>
<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotateAndScaleFromCameraWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize;

<span class="co2">// scale this image to a given maximum width and height</span>
<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>scaleWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize;
<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>scaleWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize
&nbsp;quality<span class="sy0">:</span><span class="br0">&#40;</span>CGInterpolationQuality<span class="br0">&#41;</span>quality;

<span class="kw1">@end</span>

<span class="co1">#endif &nbsp;// WBIMAGE_H</span></div>
</div>
</pre>
<p>And here&#8217;s the implementation file, WBImage.mm:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// WBImage.mm -- extra UIImage methods</span>
<span class="co2">// by allen brunson &nbsp;march 29 2009</span>

<span class="co1">#include &quot;WBImage.h&quot;</span>

<span class="kw4">static</span> inline CGFloat degreesToRadians<span class="br0">&#40;</span>CGFloat degrees<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> M_PI <span class="sy0">*</span> <span class="br0">&#40;</span>degrees <span class="sy0">/</span> 180.0<span class="br0">&#41;</span>;
<span class="br0">&#125;</span>

<span class="kw4">static</span> inline CGSize swapWidthAndHeight<span class="br0">&#40;</span>CGSize size<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGFloat &nbsp;swap <span class="sy0">=</span> size.width;

&nbsp; &nbsp; size.width &nbsp;<span class="sy0">=</span> size.height;
&nbsp; &nbsp; size.height <span class="sy0">=</span> swap;

&nbsp; &nbsp; <span class="kw1">return</span> size;
<span class="br0">&#125;</span>

<span class="kw1">@implementation</span> UIImage <span class="br0">&#40;</span>WBImage<span class="br0">&#41;</span>

<span class="co2">// rotate an image to any 90-degree orientation, with or without mirroring.</span>
<span class="co2">// original code by kevin lohman, heavily modified by yours truly.</span>
<span class="co2">// http://blog.logichigh.com/2008/06/05/uiimage-fix/</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotate<span class="sy0">:</span><span class="br0">&#40;</span>UIImageOrientation<span class="br0">&#41;</span>orient
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; UIImage<span class="sy0">*</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; copy <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGContextRef &nbsp; &nbsp; &nbsp; ctxt <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rect <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; CGAffineTransform &nbsp;tran <span class="sy0">=</span> CGAffineTransformIdentity;

&nbsp; &nbsp; bnds.size <span class="sy0">=</span> self.size;
&nbsp; &nbsp; rect.size <span class="sy0">=</span> self.size;

&nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span>orient<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationUp<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> self;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationUpMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.width, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationDown<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.width,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, degreesToRadians<span class="br0">&#40;</span>180.0<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationDownMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>0.0, rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, 1.0, <span class="sy0">-</span>1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeft<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>0.0, rect.size.width<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, degreesToRadians<span class="br0">&#40;</span><span class="sy0">-</span>90.0<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeftMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.height,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rect.size.width<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, degreesToRadians<span class="br0">&#40;</span><span class="sy0">-</span>90.0<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRight<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.height, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, degreesToRadians<span class="br0">&#40;</span>90.0<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRightMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeScale<span class="br0">&#40;</span><span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, degreesToRadians<span class="br0">&#40;</span>90.0<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">// orientation value supplied is invalid</span>
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/assert.html"><span class="kw3">assert</span></a><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; UIGraphicsBeginImageContext<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; ctxt <span class="sy0">=</span> UIGraphicsGetCurrentContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span>orient<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeft<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeftMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRight<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRightMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>ctxt, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>ctxt, <span class="sy0">-</span>rect.size.height, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>ctxt, 1.0, <span class="sy0">-</span>1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>ctxt, 0.0, <span class="sy0">-</span>rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; CGContextConcatCTM<span class="br0">&#40;</span>ctxt, tran<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextDrawImage<span class="br0">&#40;</span>ctxt, rect, self.CGImage<span class="br0">&#41;</span>;

&nbsp; &nbsp; copy <span class="sy0">=</span> UIGraphicsGetImageFromCurrentImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; UIGraphicsEndImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">return</span> copy;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotateAndScaleFromCameraWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize
<span class="br0">&#123;</span>
&nbsp; &nbsp; UIImage<span class="sy0">*</span> &nbsp;imag <span class="sy0">=</span> self;

&nbsp; &nbsp; imag <span class="sy0">=</span> <span class="br0">&#91;</span>imag rotate<span class="sy0">:</span>imag.imageOrientation<span class="br0">&#93;</span>;
&nbsp; &nbsp; imag <span class="sy0">=</span> <span class="br0">&#91;</span>imag scaleWithMaxSize<span class="sy0">:</span>maxSize<span class="br0">&#93;</span>;

&nbsp; &nbsp; <span class="kw1">return</span> imag;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>scaleWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="br0">&#91;</span>self scaleWithMaxSize<span class="sy0">:</span>maxSize quality<span class="sy0">:</span>kCGInterpolationHigh<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>scaleWithMaxSize<span class="sy0">:</span><span class="br0">&#40;</span>CGFloat<span class="br0">&#41;</span>maxSize
&nbsp;quality<span class="sy0">:</span><span class="br0">&#40;</span>CGInterpolationQuality<span class="br0">&#41;</span>quality
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp;bnds <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; UIImage<span class="sy0">*</span> &nbsp; &nbsp; &nbsp;copy <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp;orig <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; CGFloat &nbsp; &nbsp; &nbsp; rtio <span class="sy0">=</span> <span class="nu0">0.0</span>;
&nbsp; &nbsp; CGFloat &nbsp; &nbsp; &nbsp; scal <span class="sy0">=</span> <span class="nu0">1.0</span>;

&nbsp; &nbsp; bnds.size <span class="sy0">=</span> self.size;
&nbsp; &nbsp; orig.size <span class="sy0">=</span> self.size;
&nbsp; &nbsp; rtio <span class="sy0">=</span> orig.size.width <span class="sy0">/</span> orig.size.height;

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="br0">&#40;</span>orig.size.width &lt;<span class="sy0">=</span> maxSize<span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="br0">&#40;</span>orig.size.height &lt;<span class="sy0">=</span> maxSize<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> self;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>rtio &gt; 1.0<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size.width &nbsp;<span class="sy0">=</span> maxSize;
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size.height <span class="sy0">=</span> maxSize <span class="sy0">/</span> rtio;
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp; &nbsp; <span class="kw1">else</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size.width &nbsp;<span class="sy0">=</span> maxSize <span class="sy0">*</span> rtio;
&nbsp; &nbsp; &nbsp; &nbsp; bnds.size.height <span class="sy0">=</span> maxSize;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; UIGraphicsBeginImageContext<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; ctxt <span class="sy0">=</span> UIGraphicsGetCurrentContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; scal <span class="sy0">=</span> bnds.size.width <span class="sy0">/</span> orig.size.width;
&nbsp; &nbsp; CGContextSetInterpolationQuality<span class="br0">&#40;</span>ctxt, quality<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>ctxt, scal, <span class="sy0">-</span>scal<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>ctxt, 0.0, <span class="sy0">-</span>orig.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextDrawImage<span class="br0">&#40;</span>ctxt, orig, self.CGImage<span class="br0">&#41;</span>;

&nbsp; &nbsp; copy <span class="sy0">=</span> UIGraphicsGetImageFromCurrentImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; UIGraphicsEndImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">return</span> copy;
<span class="br0">&#125;</span>

<span class="kw1">@end</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2010/01/31/iphone-uiimage-rotation-and-scaling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone: keyboard trouble</title>
		<link>http://www.platinumball.net/blog/2009/08/28/iphone-keyboard-trouble/</link>
		<comments>http://www.platinumball.net/blog/2009/08/28/iphone-keyboard-trouble/#comments</comments>
		<pubDate>Fri, 28 Aug 2009 09:07:56 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=239</guid>
		<description><![CDATA[A couple of months ago, a user of my card game reported a bug. He said that when he tried to change the names of all the robot players at once, only one of them actually changed. I tried to duplicate the problem, but couldn&#8217;t. For me, all three robot player names changed. I asked [...]]]></description>
			<content:encoded><![CDATA[<div class="wp-caption alignleft" style="width: 285px"><img class="    " style="bold" title="text fields" src="http://www.platinumball.net/blog/graphics/text_fields_small.png" alt="It is possible to type into two or more of these fields at once without dismissing the keyboard" width="275" height="500" /><p class="wp-caption-text">It is possible to type into two or more of these fields without dismissing the keyboard</p></div>
<p>A couple of months ago, a user of <a href="http://www.platinumball.net/hearts/">my card game</a> reported a bug. He said that when he tried to change the names of all the robot players at once, only one of them actually changed. I tried to duplicate the problem, but couldn&#8217;t. For me, all three robot player names changed. I asked him for more details, but like many non-technical users, he wasn&#8217;t able to articulate the problem very well. He said he kept fiddling and fiddling and eventually got all three names changed. I had made a real effort to duplicate the bug and failed. So I wrote this one off as user error.</p>
<p>Over the next few weeks, the same bug got reported three more times. I was still not able to reproduce it. I asked for more specific instructions on how to tickle the bug, but none of this batch of people took the time to send a second email. I can&#8217;t blame them. Most people view it as a frivolous time-wasting diversion, useful for whiling away a few minutes while in line at the grocery or something.</p>
<p>Fortunately for me, the fifth report came from a fellow programmer. He provided very explicit instructions, and I was finally able to reproduce it. Now that I understand what was happening, it&#8217;s no small wonder that it evaded me for so long. The problem was that my mental model of how the iPhone accepts text input was wrong.</p>
<p>I had assumed the sequence of events was always like this:</p>
<p>• User touches an editable text field<br />
• Keyboard rolls up into view<br />
• User types some text<br />
• User presses the return key on the keyboard<br />
• Program forces the keyboard to disappear<br />
• Program processes the new text</p>
<p>But guess what, here is another possible sequence of events:</p>
<p>• User touches an editable text input field<br />
• Keyboard rolls up into view<br />
• User types some text<br />
• <em>User touches a second text input field</em><br />
• <em>User edits the second input field</em><br />
• User presses the return key on the keyboard<br />
• Program forces the keyboard to disappear<br />
• Program processes the new text</p>
<p>A third possible outcome is that the user navigates away from the current view to a different one, and therefore <em>never</em> presses the return key.</p>
<p>This sounds complicated, but it turns out that the fix is pretty easy. You simply have to treat &#8220;user pressed the return key&#8221; and &#8220;user finished editing&#8221; as two separate events, rather than conflating them as one.</p>
<p>The assumption here it that your users are typing into UITextField objects. The fix I&#8217;m proposing is for UITextField delegates, i.e., whatever object implements the UITextFieldDelegate protocol. Here&#8217;s an example implementation of one of those methods:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">BOOL</span><span class="br0">&#41;</span>textFieldShouldReturn<span class="sy0">:</span><span class="br0">&#40;</span>UITextField<span class="sy0">*</span><span class="br0">&#41;</span>textField
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>textField resignFirstResponder<span class="br0">&#93;</span>;
&nbsp; &nbsp; <span class="kw1">return</span> TRUE;
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>This is the delegate method that gets called when the return key is pressed. I used to process the newly-edited text field contents in here. <em>That was a mistake</em> which led to the bug I&#8217;m talking about. In a typical implementation of this method, the only thing you want to do is make the keyboard go away, which is what the <tt>[textField resignFirstResponder]</tt> line does.</p>
<p>Here&#8217;s the method you should implement to deal with new text field contents:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>textFieldDidEndEditing<span class="sy0">:</span><span class="br0">&#40;</span>UITextField<span class="sy0">*</span><span class="br0">&#41;</span>textField
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="co2">// deal with new text field contents here</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>I can&#8217;t show a typical implementation, because only you can decide what you should be doing with the new contents of the text field. But as far as I can tell, this method is <em>always</em> called when the user is finished editing the text field, regardless of why that happened. It could be because the return key was pressed, or because the user switched to a different text field, or because she switched away from the parent view altogether, or perhaps other reasons I&#8217;m not aware of.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/08/28/iphone-keyboard-trouble/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>NSLog() sucks</title>
		<link>http://www.platinumball.net/blog/2009/07/18/nslog-sucks/</link>
		<comments>http://www.platinumball.net/blog/2009/07/18/nslog-sucks/#comments</comments>
		<pubDate>Sat, 18 Jul 2009 14:15:51 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=220</guid>
		<description><![CDATA[In a previous installment I explained why printf() sucks, and how I fixed it. Today I am going to focus on NSLog(), which sucks even worse.
Why NSLog() sucks

Here&#8217;s a typical NSLog() call:
  NSLog(@"hello: %d", 6);
Note that it doesn&#8217;t require a newline character at the end of the format string. So we&#8217;ve made a little [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.platinumball.net/blog/2009/06/23/printf-sucks/">In a previous installment I explained why printf() sucks</a>, and how I fixed it. Today I am going to focus on NSLog(), which sucks even worse.<br />
<h3>Why NSLog() sucks</h3>
<p></p>
<p>Here&#8217;s a typical NSLog() call:</p>
<pre>  NSLog(@"hello: %d", 6);</pre>
<p>Note that it doesn&#8217;t require a newline character at the end of the format string. So we&#8217;ve made a little progress over printf(). It&#8217;s not until you see the output that we get to what I think is wrong with it:</p>
<pre>  2009-07-18 08:48:29.067 nslog_sucks[44201:10b] hello: 6</pre>
<p>Sigh. Just as with printf(), NSLog() is optimized for a corner case I hardly ever need. The assumption is that I would always want to know when this action took place down to a thousandth of a second, and that I&#8217;d want to see the name of the program doing the output, the program&#8217;s PID, and so on. The output I&#8217;m interested in is drowned out by unimportant noise.</p>
<h3>Replacing NSLog() with something better</h3>
<p></p>
<p>This is how NSLog() is defined, in NSObjCRuntime.h:</p>
<pre>  FOUNDATION_EXPORT void NSLog(NSString *format, ...)
   __attribute__((format(__NSString__, 1, 2)));</pre>
<p>At first glance, it appears that this would give you the same sort of warning that you get with printf() if the format string doesn&#8217;t match the arguments supplied. Sadly, I&#8217;ve never been able to coax GCC into supplying warnings in that case. But I added the same __attribute__ decoration to my NSLog() replacement, in case this is just a bug in current versions of GCC that will be fixed at some point in the future.</p>
<p>Finally, here&#8217;s the source code for nlog(), my NSLog() replacement that doesn&#8217;t fill the screen with unnecessary details. The header file, nslog_sucks.h:</p>
<pre>
<div class="codesnip-container" >
<div class="c codesnip" style="font-family:monospace;"><span class="co1">// nslog_sucks.h -- an NSLog() alternative</span>
<span class="co1">// by allen brunson &nbsp;july 18 2009</span>

<span class="co2">#ifndef NSLOG_SUCKS_H</span>
<span class="co2">#define NSLOG_SUCKS_H</span>

<span class="co2">#include &lt;Foundation/Foundation.h&gt;</span>

<span class="co1">// nlog(), a better NSLog()</span>

<span class="kw4">void</span> nlog<span class="br0">&#40;</span>NSString<span class="sy0">*</span> nfmt<span class="sy0">,</span> ...<span class="br0">&#41;</span> __attribute__<span class="br0">&#40;</span><span class="br0">&#40;</span>format<span class="br0">&#40;</span>__NSString__<span class="sy0">,</span> 1<span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>

<span class="co2">#endif &nbsp;// NSLOG_SUCKS_H</span></div>
</div>
</pre>
<p>And the implementation file, nslog_sucks.m:</p>
<pre>
<div class="codesnip-container" >
<div class="c codesnip" style="font-family:monospace;"><span class="co1">// nslog_sucks.m -- an NSLog() alternative</span>
<span class="co1">// by allen brunson &nbsp;july 18 2009</span>

<span class="co2">#include &lt;stdio.h&gt;</span>
<span class="co2">#include &lt;stdlib.h&gt;</span>
<span class="co2">#include &lt;Foundation/Foundation.h&gt;</span>
<span class="co2">#include &quot;nslog_sucks.h&quot;</span>

<span class="kw4">void</span> nlog<span class="br0">&#40;</span>NSString<span class="sy0">*</span> nfmt<span class="sy0">,</span> ...<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; va_list &nbsp; &nbsp;args <span class="sy0">=</span> NULL<span class="sy0">;</span>
&nbsp; &nbsp; NSString<span class="sy0">*</span> &nbsp;nstr <span class="sy0">=</span> nil<span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; va_start<span class="br0">&#40;</span>args<span class="sy0">,</span> nfmt<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; nstr <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>NSString alloc<span class="br0">&#93;</span> initWithFormat<span class="sy0">:</span>nfmt arguments<span class="sy0">:</span>args<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; va_end<span class="br0">&#40;</span>args<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; puts<span class="br0">&#40;</span><span class="br0">&#91;</span>nstr UTF8String<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="br0">&#91;</span>nstr release<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; nstr <span class="sy0">=</span> nil<span class="sy0">;</span>
<span class="br0">&#125;</span>

<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="kw4">int</span> argc<span class="sy0">,</span> <span class="kw4">const</span> <span class="kw4">char</span><span class="sy0">**</span> argv<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; NSAutoreleasePool<span class="sy0">*</span> &nbsp;pool <span class="sy0">=</span> <span class="br0">&#91;</span><span class="br0">&#91;</span>NSAutoreleasePool alloc<span class="br0">&#93;</span> init<span class="br0">&#93;</span><span class="sy0">;</span>

&nbsp; &nbsp; nlog<span class="br0">&#40;</span>@<span class="st0">&quot;hello from nlog: %s %d&quot;</span><span class="sy0">,</span> <span class="st0">&quot;text&quot;</span><span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="br0">&#91;</span>pool release<span class="br0">&#93;</span><span class="sy0">;</span>
&nbsp; &nbsp; pool <span class="sy0">=</span> nil<span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy0">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/07/18/nslog-sucks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Drawing NSStrings in unusual rotations</title>
		<link>http://www.platinumball.net/blog/2009/06/01/drawing-nsstrings-in-unusual-rotations/</link>
		<comments>http://www.platinumball.net/blog/2009/06/01/drawing-nsstrings-in-unusual-rotations/#comments</comments>
		<pubDate>Tue, 02 Jun 2009 02:10:39 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=185</guid>
		<description><![CDATA[If you&#8217;re used to writing apps for desktop computers, the iPhone&#8217;s screen can seem awfully small. You must make creative use of every pixel available to you. One way to do that is to draw some text vertically, rather than horizontally, which I decided to do for an iPhone app I&#8217;m working on right now.
For [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re used to writing apps for desktop computers, the iPhone&#8217;s screen can seem awfully small. You must make creative use of every pixel available to you. <a href="http://www.platinumball.net/hearts/">One way to do that is to draw some text vertically, rather than horizontally, which I decided to do for an iPhone app I&#8217;m working on right now.</a></p>
<p>For drawing normal horizontal text, UIKit has a category called <a href="http://developer.apple.com/iphone/library/documentation/UIKit/Reference/NSString_UIKit_Additions/Reference/Reference.html">UIStringDrawing</a> that provides convenient methods for drawing the contents of an NSString to the current graphics context, like <tt>drawAtPoint:withFont:</tt> and <tt>drawInRect:withFont:</tt>. Sadly, UIKit does not provide methods for drawing text in any other orientation except standard horizontal. I will now present an NSString category you can add to your own iPhone projects that allows you to draw vertical text from bottom to top, top to bottom, or horizontal text upside down.</p>
<p>My category supports the same three <tt>UITextAlignment</tt> options that UIKit provides for left, right, or centered text alignment. If using my <tt>drawInRect:...</tt> method to draw a string that&#8217;s too wide to fit within the rectangle supplied, the right end of the string will be truncated to fit, with an ellipsis character added.</p>
<p>UIKit does a better job of handling long strings than my code does. UIKit can wrap text to two or more lines, for example, which I did not try to emulate. The UIKit methods also allow you to provide a <tt>UILineBreakMode</tt> enum value, which gives you fine-grained control over how strings are truncated. I personally don&#8217;t need that much flexibility, so my category has no such support.</p>
<p>Finally, there is one last limitation of my category that might be a deal-breaker for you. The standard UIKit string-drawing functions can be used to display any Unicode character, so long as the font you&#8217;re using has a glyph for it. My category is limited to the roughly 255 characters present in the MacRoman character set. That means my code is good for displaying text in English and most European languages, like French and German, but it is completely unsuitable for text in, say, Chinese.<br />
<img class="alignright" src="http://www.platinumball.net/blog/graphics/draw_oriented_text.png" alt="" width="189" height="347" /><br />
I&#8217;m aware that this is an outrageous limitation. You&#8217;d be hard-pressed to find a programmer who is more gung ho about Unicode than I am. I struggled mightily for several days trying to find a way around this. Sadly, this is due to the way that the underlying CoreGraphics drawing routines work, and there is no good way around it that I can see. I&#8217;ll cover this in more detail later, in case you&#8217;re interested.</p>
<h3>Using the WBTextDrawing category</h3>
<p>I&#8217;ve included a sample Xcode project that demonstrates the use of my WBTextDrawing category. <a href="http://www.platinumball.net/blog/bin/draw_oriented_text.zip">Download the project by clicking here.</a></p>
<p>I&#8217;ve provided a screen-shot, but it isn&#8217;t much to look at. There are five strings displayed onscreen. The four strings at the edges of the view are displayed with my own WBTextDrawing category, drawn in all four available orientations. The string in the center is drawn with one of UIKit&#8217;s own <tt>drawInRect:...</tt> methods. The lines in red show the bounding rects used to draw the five strings. The four strings around the edges all have an associated green pixel, which illustrates the draw point used to draw that particular string. Naturally you wouldn&#8217;t draw the green and red bits in a real app. I added them to this demo so you&#8217;ll have a better idea of what&#8217;s going on.</p>
<p>Almost all the code in the project is boilerplate that can be safely ignored. To add my string-drawing category to your own program, copy <tt>WBTextDrawing.mm</tt> and <tt>WBTextDrawing.h</tt> out of this project and into your own. All other source files presented here are for demonstration purposes only.<br />
<img alt="" src="http://www.platinumball.net/blog/graphics/draw_point_right.png" class="alignleft" width="245" height="121" /><br />
You will note that <tt>WBTextDrawing.mm</tt> ends with an <tt>mm</tt> extension, rather than the usual <tt>m</tt>. That&#8217;s because this source file <em>must</em> be compiled as Objective-C++, due to the fact that it contains a small amount of C++. I know many Objective-C programmers have a strong aversion to C++, and believe me, I understand! But the underlying CoreGraphics method that&#8217;s used to draw rotated strings insists on being given a <tt>const char*</tt>. It does not work with NSString objects directly. So I chose to convert NSString objects to std::string objects just before drawing them. Yes, I could have accomplished this without leaving the confines of Objective-C, but std::string seems to me like the best tool for the job.</p>
<h3>Specifying text drawing locations</h3>
<p><img alt="" src="http://www.platinumball.net/blog/graphics/draw_point_up.png" class="alignleft" width="121" height="251" /><br />
UIKit&#8217;s UIStringDrawing category contains several <tt>drawAtPoint:...</tt> methods for drawing NSString objects. The point you pass to these methods is the far left end of the font&#8217;s baseline, as illustrated by the green point in the first figure. For the sake of compatibility, I chose to use this same convention for the <tt>drawAtPoint:...</tt> method in my own WBTextDrawing category. No matter what drawing orientation you&#8217;re using, the specified draw point is always the far left end of the font&#8217;s baseline, relative to the string being drawn. This is also the way the low-level CoreGraphics drawing routines work, conveniently enough. See the second figure for what this looks like when drawing a bottom-to-top vertical string.</p>
<p>UIStringDrawing also has several <tt>drawInRect:...</tt> methods. In this case, the rectangle supplied is the entire area allotted for drawing the string, illustrated by the red rectangles in figure one and figure two. Again, my own WBTextDrawing category does the exact same thing, for compatibility&#8217;s sake.</p>
<h3>Text drawn is limited to MacRoman</h3>
<p>This is without a doubt the worst limitation of my WBTextDrawing category. I see no good way around it, however.</p>
<p>Whatever method you use for drawing rotated text, you must accomplish two goals: 1) Apply a given font to the current drawing context, and 2) Draw the NSString supplied by the caller. The easiest way I can see to apply a font is to use <tt>CGContextSelectFont()</tt>. That method gives you two encoding options: <tt>kCGEncodingMacRoman</tt>, which uses the MacRoman encoding, or <tt>kCGEncodingFontSpecific</tt>, which means you must provide your own character-to-glyph translations, as far as I can tell. Ahem. UIKit can&#8217;t do this by itself, apparently, but the expectation is that us lowly app programmers should be able to do it? As if. So the only real option here is to use the MacRoman encoding, then use <tt>CGContextShowText()</tt> to display the text. This is the way my category works. Anything outside the MacRoman character set displays as gibberish.</p>
<p>There&#8217;s another method you can use to apply a font to the current context: <tt>CGContextSetFont()</tt>. This method doesn&#8217;t take any kind of encoding parameter at all, so it would appear to be immune from the problems presented by <tt>CGContextSelectFont()</tt>. Alas, once you&#8217;ve called that method, <tt>CGContextShowText()</tt> doesn&#8217;t work anymore. The CoreGraphics docs say you should instead call <tt>CGContextShowGlyphsAtPoint()</tt>. That function expects its caller to supply an array of <em>glyphs</em>, not characters. Which implies that you&#8217;ve got some method up your sleeve that will convert characters to glyphs for a given encoding. I don&#8217;t know about you, but I don&#8217;t have any such method lying around. So I&#8217;m stuck with boring old MacRoman.</p>
<p>This seems like an awfully strange limitation to build into the low-level CoreGraphics text drawing routines. If you know of any way around it, please tell me what it is, so I can update my text-drawing category appropriately.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/06/01/drawing-nsstrings-in-unusual-rotations/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>cocoa: app memory usage</title>
		<link>http://www.platinumball.net/blog/2009/05/03/cocoa-app-memory-usage/</link>
		<comments>http://www.platinumball.net/blog/2009/05/03/cocoa-app-memory-usage/#comments</comments>
		<pubDate>Mon, 04 May 2009 00:30:06 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=170</guid>
		<description><![CDATA[My least favorite part of Cocoa programming is its reference-counted memory management scheme. If you can exclusively target Mac OS X 10.5 or later, then you can use garbage collection instead, which is better. But it doesn&#8217;t work on Mac OS X 10.4 or earlier or the iPhone, so garbage collection might as well not [...]]]></description>
			<content:encoded><![CDATA[<p>My least favorite part of Cocoa programming is its reference-counted memory management scheme. If you can exclusively target Mac OS X 10.5 or later, then you can use garbage collection instead, which is better. But it doesn&#8217;t work on Mac OS X 10.4 or earlier or the iPhone, so garbage collection might as well not exist, as far as I&#8217;m concerned. Yes, I know Cocoa&#8217;s reference-counting scheme has <a href="http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html">&#8220;only a few simple rules&#8221;</a> you have to follow &#8230; yet Apple&#8217;s own apps tend to leak pretty badly. Back when I was using Mac OS X 10.4, I could only run Safari for a few hours before I had to restart it. Seems to be less of a problem in Mac OS X 10.5, but they&#8217;re likely using garbage collection these days.</p>
<p>So, early versions of your Cocoa programs are probably going to leak. There are ways to combat this. The primary ones are the <tt>leaks</tt> command-line tool and the Instruments app that comes bundled with Xcode, neither of which I like very much. I&#8217;d prefer that the app itself report its bad behavior. To that end, I&#8217;d like my apps to be able to tell how much memory they are using.</p>
<p>Surprisingly, an app&#8217;s memory usage is subject to interpretation. Suppose your app and another are both using one in-memory copy of a shared framework. Should your app&#8217;s memory total include the size of the framework or not? What if your app has a lot of memory allocated that currently lives on disk in a swap file &#8212; should you count <i>that?</i></p>
<p>I&#8217;ve spent some time in the past studying this issue, and I&#8217;ve decided to go with a figure called the &#8220;resident set size.&#8221; This is more-or-less how much memory your app is using. Not perfect, but plenty close enough for my needs. Here&#8217;s how you can get it.
<pre>
<div class="codesnip-container" >
<div class="c codesnip" style="font-family:monospace;"><span class="co2">#include &lt;mach/mach_init.h&gt;</span>
<span class="co2">#include &lt;mach/task.h&gt;</span>
<span class="co2">#include &lt;sys/time.h&gt;</span>
<span class="co2">#include &lt;sys/resource.h&gt;</span>
<span class="co2">#include &lt;stdint.h&gt;</span>
<span class="co2">#include &lt;string.h&gt;</span>
<span class="co2">#include &lt;unistd.h&gt;</span>

int64_t MemoryUsage<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; task_basic_info &nbsp; &nbsp; &nbsp; &nbsp; info<span class="sy0">;</span>
&nbsp; &nbsp; kern_return_t &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rval <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span>
&nbsp; &nbsp; mach_port_t &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; task <span class="sy0">=</span> mach_task_self<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; mach_msg_type_number_t &nbsp;tcnt <span class="sy0">=</span> TASK_BASIC_INFO_COUNT<span class="sy0">;</span>
&nbsp; &nbsp; task_info_t &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tptr <span class="sy0">=</span> <span class="br0">&#40;</span>task_info_t<span class="br0">&#41;</span> <span class="sy0">&amp;</span>info<span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; memset<span class="br0">&#40;</span><span class="sy0">&amp;</span>info<span class="sy0">,</span> 0<span class="sy0">,</span> <span class="kw4">sizeof</span><span class="br0">&#40;</span>info<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; rval <span class="sy0">=</span> task_info<span class="br0">&#40;</span>task<span class="sy0">,</span> TASK_BASIC_INFO<span class="sy0">,</span> tptr<span class="sy0">,</span> <span class="sy0">&amp;</span>tcnt<span class="br0">&#41;</span><span class="sy0">;</span>
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="br0">&#40;</span>rval <span class="sy0">==</span> KERN_SUCCESS<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw1">return</span> <span class="nu0">0</span><span class="sy0">;</span>
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> info.<span class="me1">resident_size</span><span class="sy0">;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>This was difficult to write. It makes use of Darwin kernel APIs, which Google knows almost nothing about.</p>
<p>This works on any version of Mac OS X back to about 10.2, I think. It also works on the iPhone simulator, as well as on actual iPhone hardware. I&#8217;ve tried it myself on all these, including my own phone. The fact that this function works unmodified on both Macs and live iPhone hardware is proof positive that the two platforms use very similar kernels.</p>
<p>If you want to use this to detect leaks, you have to track your apps&#8217; memory usage over time. Take a snapshot of your app&#8217;s size near the beginning of a run, then put your app through its paces for half an hour or so. Is the app&#8217;s memory usage trending up?</p>
<p>In addition to being useful for tracking leaks, I simply appreciate knowing how much memory my apps are using. There&#8217;s a definite upper limit on how much RAM you can allocate on an iPhone, and there&#8217;s no virtual memory at all. If your iPhone app exhausts all physical memory, it can&#8217;t start swapping to disk, it&#8217;ll just get killed.</p>
<p>I&#8217;ve noticed that the app I&#8217;m working on now uses 14MB in the simulator, but only 8MB on real iPhone hardware. Probably because simulator apps are really just modified Mac apps. Windows, views, and other user interface elements on the Mac are no doubt heavier than their iPhone counterparts.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/05/03/cocoa-app-memory-usage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iphone: drawing rectangles</title>
		<link>http://www.platinumball.net/blog/2009/04/28/iphone-drawing-rectangles/</link>
		<comments>http://www.platinumball.net/blog/2009/04/28/iphone-drawing-rectangles/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 15:33:33 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=161</guid>
		<description><![CDATA[Mac/AppKit and iPhone/UIKit development are more alike than different. In general, I&#8217;d say the iPhone APIs feel more &#8220;fresh&#8221; than their Mac equivalents. It seems to me like the current crop of Cocoa engineers at Apple have learned a lot in the years since the company ditched &#8220;classic&#8221; MacOS for an updated version of NextStep, [...]]]></description>
			<content:encoded><![CDATA[<p>Mac/AppKit and iPhone/UIKit development are more alike than different. In general, I&#8217;d say the iPhone APIs feel more &#8220;fresh&#8221; than their Mac equivalents. It seems to me like the current crop of Cocoa engineers at Apple have learned a lot in the years since the company ditched &#8220;classic&#8221; MacOS for an updated version of NextStep, and they&#8217;ve used that wisdom to design this new crop of frameworks. And they&#8217;re not afraid to revisit past decisions that didn&#8217;t work out so well: they discarded MacOSX&#8217;s view-origin-in-the-lower-left-corner mistake and put it in the upper left corner for the iPhone, where it belongs.</p>
<p>On the other hand, AppKit is far more complete than UIKit. Almost anything user-interface-related you might want to do on the Mac is covered by APIs in AppKit.  UIKit is missing many of those amenities, likely because it is targeted at resource-constrained devices that don&#8217;t have the space for dozens of multi-megabyte frameworks. The practical upshot is that I&#8217;ve spent a lot of time writing iPhone stuff that AppKit would have provided for me. All the more reason to write blog posts like this one, so coders can google up the answers rather than spending days reinventing wheels.</p>
<p>I like drawing rectangles. Only rarely do they end up in my final apps, but I use them a lot while debugging, to ensure that a view area I&#8217;ve staked out is where it should be. On the iPhone, this kind of thing is done with <a href="http://developer.apple.com/iphone/library/navigation/Frameworks/Media/CoreGraphics/index.html">Core Graphics</a>. It is a very complete framework. You can do anything with it. The down side is that CG code tends to be verbose and complicated, requiring lots of function calls to do the simplest things. This is a situation crying out for wrapper functions.</p>
<p><img class="alignright" title="rectangle drawing" src="http://www.platinumball.net/blog/graphics/rectangle_drawing.png" alt="" width="116" height="65" />I&#8217;ve written a UIView category that provides methods for drawing just about any type of rectangle you can think of: filled or outlined, rounded corners or square, including point-drawing methods. You can provide a color to draw with, or use the current draw color, which is black, unless you change it. You can draw a translucent rectangle by specifying a draw color that has an alpha value of less than one. You can change the radius of the rounded corners drawn by fiddling with the constant <tt>kCornerSize</tt> at the top of the implementation file.</p>
<p>This is beginner-level stuff, so I guess I should add that UIKit doesn&#8217;t let you draw things whenever you feel like it. (That&#8217;s true for all GUI environments I&#8217;ve ever programmed for, now that I think about it.) You must draw only within a UIView&#8217;s <tt>drawRect:</tt> method. <a href="http://developer.apple.com/iphone/library/referencelibrary/GettingStarted/GS_Graphics_iPhone/index.html">If this is news to you, you should read one of Apple&#8217;s introductory texts before continuing</a>.</p>
<p>Here&#8217;s a sample <tt>drawRect:</tt> method you can add to an existing view to demonstrate the rect-drawing methods:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>drawRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGRect &nbsp;test <span class="sy0">=</span> CGRectMake<span class="br0">&#40;</span>0.0, 0.0, 20.0, 20.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self strokeRect<span class="sy0">:</span>test color<span class="sy0">:</span><span class="br0">&#91;</span>UIColor magentaColor<span class="br0">&#93;</span><span class="br0">&#93;</span>;

&nbsp; &nbsp; test.origin.x <span class="sy0">+=</span> test.size.width;
&nbsp; &nbsp; <span class="br0">&#91;</span>self strokeRoundRect<span class="sy0">:</span>test color<span class="sy0">:</span><span class="br0">&#91;</span>UIColor yellowColor<span class="br0">&#93;</span><span class="br0">&#93;</span>;

&nbsp; &nbsp; test.origin.x <span class="sy0">+=</span> test.size.width;
&nbsp; &nbsp; <span class="br0">&#91;</span>self fillRect<span class="sy0">:</span>test color<span class="sy0">:</span><span class="br0">&#91;</span>UIColor blueColor<span class="br0">&#93;</span><span class="br0">&#93;</span>;

&nbsp; &nbsp; test.origin.x <span class="sy0">+=</span> test.size.width;
&nbsp; &nbsp; <span class="br0">&#91;</span>self fillRoundRect<span class="sy0">:</span>test color<span class="sy0">:</span><span class="br0">&#91;</span>UIColor redColor<span class="br0">&#93;</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>&#8230; which produces the output shown in the screen-shot.  here&#8217;s the header file for the category:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// WBViewRect.h -- rectangle drawing methods for UIView</span>
<span class="co2">// by allen brunson &nbsp;march 2 2009</span>

<span class="co1">#ifndef WBVIEWRECT_H</span>
<span class="co1">#define WBVIEWRECT_H</span>

<span class="co1">#import &lt;UIKit/UIKit.h&gt;</span>

<span class="kw1">@interface</span> UIView <span class="br0">&#40;</span>WBViewRect<span class="br0">&#41;</span>

<span class="co2">// save and restore graphics context</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>contextRestore<span class="sy0">:</span><span class="br0">&#40;</span>CGContextRef<span class="br0">&#41;</span>context;
<span class="sy0">-</span><span class="br0">&#40;</span>CGContextRef<span class="br0">&#41;</span>contextSave;

<span class="co2">// points</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>drawPoint<span class="sy0">:</span><span class="br0">&#40;</span>CGPoint<span class="br0">&#41;</span>point;
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>drawPoint<span class="sy0">:</span><span class="br0">&#40;</span>CGPoint<span class="br0">&#41;</span>point color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color;

<span class="co2">// filled rects</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect;
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color;

<span class="co2">// filled rects with rounded corners</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect;
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color;

<span class="co2">// outlined rects</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect;
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color;

<span class="co2">// outlined rects with rounded corners</span>
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect;
<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color;

<span class="kw1">@end</span>

<span class="co1">#endif &nbsp;// WBVIEWRECT_H</span></div>
</div>
</pre>
<p>Finally, here&#8217;s the implementation file:</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// WBViewRect.mm -- rectangle drawing methods for UIView</span>
<span class="co2">// by allen brunson &nbsp;march 2 2009</span>

<span class="co1">#include &quot;WBViewRect.h&quot;</span>

<span class="co1">#pragma mark module data</span>

<span class="kw4">static</span> <span class="kw4">const</span> CGFloat kCornerSize <span class="sy0">=</span> <span class="nu0">5.0</span>;

<span class="kw4">static</span> CGRect rectStrokeAdjust<span class="br0">&#40;</span>CGRect rect<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; rect <span class="sy0">=</span> CGRectIntegral<span class="br0">&#40;</span>rect<span class="br0">&#41;</span>;

&nbsp; &nbsp; rect.origin.x &nbsp; &nbsp;<span class="sy0">+=</span> <span class="nu0">0.5</span>;
&nbsp; &nbsp; rect.origin.y &nbsp; &nbsp;<span class="sy0">+=</span> <span class="nu0">0.5</span>;
&nbsp; &nbsp; rect.size.width &nbsp;<span class="sy0">-=</span> <span class="nu0">1.0</span>;
&nbsp; &nbsp; rect.size.height <span class="sy0">-=</span> <span class="nu0">1.0</span>;

&nbsp; &nbsp; <span class="kw1">return</span> rect;
<span class="br0">&#125;</span>

<span class="kw4">static</span> <span class="kw4">void</span> roundRect<span class="br0">&#40;</span>CGContextRef context, CGRect rect,
&nbsp;CGFloat ovalWidth, CGFloat ovalHeight<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGFloat &nbsp;fw <span class="sy0">=</span> <span class="nu0">0.0</span>;
&nbsp; &nbsp; CGFloat &nbsp;fh <span class="sy0">=</span> <span class="nu0">0.0</span>;

&nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/assert.html"><span class="kw3">assert</span></a><span class="br0">&#40;</span>ovalWidth &nbsp;&gt;<span class="sy0">=</span> 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/assert.html"><span class="kw3">assert</span></a><span class="br0">&#40;</span>ovalHeight &gt;<span class="sy0">=</span> 1.0<span class="br0">&#41;</span>;

&nbsp; &nbsp; CGContextSaveGState<span class="br0">&#40;</span>context<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>context, CGRectGetMinX<span class="br0">&#40;</span>rect<span class="br0">&#41;</span>, CGRectGetMinY<span class="br0">&#40;</span>rect<span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>context, ovalWidth, ovalHeight<span class="br0">&#41;</span>; 

&nbsp; &nbsp; fw <span class="sy0">=</span> rect.size.width &nbsp;<span class="sy0">/</span> ovalWidth;
&nbsp; &nbsp; fh <span class="sy0">=</span> rect.size.height <span class="sy0">/</span> ovalHeight; 

&nbsp; &nbsp; CGContextMoveToPoint<span class="br0">&#40;</span>context, fw, fh <span class="sy0">/</span> 2.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextAddArcToPoint<span class="br0">&#40;</span>context, fw, fh, fw <span class="sy0">/</span> 2.0, fh, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextAddArcToPoint<span class="br0">&#40;</span>context, 0.0, fh, 0, fh <span class="sy0">/</span> 2.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextAddArcToPoint<span class="br0">&#40;</span>context, 0.0, 0.0, fw <span class="sy0">/</span> 2.0, 0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextAddArcToPoint<span class="br0">&#40;</span>context, fw, 0.0, fw, fh <span class="sy0">/</span> 2.0, 1.0<span class="br0">&#41;</span>; 

&nbsp; &nbsp; CGContextClosePath<span class="br0">&#40;</span>context<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextRestoreGState<span class="br0">&#40;</span>context<span class="br0">&#41;</span>;
<span class="br0">&#125;</span>

<span class="kw1">@implementation</span> UIView <span class="br0">&#40;</span>WBRectView<span class="br0">&#41;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>contextRestore<span class="sy0">:</span><span class="br0">&#40;</span>CGContextRef<span class="br0">&#41;</span>context
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRestoreGState<span class="br0">&#40;</span>context<span class="br0">&#41;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>CGContextRef<span class="br0">&#41;</span>contextSave
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> UIGraphicsGetCurrentContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; CGContextSaveGState<span class="br0">&#40;</span>ctxt<span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">return</span> ctxt;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>drawPoint<span class="sy0">:</span><span class="br0">&#40;</span>CGPoint<span class="br0">&#41;</span>point
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>self drawPoint<span class="sy0">:</span>point color<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>drawPoint<span class="sy0">:</span><span class="br0">&#40;</span>CGPoint<span class="br0">&#41;</span>point color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGRect &nbsp;rect <span class="sy0">=</span> CGRectMake<span class="br0">&#40;</span>point.x, point.y, 1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self fillRect<span class="sy0">:</span>rect color<span class="sy0">:</span>color<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>self fillRect<span class="sy0">:</span>rect color<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> <span class="br0">&#91;</span>self contextSave<span class="br0">&#93;</span>;

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>color<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextSetFillColorWithColor<span class="br0">&#40;</span>ctxt, <span class="br0">&#91;</span>color CGColor<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp;

&nbsp; &nbsp; UIRectFill<span class="br0">&#40;</span>rect<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self contextRestore<span class="sy0">:</span>ctxt<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>self fillRoundRect<span class="sy0">:</span>rect color<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>fillRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> <span class="br0">&#91;</span>self contextSave<span class="br0">&#93;</span>;

&nbsp; &nbsp; roundRect<span class="br0">&#40;</span>ctxt, rect, kCornerSize, kCornerSize<span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>color<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextSetFillColorWithColor<span class="br0">&#40;</span>ctxt, <span class="br0">&#91;</span>color CGColor<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp;

&nbsp; &nbsp; CGContextFillPath<span class="br0">&#40;</span>ctxt<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self contextRestore<span class="sy0">:</span>ctxt<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>self strokeRect<span class="sy0">:</span>rect color<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> <span class="br0">&#91;</span>self contextSave<span class="br0">&#93;</span>;

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>color<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextSetStrokeColorWithColor<span class="br0">&#40;</span>ctxt, <span class="br0">&#91;</span>color CGColor<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp;

&nbsp; &nbsp; UIRectFrame<span class="br0">&#40;</span>rect<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self contextRestore<span class="sy0">:</span>ctxt<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="br0">&#91;</span>self strokeRoundRect<span class="sy0">:</span>rect color<span class="sy0">:</span><span class="kw2">nil</span><span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="sy0">-</span><span class="br0">&#40;</span><span class="kw4">void</span><span class="br0">&#41;</span>strokeRoundRect<span class="sy0">:</span><span class="br0">&#40;</span>CGRect<span class="br0">&#41;</span>rect color<span class="sy0">:</span><span class="br0">&#40;</span>UIColor<span class="sy0">*</span><span class="br0">&#41;</span>color
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGContextRef &nbsp;ctxt <span class="sy0">=</span> <span class="br0">&#91;</span>self contextSave<span class="br0">&#93;</span>;

&nbsp; &nbsp; rect <span class="sy0">=</span> rectStrokeAdjust<span class="br0">&#40;</span>rect<span class="br0">&#41;</span>;
&nbsp; &nbsp; roundRect<span class="br0">&#40;</span>ctxt, rect, kCornerSize, kCornerSize<span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>color<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextSetStrokeColorWithColor<span class="br0">&#40;</span>ctxt, <span class="br0">&#91;</span>color CGColor<span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span> &nbsp; &nbsp;

&nbsp; &nbsp; CGContextStrokePath<span class="br0">&#40;</span>ctxt<span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#91;</span>self contextRestore<span class="sy0">:</span>ctxt<span class="br0">&#93;</span>;
<span class="br0">&#125;</span>

<span class="kw1">@end</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/04/28/iphone-drawing-rectangles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone: UITextField and the virtual keyboard, part II</title>
		<link>http://www.platinumball.net/blog/2009/04/20/iphone-uitextfield-and-the-virtual-keyboard-part-ii/</link>
		<comments>http://www.platinumball.net/blog/2009/04/20/iphone-uitextfield-and-the-virtual-keyboard-part-ii/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 02:42:46 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=152</guid>
		<description><![CDATA[I&#8217;ve written about this subject before, but I didn&#8217;t do a very good job. Many weeks of intensive iPhone programming later, I am ready to deliver my definitive treatise on this subject.
The Problem
Say you&#8217;ve got a UITextField that you want the user to type something into. It&#8217;s located near the bottom of the screen. The [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.platinumball.net/blog/2009/03/05/iphone-using-uitextfield-with-the-virtual-keyboard/">I&#8217;ve written about this subject before</a>, but I didn&#8217;t do a very good job. Many weeks of intensive iPhone programming later, I am ready to deliver my definitive treatise on this subject.</p>
<h3>The Problem</h3>
<p>Say you&#8217;ve got a UITextField that you want the user to type something into. It&#8217;s located near the bottom of the screen. The user touches the control to begin editing. The virtual keyboard pops up, which completely covers the UITextField. It is now impossible for the user to see what she&#8217;s typing. You have to write your own custom code to move the text field out of the way before the keyboard pops up, so the user can see it.</p>
<p>This is against the spirit of Cocoa. AppKit on the Mac and UIKit on the iPhone normally give you decent behavior by default, and lots of hooks you can use for customization, if the defaults don&#8217;t suit your situation. In this case, they gave us a big problem by default and very little guidance towards solving it. Apple&#8217;s own example code does not do a good job with this. What we&#8217;re left with is lots of blog authors like me writing half-baked solutions to partial subsets of the problem, whereas Apple could have solved all of it, easily. Disappointing.</p>
<div class="wp-caption alignright" style="width: 189px"><img title="keyboardscroll screen-shot" src="http://www.platinumball.net/blog/graphics/article_keyboardscroll.png" alt="keyboardscroll screen-shot" width="179" height="324" /><p class="wp-caption-text">keyboardscroll screen-shot</p></div>
<p>Having lived with this for awhile, I thought about how best to write something definitive, so I don&#8217;t have to keep tripping over this issue again and again. The solutions I&#8217;ve seen on programming forums and blogs involve code snippets you can drop into an existing view controller, but you have to do so every time you write a new view that contains text fields. The height of cut-and-paste code reuse.</p>
<p>My first idea was to add a category to UIViewController. Then every new view controller I write from now on would get textfield-handling ability &#8220;for free.&#8221; But Apple has already solved this problem for the UITableView object with special code inside UITableViewController, as of iPhone OS version 2.2. It&#8217;s not right to apply my fix to <em>every</em> view controller if some don&#8217;t need it. So instead I implemented a descendant of UIViewController, which can be derived from to create new view controllers.</p>
<h3>The Solution</h3>
<p>My keyboardscroll Xcode project shows you two ways you can solve this problem. If you&#8217;re using a UITableView, the issue is solved for you by UITableViewController, if you get all the connections right. I&#8217;ve included a table view controller that works this way, because it was harder than I thought it would be. My first attempt failed miserably. If you&#8217;re using some other view type, you can write a new view controller descended from my own WBKeyboardViewController class, which the example project shows you how to do.</p>
<p>My view controller works for views that contain any number of UITextFields. The content view can be a UIView or UIScrollView, either works fine. Both portrait and landscape modes are fully supported.</p>
<p>The only serious limitation is that my code doesn&#8217;t cope with UITextViews, which the user can also type into, and are subject to the same problem. I don&#8217;t have enough experience with text views to have a good idea about how to approach that problem yet. My first guess is that my view controller could be made to deal with them fairly easily, with a few special cases here and there.</p>
<p>To the greatest extent possible, I&#8217;ve avoided hard-coding pixel counts. For example, the portrait mode virtual keyboard is 216 pixels tall, and the landscape one is 162 &#8212; but those two numeric constants do not appear anywhere in the code. The proper values to use are retrieved from the operating system. Apple&#8217;s own UICatalog sample project hard-codes the height of the keyboard, so I didn&#8217;t discover that there is a better way until I had been searching for articles about this for some time.</p>
<p>Hard-coded pixel counts are not just a theoretical concern. <a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariWebContent/DesigningForms/chapter_6_section_2.html">&#8220;In iPhone OS 1.1.4 and earlier, the keyboard height in landscape orientation was 180 pixels.&#8221;</a> Straight from Apple&#8217;s own documentation. Of course, that was from before the iPhone SDK existed. I think they&#8217;d be reluctant to make such a change today, since it would break so many third-party apps. Better safe than sorry, though.</p>
<p>There are 40 total UITextFields in my example project spread over two views, and they always, <em>always</em> get out of the way before the keyboard appears. I&#8217;ve tested this code thoroughly in the simulator. I&#8217;ll be using it on a real iPhone soon, so if there are issues in that scenario, I&#8217;ll find them and update this blog post. There are no bugs that I&#8217;m aware of. If you find one, I&#8217;d love to hear about it, so I can fix it.</p>
<h3>Landscape Mode is the Devil&#8217;s Own Handiwork</h3>
<p>Whew, this was <em>way</em> more complicated than I thought it would be. Apple chose to implement the landscape modes far differently than I would have. I say &#8220;modes&#8221; rather than &#8220;mode,&#8221; because there are two of them. The iPhone&#8217;s user interface can be rotated to one of four orientations: portrait, landscape, portrait upside down, and landscape upside down.</p>
<p>When your view rotates into landscape mode, almost all of UIKit remains stuck in portrait mode. That means you have to write lots of special cases. Here&#8217;s the first example. This code snippet gets you the bounds rect of the iPhone&#8217;s screen:</p>
<p>    <tt>CGRect rect = [[UIScreen mainScreen] bounds];</tt></p>
<p>In portrait mode, the rect returned has a height of 480 pixels and a width of 320, which is correct. In landscape mode, the rect returned is exactly the same as the one you get in portrait mode. Erm. Okay, it&#8217;s easy enough to write a wrapper function that swaps the rect&#8217;s width and height when appropriate, which I did.</p>
<p>Next problem. UIView contains methods for converting rects and points from the coordinate system of one view into another, <tt>convertRect:toView:</tt> being one of them. I&#8217;ve successfully used those methods in portrait modes, but not in landscape modes. It appears to me that, while your view is in landscape mode, the main window remains in portrait mode, so translations between the two are nonsensical. I couldn&#8217;t make it work, anyway. Could be because they&#8217;re weird in the way I just described, or it could be because I don&#8217;t know what I&#8217;m doing. Either way, I had to abandon UIView&#8217;s conversion methods and roll my own.</p>
<p>The next problem I ran into indicates the UIKit&#8217;s designers&#8217; intent quite strongly. UIApplication has a property called statusBarFrame. Normally I wouldn&#8217;t need to know the size of the status bar, but I was forced to roll my own coordinate conversion methods, remember. In portrait mode, the property returns a width of 320 pixels and a height of 20 pixels, which is correct. In landscape mode, it says the status bar is 20 pixels wide and 480 pixels tall! That&#8217;s obviously wrong, from the perspective of your landscape-mode view. It would be correct only from the perspective of a parent view that&#8217;s still in portrait mode. Yet another special case I had to write for the landscape modes.</p>
<p>It took me three days to get my view controller working right, despite the fact that it is only around 250 lines of code. Largely because I have come to trust that UIKit will Do The Right Thing in almost every case, so I could barely conceive of the idea that it would ever tell me that the status bar is 480 pixels tall with a straight face. Not at all what I was expecting, so I had to abandon a lot of early code and rethink my assumptions.</p>
<p>Here&#8217;s the code: <a href="http://www.platinumball.net/zip/keyboardscroll.zip">keyboardscroll.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/04/20/iphone-uitextfield-and-the-virtual-keyboard-part-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iPhone: UIImage rotation and mirroring</title>
		<link>http://www.platinumball.net/blog/2009/03/30/iphone-uiimage-rotation-and-mirroring/</link>
		<comments>http://www.platinumball.net/blog/2009/03/30/iphone-uiimage-rotation-and-mirroring/#comments</comments>
		<pubDate>Mon, 30 Mar 2009 08:19:14 +0000</pubDate>
		<dc:creator>allen</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.platinumball.net/blog/?p=127</guid>
		<description><![CDATA[Update: This post has been superseded. Please go read this instead: UIImage rotation and scaling.
My access logs show that you webbernauts like my iPhone articles better than anything else on this site. Very well then, here&#8217;s another one.
I recently found myself with a need to rotate the contents of a UIImage 90 degrees to the [...]]]></description>
			<content:encoded><![CDATA[<p>Update: This post has been superseded. Please go read this instead: <a href="http://www.platinumball.net/blog/2010/01/31/iphone-uiimage-rotation-and-scaling/">UIImage rotation and scaling</a>.</p>
<p>My access logs show that you webbernauts like my iPhone articles better than anything else on this site. Very well then, here&#8217;s another one.</p>
<p>I recently found myself with a need to rotate the contents of a UIImage 90 degrees to the right or left and then display it. Apparently this is easy if your image is inside a UIImageView and you&#8217;re willing to rotate the whole view, but that&#8217;s not what I have in mind. Rotating the UIImage itself turns out to be pretty danged complicated, and requires a great deal of math. I suck at math.</p>
<p><a href="http://blog.logichigh.com/2008/06/05/uiimage-fix/">Fortunately for me, the code given in this guy&#8217;s blog post tackles 95 percent of the problem, and 100 percent of the math</a>. Heh! It&#8217;s not <i>quite</i> what I want, however. The function given in that blog post queries the EXIF data inside the image and rotates it based on that. I want the method&#8217;s caller to be able to specify what type of rotation should be done. I tinkered with the code for awhile and got exactly what I wanted.</p>
<p>The original blog post&#8217;s code was written as a standalone C function. I wrote my version as a category attached to UIImage. Say you&#8217;ve got a UIImage you want to rotate 90 degrees left. It&#8217;s done like this:</p>
<p> &nbsp; &nbsp; <tt>newImage = [oldImage rotate:UIImageOrientationLeft];</tt></p>
<p><tt>newImage</tt> will be a newly-created copy of <tt>oldImage</tt>, rotated 90 degrees left. Other options include <tt>UIImageOrientationRight</tt>, <tt>UIImageOrientationDown</tt> (for a new image that&#8217;s an upside-down copy of the original), and so on. There are also &#8220;mirrored&#8221; variants, which both rotate the image and mirror its contents left-to-right.</p>
<p>In the process of getting it to work the way I wanted, I made a bunch of changes to the code. I reformatted it so that the lines are no longer than 78 characters. (One of these days I&#8217;m going to write a blog post about why I think that&#8217;s a good thing.) The original function had two or more unnecessary copies of some data and superfluous calls to external functions, which I eliminated. The old code trimmed the size of the original image if it was bigger than a certain size, which I eliminated. The original had several copies of an identical clause for swapping the width and height of a CGRect, which I refactored into a separate helper function. There are other changes as well, but I&#8217;ll spare you the details.</p>
<p>Okay, one more change that I&#8217;m going to document. I am 85 percent sure that the original code has a bug. It does not work properly when the input orientation is <tt>UIImageOrientationLeftMirrored</tt> or <tt>UIImageOrientationRightMirrored</tt>. The new image gets partially chopped off along one edge, which I fixed. It could be that it was not a bug in the context where the original code was being used, but it definitely is in this new context. I&#8217;ve tested all orientations in the iPhone simulator, and they all work.</p>
<p>First, here&#8217;s UKImage.h, which defines the category.</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// UKImage.h -- extra UIImage methods</span>
<span class="co2">// by allen brunson &nbsp;march 29 2009</span>

<span class="co1">#ifndef UKIMAGE_H</span>
<span class="co1">#define UKIMAGE_H</span>

<span class="co1">#import &lt;UIKit/UIKit.h&gt;</span>

<span class="kw1">@interface</span> UIImage <span class="br0">&#40;</span>UKImage<span class="br0">&#41;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotate<span class="sy0">:</span><span class="br0">&#40;</span>UIImageOrientation<span class="br0">&#41;</span>orient;

<span class="kw1">@end</span>

<span class="co1">#endif &nbsp;// UKIMAGE_H</span></div>
</div>
</pre>
<p>Now here&#8217;s UKImage.mm, which defines the <tt>rotate:</tt> method.  You can rename this file to UKImage.m if you never use any C++ constructs in your code.</p>
<pre>
<div class="codesnip-container" >
<div class="objc codesnip" style="font-family:monospace;"><span class="co2">// UKImage.mm -- extra UIImage methods</span>
<span class="co2">// by allen brunson &nbsp;march 29 2009</span>
<span class="co2">// based on original code by Kevin Lohman:</span>
<span class="co2">// http://blog.logichigh.com/2008/06/05/uiimage-fix/</span>

<span class="co1">#include &quot;UKImage.h&quot;</span>

<span class="kw4">static</span> CGRect swapWidthAndHeight<span class="br0">&#40;</span>CGRect rect<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGFloat &nbsp;swap <span class="sy0">=</span> rect.size.width;
&nbsp; &nbsp; 
&nbsp; &nbsp; rect.size.width &nbsp;<span class="sy0">=</span> rect.size.height;
&nbsp; &nbsp; rect.size.height <span class="sy0">=</span> swap;
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">return</span> rect;
<span class="br0">&#125;</span>

<span class="kw1">@implementation</span> UIImage <span class="br0">&#40;</span>UKImage<span class="br0">&#41;</span>

<span class="sy0">-</span><span class="br0">&#40;</span>UIImage<span class="sy0">*</span><span class="br0">&#41;</span>rotate<span class="sy0">:</span><span class="br0">&#40;</span>UIImageOrientation<span class="br0">&#41;</span>orient
<span class="br0">&#123;</span>
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; UIImage<span class="sy0">*</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; copy <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGContextRef &nbsp; &nbsp; &nbsp; ctxt <span class="sy0">=</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; CGImageRef &nbsp; &nbsp; &nbsp; &nbsp; imag <span class="sy0">=</span> self.CGImage;
&nbsp; &nbsp; CGRect &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rect <span class="sy0">=</span> CGRectZero;
&nbsp; &nbsp; CGAffineTransform &nbsp;tran <span class="sy0">=</span> CGAffineTransformIdentity;

&nbsp; &nbsp; rect.size.width &nbsp;<span class="sy0">=</span> CGImageGetWidth<span class="br0">&#40;</span>imag<span class="br0">&#41;</span>;
&nbsp; &nbsp; rect.size.height <span class="sy0">=</span> CGImageGetHeight<span class="br0">&#40;</span>imag<span class="br0">&#41;</span>;
&nbsp; &nbsp; 
&nbsp; &nbsp; bnds <span class="sy0">=</span> rect;
&nbsp; &nbsp; 
&nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span>orient<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationUp<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">// would get you an exact copy of the original</span>
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/assert.html"><span class="kw3">assert</span></a><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationUpMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.width, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationDown<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.width,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, M_PI<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationDownMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>0.0, rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, 1.0, <span class="sy0">-</span>1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeft<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>0.0, rect.size.width<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, 3.0 <span class="sy0">*</span> M_PI <span class="sy0">/</span> 2.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeftMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.height,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;rect.size.width<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformScale<span class="br0">&#40;</span>tran, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, 3.0 <span class="sy0">*</span> M_PI <span class="sy0">/</span> 2.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRight<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeTranslation<span class="br0">&#40;</span>rect.size.height, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, M_PI <span class="sy0">/</span> 2.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRightMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; bnds <span class="sy0">=</span> swapWidthAndHeight<span class="br0">&#40;</span>bnds<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformMakeScale<span class="br0">&#40;</span><span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; tran <span class="sy0">=</span> CGAffineTransformRotate<span class="br0">&#40;</span>tran, M_PI <span class="sy0">/</span> 2.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="co2">// orientation value supplied is invalid</span>
&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.opengroup.org/onlinepubs/009695399/functions/assert.html"><span class="kw3">assert</span></a><span class="br0">&#40;</span><span class="kw2">false</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">nil</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; UIGraphicsBeginImageContext<span class="br0">&#40;</span>bnds.size<span class="br0">&#41;</span>;
&nbsp; &nbsp; ctxt <span class="sy0">=</span> UIGraphicsGetCurrentContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span>orient<span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeft<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationLeftMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRight<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> UIImageOrientationRightMirrored<span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>ctxt, <span class="sy0">-</span>1.0, 1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>ctxt, <span class="sy0">-</span>rect.size.height, 0.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;
&nbsp; &nbsp; &nbsp; &nbsp; 
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span>
&nbsp; &nbsp; &nbsp; &nbsp; CGContextScaleCTM<span class="br0">&#40;</span>ctxt, 1.0, <span class="sy0">-</span>1.0<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; CGContextTranslateCTM<span class="br0">&#40;</span>ctxt, 0.0, <span class="sy0">-</span>rect.size.height<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">break</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; CGContextConcatCTM<span class="br0">&#40;</span>ctxt, tran<span class="br0">&#41;</span>;
&nbsp; &nbsp; CGContextDrawImage<span class="br0">&#40;</span>UIGraphicsGetCurrentContext<span class="br0">&#40;</span><span class="br0">&#41;</span>, rect, imag<span class="br0">&#41;</span>;
&nbsp; &nbsp; 
&nbsp; &nbsp; copy <span class="sy0">=</span> UIGraphicsGetImageFromCurrentImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; UIGraphicsEndImageContext<span class="br0">&#40;</span><span class="br0">&#41;</span>;

&nbsp; &nbsp; <span class="kw1">return</span> copy;
<span class="br0">&#125;</span>

<span class="kw1">@end</span></div>
</div>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.platinumball.net/blog/2009/03/30/iphone-uiimage-rotation-and-mirroring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
