<?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>&#60;&#60; shiftedbits</title>
	<atom:link href="http://shiftedbits.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://shiftedbits.org</link>
	<description>Shift those bits. C'mon, shift em!</description>
	<lastBuildDate>Sun, 19 Apr 2009 19:42:04 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>NSCopying and Mutability</title>
		<link>http://shiftedbits.org/2009/04/17/nscopying-and-mutability/</link>
		<comments>http://shiftedbits.org/2009/04/17/nscopying-and-mutability/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 19:43:12 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Cocoa Yups and Nopes]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=121</guid>
		<description><![CDATA[In the Cocoa frameworks, it is common to find mutable and immutable versions of classes that store data, such as strings, dictionaries, and arrays. Most of these classes also implement the NSCopying informal protocol, and those with mutable varients implement the NSMutableCopying protocol. These protocols specify methods for obtaining immutable and mutable copies of an [...]]]></description>
			<content:encoded><![CDATA[<p>In the Cocoa frameworks, it is common to find mutable and immutable versions of classes that store data, such as strings, dictionaries, and arrays. Most of these classes also implement the <code>NSCopying</code> informal protocol, and those with mutable varients implement the <code>NSMutableCopying</code> protocol. These protocols specify methods for obtaining immutable and mutable copies of an object. These copying methods should be implemented such that the copy can return an instance of a subclass, to allow for subclasses to copy their specific instance variables.</p>
<p>There are situations, however, that can result in the inability of a subclass to do so. Consider <code>NSURLRequest</code>:</p>
<pre>
@interface NSURLRequest : NSObject &lt;NSCoding, NSCopying, NSMutableCopying&gt;
</pre>
<p>An immutable class, but one that implements <code>NSMutableCopying</code>, it responds directly to the <code>-mutableCopyWithZone:(NSZone *)zone</code> method that returns a mutable url request, an instance of <code>NSMutableURLRequest</code>. While this isn&#8217;t a problem in itself, it becomes an issue when this method is not re-implemented in <code>NSMutableURLRequest</code>.</p>
<div class="yupnoperap">
<p class="nope"><strong>– Nope: </strong>Implement the <code>NSMutableCopying</code> protocol only in your immutable class.</p>
<div class="why">
<p>The implementation of <code>-mutableCopyWithZone:(NSZone *)zone</code> in the immutable class must certainly hard-code the name of the mutable class &#8212; it cannot be aware of any external subclasses of the mutable class. This means that asking for a mutable copy of the immutable class creates an instance of the known mutable subclass. Consider the following example:</p>
<pre>
@interface MyMutableURLRequest : NSMutableURLRequest {} @end

MyMutableURLRequest *request = [MyMutableURLRequest requestWithURL:url];
request = [request mutableCopy];
</pre>
<p>In this case, the object returned from <code>-mutableCopy</code><strong> will be an instance of <code>NSMutableURLRequest</code></strong> instead of the expected <code>MyMutableURLRequest</code>.
</div>
</div>
<div class="yupnoperap">
<p class="nope"><strong>– Nope: </strong>Hardcode class names in <code>-copyWithZone:</code> and <code>-mutableCopyWithZone:</code></p>
<div class="why">
<p>Hardcoding class names serves to block subclassers from subclassing the copy methods without dirty hacks.</p>
</div>
</div>
<div class="yupnoperap">
<p class="yup"><strong>+ Yup: </strong>[Re]Implement the <code>NSMutableCopying</code> protocol in your mutable class.</p>
<div class="why">
<p>By doing this, the class name doesn&#8217;t have to be hard-coded (in the mutable class), and so a subclasser can simply call <code>[super mutableCopy]</code> and then copy their specific instance variables.</p>
</div>
</div>
<div class="yupnoperap">
<p class="nope"><strong>+ Yup: </strong>Use <code>[self class]</code> in <code>-copyWithZone:</code> and <code>-mutableCopyWithZone:</code></p>
<div class="why">
<p>By using [self class], an object of the subclass type will be allocated.</p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2009/04/17/nscopying-and-mutability/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Readable If Statements</title>
		<link>http://shiftedbits.org/2009/04/17/readable-if-statements/</link>
		<comments>http://shiftedbits.org/2009/04/17/readable-if-statements/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 18:10:17 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Coding Yups and Nopes]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=66</guid>
		<description><![CDATA[To kick of the Coding Yups and Nopes section, I&#8217;ll start with something simple. There are a set of things to do, and a set of things to avoid. For each thing, there are one or more reasons justifying its classification. These reasons are ordered by descending importance and increasing subjectivity.

– Nope: 
if (condition) doWork();
else [...]]]></description>
			<content:encoded><![CDATA[<p>To kick of the Coding Yups and Nopes section, I&#8217;ll start with something simple. There are a set of things to do, and a set of things to avoid. For each thing, there are one or more reasons justifying its classification. These reasons are ordered by descending importance and increasing subjectivity.</p>
<div class="yupnoperap">
<p class="nope"><strong>– Nope: </strong></p>
<pre>if (condition) doWork();
else doOtherWork();
</pre>
<div class="why">
<ul>
<li>If you&#8217;re stepping through with a debugger (I used gdb), it is difficult to tell when stepping over the line if the statement is executed. To do so you must determine the value of condition, or determine if the function was called based on its side effects.</li>
<li>If you add an additional statement to the false case, it&#8217;s possible that braces may be forgotten, leading to incorrect operation.</li>
<li>Assuming the reason for putting both condition and statement on one line was to use less lines, the benefits of this are negated by the decreased readability of such a statement. By putting both condition and statement on one line, searching for a specific condition becomes more difficult.</li>
<li>Assuming other parts of your code are scoped and indented, this breaks that pattern.</li>
</ul>
</div>
<pre>if (condition) {
    doWork();
} else doOtherWork();
</pre>
<div class="why">
<ul>
<li>Similar to the above case. Basically this is inconsistent and has none of the advantages of either method.</li>
</ul>
</div>
<pre>if(condition){
    doWork();
}
</pre>
<div class="why">
<ul>
<li>This is a pure spacing issue. <code>if</code> is not a function, please do not call it as one. Also, that brace is squashed against that parentheses, give it some room! Skimping on spacing issues like this while writing makes it harder to read later.</li>
</ul>
</div>
</div>
<div class="yupnoperap">
<p class="yup"><strong>+ Yup: </strong></p>
<pre>if (condition) {
    doWork();
} else {
    doOtherWork();
}
</pre>
<div class="why">
<ul>
<li>The perfect if-else statement. Well spaced, condition and statement on separate lines.</li>
</ul>
</div>
<pre>if (error) return;
if (error) break;
if (error) continue;
</pre>
<div class="why">
<ul>
<li>When used only for error/early exit conditions, these help to condense code so that the reader can quickly get to the meat of a function.</li>
<li>The statements and the condition are on one line because I do not consider the flow control statements return, break, and continue to contribute useful work, such that it should be scoped in braces and on its own line.</li>
</ul>
</div>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2009/04/17/readable-if-statements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Window Resizing on Resolution Change</title>
		<link>http://shiftedbits.org/2009/04/16/window-resizing-on-resolution-change/</link>
		<comments>http://shiftedbits.org/2009/04/16/window-resizing-on-resolution-change/#comments</comments>
		<pubDate>Thu, 16 Apr 2009 18:35:43 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[App Yups and Nopes]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=96</guid>
		<description><![CDATA[This post kicks off the &#8220;App Yups and Nopes&#8221; section in which I&#8217;ll post both good and bad things I see applications doing. This differs from the other Yups and Nopes sections in that it talkes specifically about observed application behavior. My intent is to show why a specific behavior is undesirable, then present a [...]]]></description>
			<content:encoded><![CDATA[<p>This post kicks off the &#8220;App Yups and Nopes&#8221; section in which I&#8217;ll post both good and bad things I see applications doing. This differs from the other Yups and Nopes sections in that it talkes specifically about observed application behavior. My intent is to show why a specific behavior is undesirable, then present a solution.</p>
<p>In this situation, I connect my laptop to a projector to watch a movie. My screen resolution changes to match that of the projector. I see applications with the following behaviors:</p>
<div class="yupnoperap">
<p class="nope"><strong>–  Nope: </strong>Resize application windows to fit on screen, regardless of window or application visibility.
</p>
<div class="why">
<p>The goal of resizing an application window on screen resolution change is to make sure the window is placed so that the user is able to manipulate it (move and resize.) An application is only required to resize and reposition windows that are actually visible. If a window is offscreen or the application is hidden, the window size and position should not be modified. When an offscreen window or a window of a hidden application is modified in this way, useless computation results. If the window cannot be seen, what use is there in constraining its bounds?</p>
</div>
</div>
<div class="yupnoperap">
<p class="yup"><strong>+ Yup: </strong>Resize application windows as they are made visible, making only the smallest change necessary to satisfy visibility and interaction requirements.
</p>
<div class="why">
<p>A common trick I use before connecting an external monitor of smaller resolution is to hide all applications &#8212; for most applications this prevents their window state from being altered. In this way when I have finished using the projector, I can unhide these applications and continue using them with a window state identical to before the resolution change. This works great for applications that implement correct window resizing behavior. Most Cocoa applications do this correctly by default. Noted offenders are iTunes and iPhoto, both of which require me to pointlessly resize their windows after the resolution is restored.</p>
<p>Note also that only the height must be constrained to the visible screen height &#8212; windows are allowed to be wider than the screen. Furthermore, it is not necessary to reposition the window such that its entire contents are visible &#8212; windows can hang off the edge of the screen on the left and right sides. This, of course, becomes more complicated when multiple displays are attached as these restrictions change.</p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2009/04/16/window-resizing-on-resolution-change/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Regression: Adobe CS4</title>
		<link>http://shiftedbits.org/2009/03/26/regression-adobe-cs4/</link>
		<comments>http://shiftedbits.org/2009/03/26/regression-adobe-cs4/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 00:35:07 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Regressions]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=60</guid>
		<description><![CDATA[So I was talking with my friends a while back, deep into one of my frequent rants about ineptitude in the software industry, when it struck me that I should start blogging this stuff. Also, my friends pointed out that the manner in which I deliver my criticism is particularly funny, and that I should [...]]]></description>
			<content:encoded><![CDATA[<p>So I was talking with my friends a while back, deep into one of my frequent rants about ineptitude in the software industry, when it struck me that I should start blogging this stuff. Also, my friends pointed out that the manner in which I deliver my criticism is particularly funny, and that I should post audio clips of this to accompany the rant. </p>
<p>I&#8217;ve decided to start a new section on this site devoted to these rants. The section is called &#8220;Regressions&#8221; and will contain my rants on various software issues that have been solved correctly before but, for some reason, are (still) present in some piece of software. These rants are a bit harsh: I&#8217;m trying to write it how I spit it when I get in the mood, and so if you find intense criticism and profanity offensive, I suggest you stop reading.</p>
<p>So, lets kick this bitch off with Adobe&#8217;s Creative Suite 4!</p>
<p>First, the installer is called &#8220;Setup.&#8221; On a Mac. See guys, on the Mac, we name things after what they really are. The correct name for this application is &#8220;Adobe CS4 Installer.&#8221; &#8220;Setup&#8221; is a) Windows-esque and b) useless for determining what this thing actually installs. Consider this regression #1.</p>
<p>Not only is the installer misnamed, but it&#8217;s in a folder with some other files. On the disk you see a folder with an icon that looks vaguely archive-like called &#8220;Adobe CS4 Master Collection.&#8221; I assumed this was the installer; what else would you put on the disk? Instead of the installer, however I see another Finder window open with 6 files: Bootstrapper.dmg, deployment, extensions, payloads, resources, Setup. What is all this crap? I just wanna install the apps dude, I don&#8217;t care about any of this junk.</p>
<p>After prompting for a password, the installer then proceeds to open a copy of the installer app running as root. This then makes another couple of child processes, which do something for a bit. Despite Apple&#8217;s consistent recommendation for and implementation of installers that use privilege-escalated tools only for the actual file copying portion, it seems that this part is too hard for Adobe, so they just launch the entire installer(s) as root. Nice job guys! Lets hope there&#8217;s no security flaws in your installer :) Regression #2.</p>
<p>I then get a dialog about some applications that need to be closed for installation. Photoshop of course is on there duh, so I close that. But what the fuck? Safari and Excel? What does that have to do with Adobe products? Presumably, Adobe thinks that because it can install its horrible PDF plugin for Safari and Office programs, you need to close these programs before you can install! Of course I don&#8217;t actually use these plugins because this is Mac OS X, where the graphics subsystem has had PDF support for 7 fucking years, and neither does anyone else who hasn&#8217;t been living under a rock. Regression #3.</p>
<p>Finally I get to the list of applications to install. I choose a custom install to see what there is and damn. That&#8217;s a LOT of crap to install. And fucking huge too! Acrobat 9 Pro is 1.2GB. How on earth you manage to make a PDF editor that big I have no idea, but clearly the folks at Adobe are good at it. Fortunately, Photoshop, which is about 2000 times more awesome and useful, is about half the size. Clearly Acrobat 9 has some absolutely AMAZING features that warrant this ridiculously huge installation size. Perhaps we should all aspire to make excessively large applications. Regression #4.</p>
<p>So I select some of these components and click install. The install finishes and I check my Applications folder to see the new apps. Wow. There&#8217;s a folder for each of the apps I wanted, of course, but there&#8217;s also a folder for some of the apps I didn&#8217;t want, containing an application container with nothing in it. Clearly along the packaging process Adobe thought that littering my hard drive with crap was acceptable. Regression #5.</p>
<p>You would think a big company like Adobe with a Mac userbase that is (or was) a significant portion of their customer base would be able to put more effort into their presentation, but perhaps to a big company these things are not such critical issues. With no serious competitor to Photoshop, customers are likely to overlook issues like these, if only because they have to.</p>
<p>[Note: Apologies if this seems a bit old -- I wrote it several months ago and completely forgot about it until today]</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2009/03/26/regression-adobe-cs4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mach_absolute_time on the iPhone</title>
		<link>http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/</link>
		<comments>http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 16:22:47 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=17</guid>
		<description><![CDATA[As programmers on OS X are well aware, the units of mach_absolute_time() have been nanoseconds since 10.2, although this was only documented since 10.5. As the iPhone runs a slimmed down version of OS X, I thought it reasonable that the units would remain the same on the device.
Not so.
On the iPhone, the timebase is [...]]]></description>
			<content:encoded><![CDATA[<p>As programmers on OS X are well aware, the units of <code>mach_absolute_time()</code> have been nanoseconds since 10.2, although this was only documented since 10.5. As the iPhone runs a slimmed down version of OS X, I thought it reasonable that the units would remain the same on the device.</p>
<p>Not so.</p>
<p>On the iPhone, the timebase is different. The <code>mach_timebase_info</code> structure contains a numerator and denominator that can be used to convert between the result returned by <code>mach_absolute_time()</code> and nanoseconds. On OS X Leopard, the numerator and denominator are both 1, meaning that the units are already in nanoseconds. On OS X iPhone, the numerator is 1,000,000,000, while the denominator is 6,000,000. Thus, every unit of absolute time on the iPhone is 166.67 nanoseconds.</p>
<p>So if you&#8217;re trying to get some timing from the iPhone using <code>mach_absolute_time()</code> and seeing times that indicate <strong>faster</strong> results on the iPhone, (not that this happened to me&#8230;), make sure to account for the difference in timebase.</p>
<p>Here&#8217;s the code for conversion between the iPhone&#8217;s <code>mach_absolute_time()</code> and nanoseconds:</p>
<pre>/* Get the timebase info */
mach_timebase_info_data_t info;
mach_timebase_info(&#038;info);

uint64_t start = mach_absolute_time();

/* Do some code */

uint64_t duration = mach_absolute_time() - start;

/* Convert to nanoseconds */
duration *= info.numer;
duration /= info.denom;

/* Log the time */
NSLog(@"My amazing code took %lld nanoseconds!", duration);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Time Machine: Switching Computers</title>
		<link>http://shiftedbits.org/2008/09/19/time-machine-switching-computers/</link>
		<comments>http://shiftedbits.org/2008/09/19/time-machine-switching-computers/#comments</comments>
		<pubDate>Fri, 19 Sep 2008 17:58:37 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Leopard]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=52</guid>
		<description><![CDATA[My main Mac is out of service for a few days as the screen gets replaced, so I performed a Time Machine restore onto another computer to use in the meantime. I&#8217;ll let this computer continue backing up to the same time machine volume, then do a TM restore back onto my main machine when [...]]]></description>
			<content:encoded><![CDATA[<p>My main Mac is out of service for a few days as the screen gets replaced, so I performed a Time Machine restore onto another computer to use in the meantime. I&#8217;ll let this computer continue backing up to the same time machine volume, then do a TM restore back onto my main machine when it&#8217;s fixed. </p>
<p>On the temporary machine, Time Machine didn&#8217;t want to continue backing up to the same backup folder. From Time Machine&#8217;s perspective, this is a different computer and so it creates a separate folder to perform the backups in. The MAC address of the computer is set as an extended attribute (xattr) on this folder so TM knows which folder to use.</p>
<p>Allowing the temp machine to use the old machine&#8217;s backup folder is simple, but not as easy as it should be. The goal is to put the temp machine&#8217;s MAC address in the place of the original&#8217;s in the xattr on the backup folder. However, using xattr -w com.apple.backupd.BackupMachineAddress 00:00:00:00:00:00 doesn&#8217;t work. Instead, you need a little program that can write the address using the xattr API.</p>
<p>I&#8217;ve written a little program that performs the switch. It turns off acls on the backup volume, sets the new xattr, logs the old MAC address, then turns the acls back on. You&#8217;ll need to run it with root privileges.</p>
<p>It&#8217;s available <a href="/static/backupswitch_1.0.zip">here</a>, or in svn at http://svn.shiftedbits.org/public/backupswitch/trunk.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/09/19/time-machine-switching-computers/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Key Value Observing Improvements v1.2.2</title>
		<link>http://shiftedbits.org/2008/09/13/key-value-observing-improvements-v122/</link>
		<comments>http://shiftedbits.org/2008/09/13/key-value-observing-improvements-v122/#comments</comments>
		<pubDate>Sat, 13 Sep 2008 23:50:29 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=50</guid>
		<description><![CDATA[Quick bug fix update:
1.2.2 Fixes a crash due to a missing implementation of __KVOAdditions__dealloc__original__ on NSObject.
1.2.1 now runs on the iPhone.
The new updates are in SVN at http://svn.shiftedbits.org/public/KVOAdditions/trunk and tagged at http://svn.shiftedbits.org/public/KVOAdditions/tags/1.2.2
]]></description>
			<content:encoded><![CDATA[<p>Quick bug fix update:</p>
<p>1.2.2 Fixes a crash due to a missing implementation of __KVOAdditions__dealloc__original__ on NSObject.</p>
<p>1.2.1 now runs on the iPhone.</p>
<p>The new updates are in SVN at <code>http://svn.shiftedbits.org/public/KVOAdditions/trunk</code> and tagged at <code>http://svn.shiftedbits.org/public/KVOAdditions/tags/1.2.2</code></p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/09/13/key-value-observing-improvements-v122/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Key Value Observing Improvements v1.2</title>
		<link>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/</link>
		<comments>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/#comments</comments>
		<pubDate>Wed, 03 Sep 2008 05:35:57 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Leopard]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=46</guid>
		<description><![CDATA[Hot on the heels of the 1.1 bug fix release comes version a freshly rewritten 1.2 with API cleanup, bug fixes, and a great new feature.
Lately, I&#8217;ve been using observers to allow an object to observe changes to its own properties. This means I don&#8217;t have to override the setter method (I&#8217;m using synthesized properties) [...]]]></description>
			<content:encoded><![CDATA[<p>Hot on the heels of the 1.1 bug fix release comes version a freshly rewritten 1.2 with API cleanup, bug fixes, and a great new feature.</p>
<p>Lately, I&#8217;ve been using observers to allow an object to observe changes to its own properties. This means I don&#8217;t have to override the setter method (I&#8217;m using synthesized properties) and the observation is managed the same way that it would be externally. The current KVO implementation (at least, in non-GC land,) however, doesn&#8217;t allow you to remove observations from yourself in your -dealloc method. This is due to the way KVO works, by interposing a KVODeallocate function before your -dealloc method. It expects that all observers of the object have been removed at this point, and warns if they are not. This is, of course, blindingly annoying &#8212; you now have to create a method that gets called on your objects by their owner before they dealloc so that they can remove their observers.</p>
<p>To fix this, I&#8217;ve done a little interposing of my own, putting in another dealloc method before KVODealloc that will remove self observers and call a -KVODealloc method on the deallocating observer object before KVODeallocate is called. If you don&#8217;t want automatic removal, simply return NO from +automaticallyRemoveSelfObservations on the class of your choice.</p>
<p>The new updates are in SVN at <code>http://svn.shiftedbits.org/public/KVOAdditions/trunk</code> and tagged at <code>http://svn.shiftedbits.org/public/KVOAdditions/tags/1.2</code><br />
<span id="more-46"></span><br />
Version 1.2 also adds new methods for removing an observer that include a selector parameter.</p>
<p><code>NSObject:</code></p>
<pre>- (void)removeObserver:(NSObject *)observer
            forKeyPath:(NSString *)keyPath
              selector:(SEL)selector;
</pre>
<p><code>NSArray:</code></p>
<pre>- (void)removeObserver:(NSObject *)observer
  fromObjectsAtIndexes:(NSIndexSet *)indexes
            forKeyPath:(NSString *)keyPath
              selector:(SEL)selector;
</pre>
<p>The selector is now considered a unique part of the observation, and so a class can observe a single property on a single object using multiple selectors. This allows a class and its subclass to avoid collisions when observing a single object.</p>
<p>The <code>-removeObserver:forKeyPath:</code> method now no longer removes selector-based observers.</p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/09/03/key-value-observing-improvements-v12/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Key Value Observing Improvements</title>
		<link>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/</link>
		<comments>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/#comments</comments>
		<pubDate>Thu, 24 Jul 2008 08:26:28 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/?p=23</guid>
		<description><![CDATA[Key value observing is quite a useful tool, no doubt about it. But it has a singularly annoying manner of informing the observer of a change. The -[NSObject observeValueForKeyPath:ofObject:change:context:] method is sent to the observer when a change occurs. It&#8217;s up to the implementor to parse the `change&#8217; dictionary to figure out what changed.
When I [...]]]></description>
			<content:encoded><![CDATA[<p>Key value observing is quite a useful tool, no doubt about it. But it has a singularly annoying manner of informing the observer of a change. The <code>-[NSObject observeValueForKeyPath:ofObject:change:context:]</code> method is sent to the observer when a change occurs. It&#8217;s up to the implementor to parse the `change&#8217; dictionary to figure out what changed.</p>
<p>When I use observers, I usually want a method called on my class when a change occurs, similar to target/action with UI elements. So my <code>-[NSObject observeValueForKeyPath:ofObject:change:context:]</code> is basically a set of if&#8217;s for each key I&#8217;m observing that calls the appropriate method.</p>
<p>This turns out to be pretty nasty, especially when you have multiple classes in a hierarchy implementing the method. It wasn&#8217;t obvious to me that I needed to call super in this method. Thirty minutes of debugging later, and I was convinced there had to be a better way of doing it.</p>
<p>To this effort, I present two new APIs. To NSObject, I add <code>-[NSObject addObserver:forKeyPath:options:selector:]</code> and to NSArray, <code>-[NSArray addObserver:toObjectsAtIndexes:forKeyPath:options:selector]</code>. The code is <a href="/static/KVOAdditions.zip">available here</a>, or keep reading for the details.</p>
<p><strong>Update 1.1: Two critical bug fixes</strong>. Please update to the new version if you have the old one. Also, anonymous svn is now available if you want to use an external. http://svn.shiftedbits.org/public/KVOAdditions/trunk.<span id="more-23"></span></p>
<p><code>NSObject:</code></p>
<pre>@interface NSObject (KVOAdditions)

- (void)addObserver:(NSObject *)observer
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end
</pre>
<p><code>NSArray:</code></p>
<pre>@interface NSArray (KVOAdditions)

- (void)addObserver:(NSObject *)observer
 toObjectsAtIndexes:(NSIndexSet *)indexes
         forKeyPath:(NSString *)keyPath
            options:(NSKeyValueObservingOptions)options
           selector:(SEL)aSelector;

@end
</pre>
<p>These allow you to observe a keyPath on an object and receive a message to the designated selector when the change occurs. Furthermore, the selector can have four different signatures that allow for different levels of information to be received. These selector formats are as follows:</p>
<pre>/* Receive no information about the change */
- (void)valueDidChange;

/* Receive the raw change dictionary */
- (void)valueDidChange:(NSDictionary *)change;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new;

/* If the observing options include either
 * NSKeyValueObservingOptionOld or NSKeyValueObservingOptionNew,
 * receive the old and new values */
- (void)valueDidChange:(id)old newValue:(id)new prior:(BOOL)isPrior;
</pre>
<p>Feedback on these APIs, including suggestions and criticism (and even bugs!) are of course welcome. </p>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/07/24/key-value-observing-improvements/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SSE Optimized Compositing</title>
		<link>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/</link>
		<comments>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/#comments</comments>
		<pubDate>Tue, 29 Jan 2008 06:08:46 +0000</pubDate>
		<dc:creator>Devin Lane</dc:creator>
				<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://shiftedbits.org/2008/01/29/sse-optimized-compositing/</guid>
		<description><![CDATA[As part of a graphics API I&#8217;ve been working on (for my own use, it&#8217;s hardly ready for production,) I decided to try learning SSE optimization by making the compositing routine faster.
I came up with an implementation which, according to my tests, is 3-5X faster than the non-optimized version. The optimized version below composites a [...]]]></description>
			<content:encoded><![CDATA[<p>As part of a graphics API I&#8217;ve been working on (for my own use, it&#8217;s hardly ready for production,) I decided to try learning SSE optimization by making the compositing routine faster.</p>
<p>I came up with an implementation which, according to my tests, is 3-5X faster than the non-optimized version. The optimized version below composites a single color starting at a destination pixel buffer for a specified run of pixels. It uses source over compositing on a RGBA, 8bpc, integer pixel buffer.</p>
<p>The optimized version is presented below:</p>
<p><span id="more-14"></span></p>
<pre>
static __m128i zero =
        _mm_set_epi32(0x0, 0x0, 0x0, 0x0);
static __m128i one =
        _mm_set_epi32(0x00010001U, 0x00010001U, 0x00010001U, 0x00010001U);
static __m128i mask1 =
        _mm_set_epi32(0x00FF00FFU, 0x00FF00FFU, 0x00FF00FFU, 0x00FF00FFU);
static __m128i mask2 =
        _mm_set_epi32(0xFF00FF00U, 0xFF00FF00U, 0xFF00FF00U, 0xFF00FF00U);

if (_comp[3] == 255) {
    /* We're compositing a fully opaque pixel, just copy onto the destination */

    unsigned int *dst = (unsigned int *)_dst;

    /* The pixel offset from dst */
    size_t i = 0;

    /* The number of quad-pixels processed */
    size_t j = 0;

    /* Leading 0..3 pixels */
    while (((intptr_t)(dst+i) &#038; (intptr_t)0xF) != 0) {
        *(dst + i) = *(unsigned int *)_comp;
        i++; run--;
    }

    /* Start at the pixel i */
    __m128i *mdst = (__m128i *)(dst + i);

    /* Set 4 pixel chunks */
    for (j = 0; j < (run>>2); j++) {
        _mm_prefetch(mdst+1, _MM_HINT_T0);
        _mm_store_si128(mdst++, _src);
    }

    /* If we couldn't get all of the run in 4 pixel chunks, get them now */
    for (size_t k = 0; k < run % 4; k++) {
        *(dst + i + k + (j<&lt;2)) = *(unsigned int *)_comp;
    }
} else {
    /* We need full composition as this pixel has transparency */

    unsigned char *dst = (unsigned char *)_dst;

    /* char offset from dst */
    size_t i = 0;

    /* Quad-pixels processed */
    size_t j = 0;

    /* get the non-aligned starting 0..3 pixels */
    while (((intptr_t)(dst+i) &#038; (intptr_t)0xF) != 0) {
        dst[0+i] = _comp[0] + dst[0+i] -
            (dst[0+i] > 0? ((((unsigned short)dst[0+i] * _comp[3]) >> 8) + 1) : 0); //R
        dst[1+i] = _comp[1] + dst[1+i] -
            (dst[1+i] > 0? ((((unsigned short)dst[1+i] * _comp[3]) >> 8) + 1) : 0); //G
        dst[2+i] = _comp[2] + dst[2+i] -
            (dst[2+i] > 0? ((((unsigned short)dst[2+i] * _comp[3]) >> 8) + 1) : 0); //B
        dst[3+i] = _comp[3] + dst[3+i] -
            (dst[3+i] > 0? ((((unsigned short)dst[3+i] * _comp[3]) >> 8) + 1) : 0); //A
        i += 4; run--;
    }

    /* Load in 2 pixels */
    __m128i *mdst = (__m128i *)(dst+i);
    __m128i d, d1, d2, res;
    for (j; j < (run>>2); j++) {
        /* Load 4 pixels */
        d = _mm_load_si128(mdst);

        /* Take chars 0,2,4,6,8,10,12,14 and composite */
        d1 = _mm_and_si128(d, mask1);
        d1 = _mm_add_epi16(_mm_subs_epi16(d1, _mm_add_epi16(
                    _mm_srli_epi16(_mm_mullo_epi16(d1, _c3), 8),
                    _mm_and_si128(_mm_cmpgt_epi16(d1, zero), one))), _ce);

        /* Take chars 1,3,5,7,9,11,13,15 and composite */
        d2 = _mm_srli_epi16(_mm_and_si128(d, mask2), 8);

        /* prefetch the next 4 pixels */
        _mm_prefetch(mdst+1, _MM_HINT_T0);

        d2 = _mm_add_epi16(_mm_subs_epi16(d2, _mm_add_epi16(
                    _mm_srli_epi16(_mm_mullo_epi16(d2, _c3), 8),
                    _mm_and_si128(_mm_cmpgt_epi16(d2, zero), one))), _co);

        /* shift odd chars (d2) to high 8 bits and or with d1 */
        res = _mm_or_si128(d1, _mm_slli_epi16(d2, 8));

        /* Store 4 pixels */
        _mm_store_si128(mdst, res);

        mdst++;
    }

    // Get the trailing 0..3 pixels
    dst += i + (j< &lt;4);
    for (size_t k = 0; k < (run % 4) * 4; k+=4) {
        dst[0+k] = _comp[0] + dst[0+k] -
            (dst[0+k] > 0? ((((unsigned short)dst[0+k] * _comp[3]) >> 8) + 1) : 0); //R
        dst[1+k] = _comp[1] + dst[1+k] -
            (dst[1+k] > 0? ((((unsigned short)dst[1+k] * _comp[3]) >> 8) + 1) : 0); //G
        dst[2+k] = _comp[2] + dst[2+k] -
            (dst[2+k] > 0? ((((unsigned short)dst[2+k] * _comp[3]) >> 8) + 1) : 0); //B
        dst[3+k] = _comp[3] + dst[3+k] -
            (dst[3+k] > 0? ((((unsigned short)dst[3+k] * _comp[3]) >> 8) + 1) : 0); //A
    }
}
</pre>
<p>_c3 is a vector composed solely of the alpha value of the color.<br />
_ce is a vector composed of pairs of the red and blue components.<br />
_co is a vector composed of pairs of the green and alpha components.<br />
_src is the start address of the pixel buffer.</p>
<p>_c3, _ce, _co, and _src are set from the following function:</p>
<pre>
unsigned short r = _comp[0], g = _comp[1], b = _comp[2], a = _comp[3];
_c3 = _mm_setr_epi16(a, a, a, a, a, a, a, a);
_ce = _mm_setr_epi16(r, b, r, b, r, b, r, b);
_co = _mm_setr_epi16(g, a, g, a, g, a, g, a);

_src = _mm_set_epi32(*(int*)_comp, *(int*)_comp, *(int*)_comp, *(int*)_comp);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://shiftedbits.org/2008/01/29/sse-optimized-compositing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.312 seconds -->
<!-- Cached page served by WP-Cache -->
