<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Cocoaphony</title>
	
	<link>http://robnapier.net/blog</link>
	<description>Mac and iPhone, on the brain</description>
	<lastBuildDate>Sun, 13 May 2012 00:11:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Cocoaphony" /><feedburner:info uri="cocoaphony" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Wrapping C++ Final Edition</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/nuq7S1NoyxY/wrapping-cppfinal-edition-759</link>
		<comments>http://robnapier.net/blog/wrapping-cppfinal-edition-759#comments</comments>
		<pubDate>Sun, 13 May 2012 00:11:45 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=759</guid>
		<description><![CDATA[Wrapping C++ for use by ObjC used to be somewhat complicated, especially if the C++ include namespaces or templates. Changes in ObjC have now made it nearly trivial. In my (hopefully) final installment on the subject, I lay out just how easy it is now.]]></description>
			<content:encoded><![CDATA[<p>I have always strong recommended segregating Objective-C and C++ code with a thin Objective-C++ wrapper. I do not like Objective-C++. It is useful for what it does, but it is a mess of a &#8220;language.&#8221; It has many downsides, for slower compiles and poor debugging facilities, to confusing code and inefficient ARC code. <code>.mm</code> is a blight on your code. Never let it spread.</p>

<p>That said, Objective-C++ is invaluable for integrating C++ into Objective-C. And while I am not a great lover of C++, it is a very useful language and there is a great deal of excellent code written in it that is well-worth reusing in your Cocoa projects. Many of Apple&#8217;s frameworks are implemented in C++.</p>

<p>So my recommendation for those who have existing C++ logic code has always been thus: write your UI in pure Objective-C (.m). Write your &#8220;middleware&#8221; in pure C++ (.cpp). And have a thin Objective-C++ (.mm) wrapper layer to glue them together. Your ObjC++ API should ideally exactly match your C++ API, just converting types (for instance converting std::string to and from NSString).</p>

<p>(As a side note, I also recommend that OS-related things like file management, network management, and threading all be handled natively. GCD is much better than pthreads. NSURLConnection is much better than writing your own C++ networking layer in BSD sockets. But this is tangental to the main point.)</p>

<p>Saying all that, how do you wrap a C++ object so that Objective-C can read it? This used to be a question that required some significant thought. See <a href="http://robnapier.net/blog/wrapping-c-take-2-1-486">Wrapping C++, Take 2 Part 1</a> and <a href="http://robnapier.net/blog/wrapping-c-take-2-2-493">Part 2</a> for my previous thinking on the subject.</p>

<p>Improvements in Objective-C have made all of the previous hoop-jumping irrelevant. The problem all my previous solutions was trying to solve was that you had to declare ivars in the header. Your ivar was a C++ class (which might be in a namespace or might be a template), and that made it difficult to declare in the header without forcing all the importers to be ObjC++. So to solve this generally you needed opaque types, or at the very least forward declared structs, etc. And it was all a big pain.</p>

<p>But that&#8217;s over. You can now declare all your ivars in the implementation file. So everything&#8217;s easy. Your wrapper class can have C++ ivars without having any impact on users of the wrapper class.</p>

<p>Consider a simple C++ class (but throwing in the headache of a namespace):</p>

<pre><code>namespace MY {
class Cpp {
  public:
    std::string getName() { return _name; };
    void setName(std::string aName) { _name = aName; };
  private:
    std::string _name;
};
}
</code></pre>

<p>The wrapper for this is trivial:</p>

<pre><code>@interface CPPWrapper : NSObject
@property (nonatomic, readwrite, copy) NSString *name;
@end

@interface CPPWrapper ()
@property (nonatomic, readwrite, assign) MY::Cpp *cpp;
@end

@implementation CPPWrapper
@synthesize cpp = _cpp;

- (id)init {
  self = [super init];
  if (self) {
    _cpp = new MY::Cpp();
  }
  return self;
}

- (void)dealloc {
  delete _cpp;
}

- (NSString *)name {
  return [NSString stringWithUTF8String:self.cpp-&gt;getName().c_str()];
}

- (void)setName:(NSString *)aName {
  self.cpp-&gt;setName([aName UTF8String]);
}
@end
</code></pre>

<p>Couldn&#8217;t be easier really. The one headache that really remains in my experience is enums inside of a namespace (or more generally enums declared in a C++ header). The best solution is to use <code>#if __cplusplus</code> blocks to strip away the namespace and still declare the enum in pure C. Do this if at all possible. Otherwise you&#8217;ll wind up with an C enum that mirrors the C++ enum. This is a maintenance nightmare, since changes to the C++ enum will often be missed in the ObjC enum, and you&#8217;ll get very difficult-to-debug errors with enum mismatches.</p>

<p>Just to ask and answer a possible question: why <code>*Cpp</code> and not just <code>Cpp</code>? The reason is that in almost all cases the C++ object will be created outside of your wrappers. So in almost all cases, there&#8217;s going to be a method like <code>initWithCpp:(Cpp *)cpp</code>. How does that work? Easy, wrap it in <code>#if __cplusplus</code>:</p>

<pre><code>#if __cplusplus
#include "Cpp.h"
...
- (CppWrapper *)initWithCpp:(Cpp *)cpp;
#endif
</code></pre>

<p>Anyway, most of my research into opaque types and generally how to manage C++ wrappers has now become trivial. I&#8217;m just giving one more post to let you all know that. (And because <a href="http://robnapier.net/blog/wrapping-c-take-2-1-486#comment-15967">Orpheus</a> asked.) Post comments if there are more questions.</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/nuq7S1NoyxY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/wrapping-cppfinal-edition-759/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/wrapping-cppfinal-edition-759</feedburner:origLink></item>
		<item>
		<title>Github and its pricing</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/pea1lzcXtcU/github-pricing-754</link>
		<comments>http://robnapier.net/blog/github-pricing-754#comments</comments>
		<pubDate>Sat, 31 Mar 2012 02:48:49 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[github]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=754</guid>
		<description><![CDATA[I&#8217;ve been looking into better ways to host my repositories for clients, manage task lists, documents, etc. I like github. It&#8217;s a good interface. It works. I could use a few more features in the Issues module, but it&#8217;s nice that they keep it simple. I&#8217;ve tried BitBucket and Assembla, and looked at several others. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been looking into better ways to host my repositories for clients, manage task lists, documents, etc. I like github. It&#8217;s a good interface. It works. I could use a few more features in the Issues module, but it&#8217;s nice that they keep it simple. I&#8217;ve tried BitBucket and Assembla, and looked at several others. I&#8217;ve managed my own servers. In every test, github wins.</p>

<p>Except for price. github is often the most expensive. Especially if you need what I need, which is several small repositories, each with a small number of collaborators (often just one or two). But just a few of those can push you into the Medium plan, or even into the Bronze plan.<span id="more-754"></span>So I was complaining about this to my wife. I say &#8220;Wife, github is just too expensive. Why do they have to be like that? I really like using them.&#8221;</p>

<p>&#8220;Oh,&#8221; says Wife. &#8220;What are we talking about?&#8221;</p>

<p>&#8220;Well,&#8221; I say, &#8220;it could easily be $25/month.&#8221;</p>

<p>&#8220;$300/year?&#8221;</p>

<p>&#8220;Yeah.&#8221;</p>

<p>&#8220;And it works really well? And makes business go more smoothly?&#8221;</p>

<p>&#8220;Yeah&#8230;?&#8221;</p>

<p>&#8220;And you need some service for this, right?&#8221;</p>

<p>&#8220;One way or another.&#8221;</p>

<p>&#8220;Get over yourself. Pay them.&#8221;</p>

<p>And I started to think about it. If I&#8217;d billed the time I&#8217;d already spent researching and designing scripts to work around issues, I&#8217;d probably have covered a year or two of service.</p>

<p>Some services have gotten so cheap, you get used to what you think they &#8220;should&#8221; cost. I remember haggling in markets in Shanghai and friends saying &#8220;Rob, you&#8217;re buying a scarf for $2 and you&#8217;re haggling over the last 50 cents.&#8221; My attitude was, yeah, but in Shanghai that scarf should be 8 RMB and she&#8217;s asking 14. At home I&#8217;d think nothing of paying $10, but in Shanghai I feel ripped off paying more than a buck. The whole Internet is a Shanghai market sometimes.</p>

<p>Quality is worth paying for. As a developer, I expect to be paid for the quality code I write. Time to pay others for theirs.</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/pea1lzcXtcU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/github-pricing-754/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/github-pricing-754</feedburner:origLink></item>
		<item>
		<title>Some math behind “contribution != compensation”</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/hDkflI36qcA/contribution-vs-compensation-748</link>
		<comments>http://robnapier.net/blog/contribution-vs-compensation-748#comments</comments>
		<pubDate>Sat, 24 Mar 2012 22:16:32 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[Software Development]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=748</guid>
		<description><![CDATA[There is a suggestion that the apparent gap between pay and productivity is due to some kind of inefficiency in the system, whether it be an inability to measure productivity or companies intentionally ignoring that value. I argue, based on economics]]></description>
			<content:encoded><![CDATA[<p>Thanks to @codinghorror, I recently read a blog post from Steve McConnell called <a href="http://blogs.construx.com/blogs/stevemcc/archive/2011/01/22/10x-productivity-myths-where-s-the-10x-difference-in-compensation.aspx">10x Productivity Myths: Where’s the 10x Difference in Compensation?</a> Steve quotes a question from Pete McBreen:</p>

<blockquote>&#8220;One point in his article that McConnell did not address&#8211;<strong>programmer compensation does not vary accordingly.</strong> This is a telling point&#8211;if the difference is productivity can be 10X, why is it that salaries rarely fall outside the 2X range for experienced developers?&#8221; [emphasis in original]</blockquote>

<p>He then provides some fairly satisfying answers. &#8220;The other guy is actually overpaid.&#8221; &#8220;You&#8217;re confusing coding with actual business value.&#8221; &#8220;Companies pay the least they can get away with.&#8221; etc. All his answers make good, intuitive sense. Unfortunately, despite being a longtime fan of Steve McConnell&#8217;s work, I believe most are irrelevant or incorrect.
<span id="more-748"></span></p>

<p>Let me state this a little more concretely. If a company pays Alice $X, but Alice generates $10X in marginal value, then there is a very strong incentive for another company to offer Alice $2X and receive $9X in marginal value. Alice would almost certainly accept $2X, and a competitor would be idiotic not to pay it. As long as Alice were free to change employers at will, and as long as employers were capable of determining Alice&#8217;s value in even a vague way, this would naturally continue until there were little marginal value left (less than the friction of recruiting and moving and within the precision of determining Alice&#8217;s productivity). That is to say, there should not be much money left on the table. In the normal version of this story, there is a massive amount of money on the table. It&#8217;s hard to believe this continues indefinitely in a highly competitive, unregulated, and mobile industry like ours.</p>

<p>Arguing that it&#8217;s impossible to measure Alice&#8217;s productivity to any precision makes the entire discussion moot, since it eliminates the ability to say that Alice is 10x more productive. How did you decide that if productivity is unmeasurable? Even intuitive measurements would be sufficient to create a bidding war if there were really 10x value on the table.</p>

<p>It also seems unworkable that a company would continue to pay large numbers of people dramatically above their total contribution. Sure, here and there; large companies are quite inefficient in my experience. And at the executive level, I believe there is enough collusion between compensation committees and CEOs to make the system significantly inefficient. But almost any argument for this being systemic suggests that companies are highly altruistic. It&#8217;s hard to believe that a greedy company would hold onto a significant number of low-level employees that would be cheaper to fire and replace with no one.</p>

<p>I suggest that there&#8217;s another answer that doesn&#8217;t require long-lived massive inefficiencies in the market. I suggest that Alice is being paid in another way and that our &#8220;loser&#8221; employee provides some other value. I&#8217;m further claiming that the value Loser provides is reasonably close to the money that Alice foregoes. In other words, Alice is paying Loser for his service, and thus a reasonably efficient economic system in equilibrium is restored. I&#8217;m not claiming to have created this idea. It&#8217;s directly from R. H. Frank&#8217;s <a href="http://www.jstor.org/stable/1805123">&#8220;Are Workers Paid their Marginal Products?&#8221;</a> where it is examined in detail in several industries, including ones where it is much easier to determine precise productivity than ours.</p>

<p>To see how this works, let&#8217;s play it out in a system where productivity==pay. You have the option of two jobs, one with Company A and another with Company B. At Company A, you would be one of the most productive people there. In fact, you&#8217;d be twice as productive as the average employee. The average employee at A makes $50k (all numbers are total compensation).</p>

<p>Company B, on the other hand, has some of the most brilliant people in the industry. You&#8217;d be half as productive there as the average employee. Since the average employee at Company B is 4x as productive as the average employee at Company A, they also make 4x as much: $200k. So in either case, your &#8220;fair&#8221; compensation would be $100k. Which job do you choose?</p>

<p>Well, let&#8217;s think about it some more. At Company A, you&#8217;re going to be at the top of the pile. You&#8217;re going to get the best assignments, designing the most cutting edge stuff that Company A does. That&#8217;s going to be less cutting edge than Company B&#8217;s most advanced stuff, but at Company B you&#8217;re not going to work on the most advanced stuff. You&#8217;re going to be at the bottom of the pile there, one of the most junior people. You&#8217;re going to do maintenance on their legacy products. You&#8217;re going to do the bug fixes that the senior guys don&#8217;t want to do.</p>

<p>So you&#8217;re faced with a very productive company where you&#8217;re Loser or a less productive company where you&#8217;re Alice. The question is, what kind of compensation would you require from each company in order to be willing to work there? Different people weigh these things differently. Some people would take a huge pay cut to do grunt work for a brilliant company (I know a guy who did this). But I&#8217;m guessing for most people Company B would have to pay them more to be at the bottom of the pile than Company A would to be at the top.</p>

<p>Now the math behind the pay compression should come into focus. If you demand $110k to work at Company B, you&#8217;d still be one of the lowest paid people there. But the average employee would only be paid 1.8x as much for 2x as much productivity. You just created the &#8220;unfair&#8221; situation we&#8217;re talking about. On the other hand, if you choose to work on more exciting projects at Company A and are willing to do it for $90k, then you&#8217;re on exactly the other side of the coin.</p>

<p>What this boils down to is that without Loser, Alice can&#8217;t be at the top. Without someone to do the boring maintenance work, Alice would have to do it herself. So she willingly, if unconsciously, pays Loser a premium so she can work on cooler projects. Company B needs someone to do $100k junior work. You demand $110k to be junior there rather than $90k to be senior at Company A. So they pay Alice $10k less than her job is worth, you $10k more, and the system is back in balance. Except now you&#8217;re Loser and Alice keeps asking why she doesn&#8217;t make as much as her performance predicts.</p>

<p>This is not the only cause of what seem like unfair pay practices. There is absolutely a lot of inefficiencies in big companies that allow deadwood to coast. There are definitely politics that let do-nothings get to work on cool projects. In some cases Loser can make <em>more</em> than Alice for absurd reasons. But I&#8217;m arguing that these are the margins. If they were the primary cause, more efficient companies would destroy these idiotic firms by taking all their Alices. I&#8217;m saying that the core of the compression, the reason that 3x productivity can become 1.3x pay, is that it is the natural economic result of a free market working efficiently, and that Alice is paying Loser for her rank.</p>

<p>It may not be as satisfying an answer as &#8220;companies are messed up,&#8221; but I think it actually explains the situation most accurately.</p>

<p>Footnote: Frank has recently put out a new, related book called <em>The Darwin Economy</em>. I&#8217;m not a fan of the book, even when I agree with it, because it glosses over some important points too easily. But for $10 you can read the <a href="http://www.jstor.org/stable/1805123"><em>American Economic Association</em></a> paper and see some of the real-world studies that back up this particular economic theory.</p>

<p>I&#8217;ll get back to writing about NEON assembly on the iPad in the next week or so.</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/hDkflI36qcA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/contribution-vs-compensation-748/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/contribution-vs-compensation-748</feedburner:origLink></item>
		<item>
		<title>Triangle CocoaHeads (and Building a (Core) Foundation)</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/F4ZtyLUyAM4/triangle-cocoaheads-march-745</link>
		<comments>http://robnapier.net/blog/triangle-cocoaheads-march-745#comments</comments>
		<pubDate>Sat, 24 Mar 2012 01:48:30 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[CocoaHeads]]></category>
		<category><![CDATA[CoreFoundation]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=745</guid>
		<description><![CDATA[Last night&#8217;s CocoaHeads was a blast. Alondo, you have to come give an intermediate/advanced talk on Storyboards. Thanks a lot to @scottpenrose for his lightning and thunder, and @flightblog for his inspiration (METAR gave me a lot of headaches, too). And of course, thanks especially to Josh for organizing everything. And a new place for [...]]]></description>
			<content:encoded><![CDATA[<p>Last night&#8217;s <a href="http://meetup.trianglecocoa.com/events/49569052/">CocoaHeads</a> was a blast. <a href="http://www.dtsquaredsoftware.com/">Alondo</a>, you have to come give an intermediate/advanced talk on Storyboards. Thanks a lot to @scottpenrose for his lightning and thunder, and @flightblog for his inspiration (METAR gave me a lot of headaches, too). And of course, thanks especially to <a href="http://log.jsh.in/">Josh</a> for organizing everything. And a new place for NSCoder? You rock.</p>

<p>For those who didn&#8217;t scribble notes fast enough, my Core Foundation presentation is attached (including the fix for my memory leak; was it Jay who found that?) I&#8217;ll make sure to fix the code in the book for the next edition.</p>

<p><a href="http://robnapier.net/blog/wp-content/uploads/2012/03/Building-a-Core-Foundation.pdf" title="Building a Core Foundation.pdf" alt="Building a Core Foundation">Building a Core Foundation.pdf</a></p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/F4ZtyLUyAM4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/triangle-cocoaheads-march-745/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/triangle-cocoaheads-march-745</feedburner:origLink></item>
		<item>
		<title>Even Faster Bezier</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/dcyHHO6X48w/faster-bezier-722</link>
		<comments>http://robnapier.net/blog/faster-bezier-722#comments</comments>
		<pubDate>Tue, 06 Mar 2012 16:53:40 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[performance]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=722</guid>
		<description><![CDATA[When last we looked at Bézier curve calculations, we were able to calculate five million points in about 0.6s (~8.3Mp/s or megapoints-per-second). That's 1000 points per curve, 100 curves, at 50fps. That was 5x faster than the original <code>-Os</code> optimized function. But we're just getting warmed up. We haven't yet gotten half of the performance available. In this installment, we'll look at improving our algorithm.]]></description>
			<content:encoded><![CDATA[<p>When <a href="http://robnapier.net/blog/fast-bezier-intro-701">last we looked at Bézier curve calculations</a>, we were able to calculate five million points in about 0.6s (~8.3Mp/s or megapoints-per-second). That&#8217;s 1000 points per curve, 100 curves, at 50fps. That was 5x faster than the original <code>-Os</code> optimized function. But we&#8217;re just getting warmed up. We haven&#8217;t yet gotten half of the performance available.</p>

<p><span id="more-722"></span>
In this installment, we&#8217;ll look at improving our algorithm. The code is available on <a href="https://github.com/rnapier/cocoaphony/tree/master/BezierPerf">github</a>.</p>

<p>We tried the Accelerate framework, but it didn&#8217;t help us. The cost of the function calls obliterated our gains. What can we do? First, let&#8217;s look at the code again, and see if we&#8217;re doing anything foolish.</p>

<pre><code>static inline CGFloat BezierNoPow(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) {
  return
    (1-t)*(1-t)*(1-t) * P0
    + 3 * (1-t)*(1-t) * t * P1
    + 3 * (1-t) * t*t * P2
    + t*t*t * P3;
}

unsigned int copyBezierNoPow(CGPoint P0, CGPoint P1, CGPoint P2, CGPoint P3, CGPoint **results) {
  *results = calloc(kSteps + 1, sizeof(struct CGPoint));

  for (unsigned step = 0; step &lt;= kSteps; ++step) {
    CGFloat x = BezierNoPow((CGFloat)step/(CGFloat)kSteps, P0.x, P1.x, P2.x, P3.x);
    CGFloat y = BezierNoPow((CGFloat)step/(CGFloat)kSteps, P0.y, P1.y, P2.y, P3.y);
    (*results)[step] = CGPointMake(x, y);
  }
  return kSteps + 1;
}
</code></pre>

<p>Notice how we&#8217;re recalculating a lot of things. For example, we calculate <code>(1-t)*(1-t)*(1-t)</code> twice with the same <code>t</code>. That can&#8217;t be good. What if we factor out the part that doesn&#8217;t change between <em>x</em> and <em>y</em>?</p>

<pre><code>unsigned int copyBezierXY(CGPoint P0, CGPoint P1, CGPoint P2, CGPoint P3, CGPoint **results) {
  *results = malloc((kSteps + 1) * sizeof(struct CGPoint));

  for (unsigned step = 0; step &lt;= kSteps; ++step) {
    CGFloat t = (CGFloat)step/(CGFloat)kSteps;

    CGFloat C0 = (1-t)*(1-t)*(1-t); // * P0
    CGFloat C1 = 3 * (1-t)*(1-t) * t; // * P1
    CGFloat C2 = 3 * (1-t) * t*t; // * P2
    CGFloat C3 = t*t*t; // * P3;

    CGPoint point = {
      C0*P0.x + C1*P1.x + C2*P2.x + C3*P3.x,
      C0*P0.y + C1*P1.y + C2*P2.y + C3*P3.y
    };

    (*results)[step] = point;
  }
  return kSteps + 1;
}
</code></pre>

<p>Hey, that gets us from 0.6s to 0.5s (10Mp/s). A 17% improvement&#8217;s pretty good. But let&#8217;s think about this some more. The values <code>t</code> can take are exactly dependent on <code>kSteps</code>, which is a constant for the program. And since the <code>C</code> variables depend only on <code>t</code>, that means they&#8217;re a fixed set as well. We should only have to calculate them once for the whole program. That seems a lot of work we don&#8217;t need to do. Let&#8217;s see how it turns out.</p>

<pre><code>unsigned int copyBezierTable(CGPoint P0, CGPoint P1, CGPoint P2, CGPoint P3, CGPoint **results) {
  *results = malloc((kSteps + 1) * sizeof(struct CGPoint));

  static CGFloat C0[kSteps] = {0};
  static CGFloat C1[kSteps] = {0};
  static CGFloat C2[kSteps] = {0};
  static CGFloat C3[kSteps] = {0};
  static int sInitialized = 0;
  if (!sInitialized) {
    for (unsigned step = 0; step &lt;= kSteps; ++step) {
      CGFloat t = (CGFloat)step/(CGFloat)kSteps;
      C0[step] = (1-t)*(1-t)*(1-t); // * P0
      C1[step] = 3 * (1-t)*(1-t) * t; // * P1
      C2[step] = 3 * (1-t) * t*t; // * P2
      C3[step] = t*t*t; // * P3;
    }
    sInitialized = 1;
  }

  for (unsigned step = 0; step &lt;= kSteps; ++step) {
    CGPoint point = {
      C0[step]*P0.x + C1[step]*P1.x + C2[step]*P2.x + C3[step]*P3.x,
      C0[step]*P0.y + C1[step]*P1.y + C2[step]*P2.y + C3[step]*P3.y
    };
    (*results)[step] = point;
  }
  return kSteps + 1;
}
</code></pre>

<p>0.16s. 31Mp/s. That&#8217;s over 3x faster by just calculating the piece that changes.</p>

<p><strong>Lesson 2: In most cases, your biggest improvements will come from changing your algorithm. Whenever possible, get expensive things out of loops. Don&#8217;t make a calculation fast if you can get rid of the calculation entirely. Remember that if you&#8217;re called many times, that&#8217;s the same as a loop.</strong></p>

<p>The cost of this is 4 floats (16 bytes) per step to store the constants. So for a 1000 step curve, that&#8217;s less than 16kB. Not a bad investment on iOS. This cost is for as many curves as you want, as long as they all use the same step size. Of course, if you want different numbers of steps, you could just pass a scale variable to calculate every other point, every fourth point, etc. But by the time we&#8217;re done optimizing this (and there&#8217;s still plenty of performance left to unlock), you may find that it&#8217;s faster and easier just to calculate the same number of points for all curves.</p>

<p>There is another common way to speed up Bézier calculation. Hannu Kankaanpää wrote an excellent article explaining <a href="http://www.niksula.hut.fi/~hkankaan/Homepages/bezierfast.html">forward differencing using a Taylor series</a>. His approach is fast. About 50-60% faster than <code>copyBezierXY()</code>. But <code>copyBezierTable()</code> is about twice as fast as forward differencing if you calculate a lot of curves with the same step size. Forward differencing is fast if you have one incredibly expensive curve to calculate (say a large Bézier surface). But it loses when you need to calculate a lot of curves. Factoring out everything but the points themselves into a pre-calcuated table lets you skip almost all the work. And that&#8217;s the goal.</p>

<p>We <em>still</em> haven&#8217;t pulled out Instruments, and we&#8217;re still writing in portable C. I wonder what we might get if we go off-road and write directly for the NEON coprocessor. Yes, that means we&#8217;re moving onto ARM assembler in the next post. Think you can&#8217;t beat the compiler? Think it&#8217;s not worth it to try? Think again.</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/dcyHHO6X48w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/faster-bezier-722/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/faster-bezier-722</feedburner:origLink></item>
		<item>
		<title>Introduction to Fast Bezier (and trying the Accelerate.framework)</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/B9ulA9zIZyo/fast-bezier-intro-701</link>
		<comments>http://robnapier.net/blog/fast-bezier-intro-701#comments</comments>
		<pubDate>Fri, 24 Feb 2012 18:22:46 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[accelerate]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=701</guid>
		<description><![CDATA[So you want to hand-calculate Bézier curves. Good for you. It comes up more often then you'd think on iOS. We'll discuss how to do it simply, and how to do it faster.]]></description>
			<content:encoded><![CDATA[<p>[If you want the answer to last time's homework, skip to the end.]</p>

<p>So you want to hand-calculate Bézier curves. Good for you. It comes up more often then you&#8217;d think on iOS, even though <code>UIBezierPath</code> is supposed to do it all for you. The truth is, sometimes you need the numbers yourself. For instance if you want to calculate intersections, or you want to draw text along the curve (like in <a href="https://github.com/rnapier/ios5ptl/tree/master/ch18/CurvyText">CurvyText</a> from <a href="http://iosptl.com">iOS:PTL</a> chapter 18).
<span id="more-701"></span>
Just as a refresher, here&#8217;s the cubic Bézier function in C, written in the simplest possible way (we&#8217;re only going to discuss the cubic Bézier function here):</p>

<p><pre>
static CGFloat Bezier(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) {
  return 
    powf(1-t, 3) * P0
    + 3 * powf(1-t, 2) * t * P1
    + 3 * (1-t) * powf(t, 2) * P2
    + powf(t, 3) * P3;
}
</pre></p>

<p>If you want to see this function in use, pull down CurvyText and look in <a href="https://github.com/rnapier/ios5ptl/blob/master/ch18/CurvyText/CurvyText/CurvyTextView.m">CurvyTextView.m</a>.</p>

<p><code>P0</code> through <code>P3</code> are the control points. If you called <code>addCurveToPoint:controlPoint1:controlPoint2:</code>, then the starting point (wherever you &#8220;were&#8221;) would be <code>P0</code>. The end point would be <code>P3</code> and the control points would be <code>P1</code> and <code>P2</code>. <code>t</code> is a value that runs from 0 to 1; we&#8217;ll talk about it more in a moment. If you&#8217;re still really lost, you should take time out and read the <a href="http://en.wikipedia.org/wiki/Bézier_curve">Wikipedia article on Bézier curves</a>.</p>

<p>The first thing to understand is that this is exactly the same function that <code>UIBezierPath</code> uses. (Well, exactly equivalent to the function they use. I&#8217;m certain they don&#8217;t use this one because it&#8217;s pretty inefficient as we&#8217;ll see.) So when we start calculating, we&#8217;re going to match <code>UIBezierPath</code> exactly. That&#8217;s great because it means you can mix-and-match your code and Core Graphics and everything will match-up.</p>

<p>The next thing to understand is that in this form, the Bézier curve function is effectively one-dimensional. We hand it an &#8220;x&#8221; value and we get back an &#8220;x&#8221; value. We hand it a &#8220;y&#8221; value and we get back a &#8220;y&#8221; value. So we have to call it twice per point. That&#8217;ll be important later for optimization purposes.</p>

<p>Finally, the strangest thing you need to understand is that this function is not linear for <code>t</code>. At <code>t=0</code>, the equation evaluates to <code>P0</code>. At <code>t=1</code>, the equation evaluates to <code>P3</code>. (The equation never evaluates to <code>P1</code> or <code>P2</code> since Bézier curves do not pass through these control points.) But between 0 and 1, things get much more complicated. <code>t=0.5</code> does not represent &#8220;half-way along the curve.&#8221; Small changes in <code>t</code> can represent very small movement or very large movement along the curve depending on where you are on it. This fact is one of the headaches of Bézier curves.</p>

<p>Our goal is to figure out how to calculate Bézier very fast. So we&#8217;re not going to worry much about drawing. We&#8217;re just going to investigate ways to calculate this function quickly. Hopefully the process will help you when you&#8217;re investigating other functions.</p>

<p>First, let&#8217;s build a test project. You can get the full test code in <a href="https://github.com/rnapier/cocoaphony/BezierPerf">BezierPerf</a>. Starting with a basic project, you want this in <code>didFinishLaunchingWithOptions:</code> to simulate 100 curves drawn at 50 frames per second:</p>

<pre><code>#define BEZIER_FUNC copyBezierSimple

const unsigned kFPS = 50;
const unsigned kNumCurves = 100;

CGPoint P0 = {50, 500};
CGPoint P1 = {300, 300};
CGPoint P2 = {400, 700};
CGPoint P3 = {650, 500};

CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
CGPoint lastPoint = {0};
for (unsigned i = 0; i &lt; kFPS * kNumCurves; ++i) {
  CGPoint *points;
  unsigned count = BEZIER_FUNC(P0, P1, P2, P3, &amp;points);
  lastPoint = points[count-1];
  free(points);
}
printf("Time: %f\n", CFAbsoluteTimeGetCurrent() - start);
printf("{%f, %f}\n", lastPoint.x, lastPoint.y );
exit(0);
</code></pre>

<p>Now we&#8217;ll start with the simplest approach (<a href="https://github.com/rnapier/cocoaphony/blob/master/BezierPerf/BezierPerf/Bezier.c" target="_blank">Bezier.c</a>):</p>

<pre><code>unsigned int copyBezierSimple(CGPoint P0, CGPoint P1, CGPoint P2, CGPoint P3, CGPoint **results) {
  *results = calloc(kSteps + 1, sizeof(struct CGPoint));

  for (unsigned step = 0; step &lt;= kSteps; ++step) {
    CGFloat x = Bezier((CGFloat)step/(CGFloat)kSteps, P0.x, P1.x, P2.x, P3.x);
    CGFloat y = Bezier((CGFloat)step/(CGFloat)kSteps, P0.y, P1.y, P2.y, P3.y);
    (*results)[step] = CGPointMake(x, y);
  }
  return kSteps + 1;
}
</code></pre>

<p>This just calls <code>Bezier()</code> twice. On my iPhone 4, in Debug mode, with 1000 points, this takes over 20 seconds to run. In Release mode (with optimizations) it takes just over 3 seconds. Wow. 6x improvement. We&#8217;ll look into what it&#8217;s doing later, but 3s is still no good. We need these calculations every second, and we haven&#8217;t even drawn anything yet. Time to start optimizing.</p>

<p>It&#8217;s math, so Accelerate.framework is going to make it magically fast, right? I mean, everyone knows that Accelerate uses the fancy vector hardware and that means super-duper fast. So let&#8217;s do that. We&#8217;ll rewrite <code>Bezier()</code> to use Accelerate. This calculates <code>P*B*T</code> as we discussed in <a href="http://robnapier.net/blog/equations-matrices-accelerate-607">the last post</a>.</p>

<pre><code>static CGFloat BezierAccelerate(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) {
  const CGFloat P[1][4] = {P0, P1, P2, P3};

  static const CGFloat B[4][4] = 
  { {-1,  3, -3, 1},
    { 3, -6,  3, 0},
    {-3,  3,  0, 0},
    { 1,  0,  0, 0}};

  const CGFloat T[4][1] = { powf(t, 3), powf(t, 2), t, 1 };

  CGFloat PB[1][4];
  vDSP_mmul((CGFloat*)P, 1, (CGFloat*)B, 1, (CGFloat*)PB, 1, 1, 4, 4);

  CGFloat result[1][1];
  vDSP_mmul((CGFloat*)PB, 1, (CGFloat *)T, 1, (CGFloat*)result, 1, 1, 1, 4);

  return result[0][0];
}
</code></pre>

<p>This is going to be great. We got rid of that long crazy function and replaced it with a couple of elegant matrix multiples running on the NEON vector processor. I can feel the speed already.</p>

<p>11s. In Release mode, with optimizations.</p>

<p>OK, so it&#8217;s twice as fast as the original Debug code. But it&#8217;s almost 4 times slower than just turning on <code>-Os</code> with the original function. What? Isn&#8217;t Accelerate supposed to make all things faster? We haven&#8217;t even tried to optimize the original <code>Bezier()</code> function, and still Accelerate is slower.</p>

<p><strong>Lesson 1: Accelerate is not magic &#8220;go fast&#8221; fairy dust. It may even be slower than the simplest possible non-Accelerate implementation.</strong></p>

<p>This is not to say that Accelerate isn&#8217;t awesome. It can be for certain problems. But day-to-day multiplication is often not one of them.</p>

<p>I promised we&#8217;d talk about what <code>-Os</code> is doing and why it&#8217;s giving us a 6x speedup. First, you can take a look at the code by editing the Scheme and setting the Build Configuration to Debug. Then use Product, Generate Output, Assembly File to see what happens. At the bottom of the assembler output window, you will see &#8220;Show Assembly Output For.&#8221; Switching between &#8220;Running&#8221; and &#8220;Archiving&#8221; will let you compare the debug and release output.</p>

<p>The easiest way to navigate this output is by searching for <code>.thumb_func</code> which will help you find your functions. You can then look for <code>blx</code> to find the places you make function calls. The <code>.loc</code> entries tell you where you are in the source file (filenumber, line, column). Handy, right? In debug mode, you can see the Bezier function and the four calls to <code>powf()</code>. But in release mode, the <code>Bezier</code> function is gone entirely. It&#8217;s been inlined. This is a big deal. Function calls can be expensive. This is one of the big reasons that hand-calculation can be so much faster than Accelerate. Accelerate is optimized for big matrices. For little tiny things, the cost of the function call dwarfs what you might save otherwise. Also, most Accelerate functions include fancy features like adjustable stride and parameter error checking. &#8220;Fancy features&#8221; translates into &#8220;probably slower.&#8221;</p>

<p>Back to the assembler, note that there are only two calls to <code>powf()</code>. Where did the other calls go? Well, if you dig a little, you&#8217;ll notice these lines:</p>

<pre><code>vmul.f32    d16, d0, d0
...
vmul.f32    d17, d1, d1
</code></pre>

<p>These are squaring functions (<code>d0*d0 -&gt; d16</code>). That is incredibly, insanely faster than <code>pow(x,2)</code>. We got rid of a lot of function calls (both calls to <code>Bezier</code> and calls to <code>powf</code>), and we replaced a very expensive squaring function with a very cheap one using <code>vmul</code>.</p>

<p>Which brings us to the next point. <code>vmul</code> is a NEON instruction. You don&#8217;t have to use Accelerate to get NEON benefits. The compiler uses the NEON processor for all kinds of things.</p>

<p>So now that we know that the compiler will replace <code>pow(x,2)</code> with <code>x*x</code>, I wonder if cubing by hand is faster, too. Let&#8217;s try <code>BezierNoPow()</code>:</p>

<pre><code>static CGFloat BezierNoPow(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2, CGFloat P3) {
  return
    (1-t)*(1-t)*(1-t) * P0
    + 3 * (1-t)*(1-t) * t * P1
    + 3 * (1-t) * t*t * P2
    + t*t*t * P3;
}
</code></pre>

<p>Debug: 9.7s. Nice. 50% improvement over unoptimized <code>powf()</code>.</p>

<p>Release: <strong>0.6s.</strong> 5x speedup over optimized <code>powf()</code>. <strong>30x speedup over the original function.</strong></p>

<p>In fairness, we should try removing the <code>powf()</code> calls in the Accelerate function. That gets us to 6.5s. Still 10x slower then hand-coded.</p>

<p>Now 0.6s is still 60% of our available time, so it&#8217;s worth digging deeper to see what else we can do to speed things up. We&#8217;ll talk more about that later. We haven&#8217;t really gotten warmed up yet. We haven&#8217;t even launched Instruments. There is still plenty of speed we can pick up here. Read more at <a href="http://robnapier.net/blog/faster-bezier-722">Even Faster Bezier</a>.</p>

<hr />

<p>For those of you who did your homework from <a href="http://robnapier.net/blog/equations-matrices-accelerate-607">last time</a>, here&#8217;s the answer, this time in C, for the matrix you need to calculate the derivative (slope) of the Bézier function:</p>

<pre><code>const float Bp[4][3] = {
  {-3, 6, -3},
  {9, -12, 3},
  {-9, 6, 0},
  {3, 0, 0}
};
</code></pre>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/B9ulA9zIZyo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/fast-bezier-intro-701/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/fast-bezier-intro-701</feedburner:origLink></item>
		<item>
		<title>Converting algebra to matrices for Accelerate framework</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/ARgXXgtXMaM/equations-matrices-accelerate-607</link>
		<comments>http://robnapier.net/blog/equations-matrices-accelerate-607#comments</comments>
		<pubDate>Mon, 06 Feb 2012 15:19:28 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=607</guid>
		<description><![CDATA[In this post, you will learn the basic math and tools required to convert algebraic equations into the kind of matrices required to use the Accelerate framework.]]></description>
			<content:encoded><![CDATA[<div><!-- turn off markdown -->

<p>Chapter 18 of <a href="http:/book">iOS:PTL</a> includes code for calculating points on a Bézier curve (see CurvyText in the <a href="/bookcode">sample code</a>). In the book, I hinted that this operation would likely be well suited to the <a href="https://developer.apple.com/performance/accelerateframework.html">Accelerate framework</a>. The Accelerate framework provides hardware-accelerated vector operations. Solving Bézier equations seems a perfect fit. I&#8217;ll get more into Accelerate in later posts (including some thoughts on when to use it), but first I need to introduce some mathematical groundwork.</p>

<p>In this post, I&#8217;m targeting a specific kind of developer; one like myself. My mathematically inclined friends will find this so trivial that it&#8217;s hardly worth discussing. For those of you who have never seen a matrix before, this may be a bit dense. But if you&#8217;re like me, and once upon a time you actually took linear algebra, but today you wouldn&#8217;t know a transpose if it invited you to dinner, this may help. (The last time I computed a dot-product, the Newton hadn&#8217;t been released…) My goal isn&#8217;t to teach you Guassian elimination or eigenvalues. My goal is to show you by example the specific tools you need to convert the math you find in a book into matrices so you can calculate it faster. (And how to cheat with the incredible new tools available to us.)</p>
<span id="more-607"></span>

<p>So by way of example, we will consider the cubic Bézier curve (as expressed by <a href="http://en.wikipedia.org/wiki/Bézier_curve#Cubic_B.C3.A9zier_curves">Wikipedia</a>):</p>

<p class="ql-center-displayed-equation" style="line-height: 22px;"><span class="ql-right-eqno"> (1) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-90afb3051813e555c8cddfa65cb10075_l3.png"class="ql-img-displayed-equation" alt=" &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#66;&#125;&#40;&#116;&#41;&#32;&#61;&#32;&#40;&#49;&#45;&#116;&#41;&#94;&#51;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#48;&#32;&#43;&#32;&#51;&#40;&#49;&#45;&#116;&#41;&#94;&#50;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#49;&#32;&#43;&#32;&#51;&#40;&#49;&#45;&#116;&#41;&#116;&#94;&#50;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#50;&#32;&#43;&#32;&#116;&#94;&#51;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#51;&#44;&#32;&#116;&#32;&#92;&#105;&#110;&#32;&#91;&#48;&#44;&#49;&#93;&#46; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; " title="Rendered by QuickLaTeX.com"/></p>
<p>This means that for each coordinate (x,y), you calculate the above for values running from t=0 to t=1. In C that translates into:</p>

<code><pre>
static CGFloat Bezier(CGFloat t, CGFloat P0, CGFloat P1, CGFloat P2,
                  CGFloat P3) {
  return 
    powf(1-t, 3) * P0
    + 3 * powf(1-t, 2) * t * P1
    + 3 * (1-t) * powf(t, 2) * P2
    + powf(t, 3) * P3;
}
</pre></code>

<p>For the four control points (<code>P0</code>&#8230;<code>P3</code>), you pass the <code>x</code> value to <code>Bezier()</code> and get back the <code>x</code> value of the curve. Repeat for <code>y</code>. There are many reasons that the above approach is inefficient. We&#8217;ll discuss that more in later posts. But for this post, the goal is to figure out how to convert this into an matrix operation so we can use some of of our fancy hardware to calculate it for us.</p>

<p>The first step is realizing what kind of matrix we want. Our goal is to collect all the <code>t</code> terms into one matrix, all the <code>P</code> terms into one matrix. and all the constants into a third matrix. When we&#8217;re done, it&#8217;ll look like this (where <code>K</code> is the constants):</p>

<p class="ql-center-displayed-equation" style="line-height: 18px;"><span class="ql-right-eqno"> (2) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-1802d4eb73f633dae822f14771f05977_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#66;&#125;&#40;&#116;&#41;&#32;&#61;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#75;&#84;&#125; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>Written out, that looks like:</p>

<p class="ql-center-displayed-equation" style="line-height: 88px;"><span class="ql-right-eqno"> (3) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-654967bc093384bcfe8bed51496ba481_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#66;&#125;&#40;&#116;&#41;&#32;&#61;&#32;&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#48;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#49;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#50;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#51;&#32; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#63;&#63;&#63;&#32;&#92;&#92;&#32; &#116;&#104;&#101;&#92;&#32;&#99;&#111;&#110;&#115;&#116;&#97;&#110;&#116;&#115;&#32;&#92;&#92; &#63;&#63;&#63;&#32; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#116;&#94;&#51;&#32;&#92;&#92; &#116;&#94;&#50;&#32;&#92;&#92; &#116;&#32;&#92;&#92; &#49; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>The four <code>P</code> values are the control points from the Bézier equation (these are points, so they include an x and y). The four <code>t</code> terms are the powers that occur in the equation (remember: 1 = t<sup>0 </sup>).</p>

<p>When you multiply matrices, the result has the number of rows in the first matrix and the number of columns in the second. So <code>P</code> is 1&#215;4 and the constants are MxN (we&#8217;ll figure out M and N shortly). So that result is 1xN. Times <code>T</code> (4&#215;1) and we&#8217;ll finish up with a 1&#215;1 matrix. A single point value. This is why it matters that <code>P</code> is in a row and <code>T</code> is in a column.</p>

<p>But a &#8220;point&#8221; is a vector. Let&#8217;s make that a little clearer (I hope):</p>

<p class="ql-center-displayed-equation" style="line-height: 88px;"><span class="ql-right-eqno"> (4) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-002388cb33024fade0dc1d1bc46c2bd5_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#66;&#95;&#120;&#40;&#116;&#41;&#92;&#92; &#66;&#95;&#121;&#40;&#116;&#41; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#32;&#61;&#32;&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#48;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#49;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#50;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#51;&#32; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#63;&#63;&#63;&#92;&#92; &#116;&#104;&#101;&#92;&#32;&#99;&#111;&#110;&#115;&#116;&#97;&#110;&#116;&#115;&#92;&#92; &#63;&#63;&#63;&#92;&#92; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#116;&#94;&#51;&#32;&#92;&#92; &#116;&#94;&#50;&#32;&#92;&#92; &#116;&#32;&#92;&#92; &#49; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>OK, that&#8217;s a little closer to a <code>CGPoint</code>. One x, one y. But what about &#8220;the constants?&#8221; These are the multipliers for each of the terms in &#8220;expanded form.&#8221; What we want is our equation in a form like:</p>

<p class="ql-center-displayed-equation" style="line-height: 21px;"><span class="ql-right-eqno"> (5) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-f7d1bada90b9c04a6b0a59b384c8849b_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#97;&#80;&#95;&#48;&#116;&#94;&#51;&#32;&#43;&#32;&#98;&#80;&#95;&#48;&#116;&#94;&#50;&#32;&#43;&#32;&#99;&#80;&#95;&#48;&#116;&#32;&#43;&#32;&#100;&#80;&#95;&#48;&#32;&#43;&#32;&#101;&#80;&#95;&#49;&#116;&#94;&#51;&#32;&#43;&#32;&#102;&#80;&#95;&#49;&#116;&#94;&#50;&#32;&#43;&#32;&#103;&#80;&#95;&#49;&#116;&#32;&#43;&#32;&#92;&#99;&#100;&#111;&#116;&#115; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>This gives us the sum of every combination of each <code>P</code> with each power of <code>t</code>. When you see &#8220;the sum of every combination&#8221; you should be thinking dot product and matrix multiplication. From this equation, it shouldn&#8217;t take a lot of imagination to figure out what <code>K</code> looks like.</p>

<p class="ql-center-displayed-equation" style="line-height: 88px;"><span class="ql-right-eqno"> (6) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-9f75587df76ce1b7cc5903742e329db2_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#66;&#95;&#120;&#40;&#116;&#41;&#92;&#92; &#66;&#95;&#121;&#40;&#116;&#41; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#32;&#61;&#32;&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#48;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#49;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#50;&#32;&#38;&#32;&#92;&#109;&#97;&#116;&#104;&#98;&#102;&#123;&#80;&#125;&#95;&#51;&#32; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#97;&#32;&#38;&#32;&#98;&#32;&#38;&#32;&#99;&#32;&#38;&#32;&#100;&#32;&#92;&#92; &#101;&#32;&#38;&#32;&#102;&#32;&#38;&#32;&#103;&#32;&#38;&#32;&#104;&#32;&#92;&#92; &#105;&#32;&#38;&#32;&#106;&#32;&#38;&#32;&#107;&#32;&#38;&#32;&#108;&#32;&#92;&#92; &#109;&#32;&#38;&#32;&#110;&#32;&#38;&#32;&#111;&#32;&#38;&#32;&#112; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#116;&#94;&#51;&#32;&#92;&#92; &#116;&#94;&#50;&#32;&#92;&#92; &#116;&#32;&#92;&#92; &#49; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>Now, if only we had a way to figure out all those constants easily. We could do it with pencil and paper, but I always screw up simple algebra. If only there were some device that did mechanical operations really well. Just imagine if someone put up a <a href="http://www.wolframalpha.com/">free web service</a> that would do algebra for you.</p>

<p>Bless you Wolfram. You are my hero.</p>

<p>So we head over to Wolfram|Alpha and ask it to <a href="http://www.wolframalpha.com/input/?i=expand+%281-t%29%5E3+P_0+%2B+3+%281-t%29%5E2+t+P_1+%2B+3+%281-t%29+t%5E2+P_2+%2B+t%5E3+P_3">expand the Bézier equation</a> for us:</p>

<code><pre>
expand (1-t)^3 P_0 + 3 (1-t)^2 t P_1 + 3 (1-t) t^2 P_2 + t^3 P_3
</pre></code>

<p><img style="display:block; margin-left:auto; margin-right:auto;" src="http://robnapier.net/blog/wp-content/uploads/2012/02/wolframalpha-20120206103919629.gif" alt="wolframalpha-20120206103919629.gif" border="0" width="590" height="123" /></p>

<p>And from that, we can work out our matrix:</p>

<p class="ql-center-displayed-equation" style="line-height: 86px;"><span class="ql-right-eqno"> (7) </span><span class="ql-left-eqno"> &nbsp; </span><img src="http://robnapier.net/blog/wp-content/ql-cache/quicklatex.com-d625900a1af657d107506eb7a89c1af1_l3.png"class="ql-img-displayed-equation" alt="&#92;&#98;&#101;&#103;&#105;&#110;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125; &#92;&#98;&#101;&#103;&#105;&#110;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#45;&#49;&#32;&#38;&#32;&#51;&#32;&#38;&#32;&#45;&#51;&#32;&#38;&#32;&#49;&#92;&#92; &#51;&#32;&#38;&#32;&#45;&#54;&#32;&#38;&#32;&#51;&#32;&#38;&#32;&#48;&#32;&#92;&#92; &#45;&#51;&#32;&#38;&#32;&#51;&#32;&#38;&#32;&#48;&#32;&#38;&#32;&#48;&#32;&#92;&#92; &#49;&#32;&#38;&#32;&#48;&#32;&#38;&#32;&#48;&#32;&#38;&#32;&#48; &#92;&#101;&#110;&#100;&#123;&#112;&#109;&#97;&#116;&#114;&#105;&#120;&#125; &#92;&#101;&#110;&#100;&#123;&#101;&#113;&#117;&#97;&#116;&#105;&#111;&#110;&#42;&#125;" title="Rendered by QuickLaTeX.com"/></p>

<p>Now, in fairness, I have found this matrix several <a href="http://www.google.com/search?client=safari&#038;rls=en&#038;q=bezier+matrix&#038;ie=UTF-8&#038;oe=UTF-8">places on the internet</a>. So why bother doing all this? Why not just copy the final answer? For the Bézier calculations I wanted to do, I also need the first derivative of this, and I couldn&#8217;t find the matrix for that anywhere. So sometimes the answer isn&#8217;t just out there for you. And from experience, let me say that trying to debug this kind of code when you don&#8217;t actually know what the matrix means is&#8230; challenging.</p>

<p>As an exercise, calculate the matrix for the Bézier derivative yourself. Wolfram|Alpha will give you the derivative of a function using the command <code>derivative</code> (instead of <code>expand</code>). I&#8217;ll give you a hint: the matrix is not 4&#215;4. I&#8217;ll post the answer (and how to get it) in my next installment.</p>
</div>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/ARgXXgtXMaM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/equations-matrices-accelerate-607/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/equations-matrices-accelerate-607</feedburner:origLink></item>
		<item>
		<title>Drop-in offline caching for UIWebView (and NSURLProtocol)</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/3JhfAvajDg8/offline-uiwebview-nsurlprotocol-588</link>
		<comments>http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588#comments</comments>
		<pubDate>Sun, 29 Jan 2012 18:56:11 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=588</guid>
		<description><![CDATA[Your programs need to deal gracefully with being offline. Mugunth Kumar has built an excellent toolkit that manages REST connections while offline called MKNetworkKit, and Chapter 17 of our book is devoted to the ins-and-outs of this subject. But sometimes you just have a simple UIWebView, and you want to cache the last version of the page.  In this article you'll learn how to implement this using NSURLProtocol]]></description>
			<content:encoded><![CDATA[<p><em>The most up-to-date source for this is now available at <a href="https://github.com/rnapier/RNCachingURLProtocol">github</a>.</em></p>

<p>Your programs need to deal gracefully with being offline. Mugunth Kumar has built an excellent toolkit that manages REST connections while offline called <a href="https://github.com/MugunthKumar/MKNetworkKit">MKNetworkKit</a>, and Chapter 17 of <a href="http://robnapier.net/book">our book</a> is devoted to the ins-and-outs of this subject.</p>

<p>But sometimes you just have a simple <code>UIWebView</code>, and you want to cache the last version of the page. You&#8217;d think that <code>NSURLCache</code> would handle this for you, but it&#8217;s much more complicated than that. <code>NSURLCache</code> doesn&#8217;t cache everything you&#8217;d think it would. Sometimes this is because of Apple&#8217;s decisions in order to save space. Just as often, however, it&#8217;s because the HTTP caching rules explicitly prevent caching a particular resource.</p>

<p>What I wanted was a simple mechanism for the following case:</p>

<ul>
<li>You have a UIWebView that points to a website with embedded images</li>
<li>When you&#8217;re online, you want the normal caching algorithms (nothing fancy)</li>
<li>When you&#8217;re offline, you want to show the last version of the page</li>
</ul>

<p>My test case was simple: a webview that loads cnn.com (a nice complicated webpage with lots of images). Run it once. Quit. Turn off the network. Run it again. CNN should display.</p>

<p><span id="more-588"></span></p>

<h3>Exisiting solutions</h3>

<p>The ever-brilliant Matt Gallagher has <a href="http://cocoawithlove.com/2010/09/substituting-local-data-for-remote.html">some interesting thoughts</a> on how to subclass <code>NSURLCache</code> to handle this, but I find his solution fragile and unreliable, especially on iOS 5. The HTTP caching rules are complicated, and in many cases you need to connect to the server to re-validate your cache before you&#8217;re allowed to use your local copy. Unless everything works out perfectly, his solution may not work when you&#8217;re offline, or may force you to turn off cache validation (which could make your pages go stale).</p>

<p><a href="https://github.com/artifacts/AFCache">AFCache</a> is also promising, using essentially the same approach. I haven&#8217;t found the offline support to work very well, at least in my tests, for the same reasons as Matt&#8217;s solution. It&#8217;s designed to be an advanced HTTP-caching solution. The docs are limited and I couldn&#8217;t get it to pass my CNN test.</p>

<h3>RNCachingURLProtocol</h3>

<p>So, I present <code>RNCachingURLProtocol</code>. It isn&#8217;t a replacement for <code>NSURLCache</code>. It&#8217;s a simple shim for the HTTP protocol (that&#8217;s not nearly as scary as it sounds). Anytime a URL is download, the response is cached to disk. Anytime a URL is requested, if we&#8217;re online then things proceed normally. If we&#8217;re offline, then we retrieve the cached version. The current implementation is extremely simple. In particular, it doesn&#8217;t worry about cleaning up the cache. The assumption is that you&#8217;re caching just a few simple things, like your &#8220;Latest News&#8221; page (which was the problem I was solving). It caches all HTTP traffic, so without some modifications, it&#8217;s not appropriate for an app that has a lot of HTTP connections (see <code>MKNetworkKit</code> for that). But if you need to cache some URLs and not others, that is easy to implement.</p>

<p>First, a quick rundown of how to use it:</p>

<ol>
<li><p>At some point early in the program (<code>application:didFinishLaunchingWithOptions:</code>), call the following:</p>

<p><code>[NSURLProtocol registerClass:[RNCachingURLProtocol class]];</code></p></li>
<li><p>There is no step 2.</p></li>
</ol>

<p>Since <code>RNCachingURLProtocol</code> doesn&#8217;t mess with the existing caching solution, it is compatible with other caches, like <code>AFCache</code>. In fact, the technique used by <code>RNCachingURLProtocol</code> could probably be integrated into <code>AFCache</code> pretty easily.</p>

<p>The cache itself is stored in the <code>Library/Caches</code> directory. In iOS 5, this directory can be purged whenever space is tight. Keep that in mind. You may want to store your caches elsewhere if offline access is critical.</p>

<h3>Understanding NSURLProtocol</h3>

<p>An <code>NSURLProtocol</code> is a handler for <code>NSURLConnection</code>. Each time a request is made, <code>NSURLConnection</code> walks through all the protocols and asks &#8220;Can you handle this request (<code>canInitWithRequest:</code>)?&#8221; The first protocol to return <code>YES</code> is used to handle the connection. Protocols are queried in the reverse order of their registration, so your custom handlers will get a crack at requests before the system handlers do.</p>

<p>Once your handler is selected, the connection will call <code>initWithRequest:cachedResponse:client:</code> and then <code>startLoading</code>. It is then your responsibility to call the connection back with <code>URLProtocol:didReceiveResponse:cacheStoragePolicy:</code>, some number of calls to <code>URLProtocol:didLoadData:</code>, and finally <code>URLProtocolDidFinishLoading:</code>. If these sound similar to the <code>NSURLConnection</code> delegate methods, that&#8217;s no accident.</p>

<p>While online, <code>RNCachingURLProtocol</code> just forwards requests to a new <code>NSURLConnection</code>, making copies of the results, and passing them along to the original connection. When offline, <code>RNCachingURLProtocol</code> loads the previous result from disk, and plays it back to the requesting connection. The whole thing is less than 200 lines of pretty simple code (not counting <code>Reachability</code>, which I include from Apple&#8217;s sample code to determine if we&#8217;re online).</p>

<p>There&#8217;s a subtle problem with the above solution. When <code>RNCachingURLProtocol</code> creates a new <code>NSURLConnection</code>, that new connection has to find a handler. If <code>RNCachingURLProtocol</code> says it can handle it, then you&#8217;ll have an infinite loop. So how do I know not to handle the second request? By adding a custom header (<code>X-RNCache</code>) to the HTTP request. If it&#8217;s there, then we&#8217;ve already seen this one, and the handler returns <code>NO</code>.</p>

<p>Again, this intercepts <em>all</em> HTTP traffic. That could intercept pages you don&#8217;t want. If so, you can modify <code>canInitWithRequest:</code> to select just things you want to cache (for instance, you could turn off caching for URLs that include parameters or POST requests).</p>

<h3>Wrap-up</h3>

<p>This technique isn&#8217;t a replacement for a full caching engine like <code>AFCache</code> or an offline REST engine like <code>MKNetworkKit</code>. It&#8217;s intended to solve a single, simple problem (though it can be extended to solve much more complicated problems). <code>NSURLProtocol</code> is extremely powerful, and I&#8217;ve used it extensively when I need to eavesdrop on network traffic (such as in PandoraBoy&#8217;s several <a href="https://github.com/PandoraBoy/PandoraBoy/blob/master/ProxyURLProtocol.h">ProxyURLProtocol</a> classes). It&#8217;s well-worth adding to your toolkit.</p>

<p>The code is in the attached project. Look in <code>RNCachingURLProtocol.m</code>.</p>

<p><strong>EDIT: Be sure to see Nick Dowell&#8217;s modification in the comments to handle HTTP redirect.</strong></p>

<p><strong>EDIT2: In <code>cachePathForRequest:</code>, I use <code>hash</code> to uniquely identify the URLs. For long, similar URLs, this collides a lot (See <a href="http://opensource.apple.com/source/CF/CF-476.17/CFString.c">CFString.c</a> for comments on how the hash function is implemented.) The better thing to use is MD5 or SHA1 or something, but those aren&#8217;t built-in on iOS prior to iOS5, so you&#8217;d have to implement your own (and I don&#8217;t need it that badly for my current projects). This is something you&#8217;d want to fix before using this seriously.</strong></p>

<p><a href='http://robnapier.net/blog/wp-content/uploads/2012/01/CachedWebView.zip'>CachedWebView Example Project</a></p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/3JhfAvajDg8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588/feed</wfw:commentRss>
		<slash:comments>37</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/offline-uiwebview-nsurlprotocol-588</feedburner:origLink></item>
		<item>
		<title>Kindle!</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/WVSm1xwBpAo/ios5-ptl-kindle-585</link>
		<comments>http://robnapier.net/blog/ios5-ptl-kindle-585#comments</comments>
		<pubDate>Thu, 22 Dec 2011 14:47:36 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[Pushing The Limits]]></category>
		<category><![CDATA[ios5ptl]]></category>
		<category><![CDATA[kindle]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=585</guid>
		<description><![CDATA[For those who have asked (and it's the #1 question I'm asked about the book), iOS 5 Programming Pushing the Limits is now available in Kindle format.]]></description>
			<content:encoded><![CDATA[<p>For those who have asked (and it&#8217;s the #1 question I&#8217;m asked about the book), <em>iOS 5 Programming Pushing the Limits</em> is now available in <a href="http://www.amazon.com/Programming-Pushing-Limits-Extraordinary-ebook/dp/B006OP97QI/ref=sr_1_11?s=digital-text&#038;ie=UTF8&#038;qid=1324561899&#038;sr=1-11">Kindle format</a>, along with iBook and Adobe eBook. Enjoy</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/WVSm1xwBpAo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/ios5-ptl-kindle-585/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/ios5-ptl-kindle-585</feedburner:origLink></item>
		<item>
		<title>iOS 5 Programming in Adobe E-Book format</title>
		<link>http://feedproxy.google.com/~r/Cocoaphony/~3/cZ8cVXW0GmE/ios-5-programming-adobe-ebook-format-581</link>
		<comments>http://robnapier.net/blog/ios-5-programming-adobe-ebook-format-581#comments</comments>
		<pubDate>Fri, 16 Dec 2011 15:38:47 +0000</pubDate>
		<dc:creator>Rob Napier</dc:creator>
				<category><![CDATA[cocoa]]></category>
		<category><![CDATA[iphone]]></category>

		<guid isPermaLink="false">http://robnapier.net/blog/?p=581</guid>
		<description><![CDATA[For those who have asked, the Adobe E-Book version of iOS 5 Programming is available now from Wiley. I&#8217;m not certain yet when the Kindle version will be out, but I&#8217;m looking into it, along with getting a list of what other formats are planned.]]></description>
			<content:encoded><![CDATA[<p>For those who have asked, the <a href="http://www.wiley.com/WileyCDA/WileyTitle/productCd-1119961580.html">Adobe E-Book version</a> of iOS 5 Programming is available now from Wiley. I&#8217;m not certain yet when the Kindle version will be out, but I&#8217;m looking into it, along with getting a list of what other formats are planned.</p>
<img src="http://feeds.feedburner.com/~r/Cocoaphony/~4/cZ8cVXW0GmE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://robnapier.net/blog/ios-5-programming-adobe-ebook-format-581/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://robnapier.net/blog/ios-5-programming-adobe-ebook-format-581</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 1.389 seconds. --><!-- Cached page generated by WP-Super-Cache on 2012-05-17 12:57:36 --><!-- Compression = gzip -->

