<?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>An Experiment in Bloggery &#187; Programming</title>
	<atom:link href="http://kevin.sb.org/tag/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://kevin.sb.org</link>
	<description>The occasional view into my life</description>
	<lastBuildDate>Fri, 09 Sep 2011 00:19:38 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>TinEye Safari Extensions</title>
		<link>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/</link>
		<comments>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 05:43:14 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[extensions]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[tineye]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=242</guid>
		<description><![CDATA[TinEye is a cool reverse image search engine. It lets you take an image and search for it on the web, even finding uncropped, expanded, or unwatermarked versions of the image. Sadly, while TinEye provides plugins for both Firefox and Chrome, they don&#8217;t provide one for Safari. Because of this, I have written my own [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tineye.com">TinEye</a> is a cool reverse image search engine. It lets you take an image and search for it on the web, even finding uncropped, expanded, or unwatermarked versions of the image. Sadly, while TinEye provides plugins for both Firefox and Chrome, they don&#8217;t provide one for Safari. Because of this, I have written my own extension. Just install it, then right-click on any image and you should see &#8220;Search Image on TinEye&#8221;. You can <a href="http://github.com/kballard/TinEye-for-Safari">get it here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2010/06/12/tineye-safari-extensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Major FontLabel update</title>
		<link>http://kevin.sb.org/2009/05/18/major-fontlabel-update/</link>
		<comments>http://kevin.sb.org/2009/05/18/major-fontlabel-update/#comments</comments>
		<pubDate>Mon, 18 May 2009 21:15:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[FontLabel]]></category>
		<category><![CDATA[iPhone SDK]]></category>
		<category><![CDATA[Obj-C]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=184</guid>
		<description><![CDATA[Last week I pushed out a major rewrite of FontLabel. This new version includes a category modeled after UIStringDrawing that enables you to draw text in custom fonts in your own drawRect: methods. It also includes accurate font metrics and uses more of the built-in UILabel properties. Contributions are welcome!]]></description>
			<content:encoded><![CDATA[<p>Last week I pushed out a major rewrite of <a href="http://github.com/zynga/FontLabel">FontLabel</a>. This new version includes a category modeled after UIStringDrawing that enables you to draw text in custom fonts in your own <code>drawRect:</code> methods. It also includes accurate font metrics and uses more of the built-in UILabel properties. Contributions are welcome!</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2009/05/18/major-fontlabel-update/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>GrabUp released</title>
		<link>http://kevin.sb.org/2008/04/16/grabup-released/</link>
		<comments>http://kevin.sb.org/2008/04/16/grabup-released/#comments</comments>
		<pubDate>Wed, 16 Apr 2008 06:44:55 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[GrabUp]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/?p=151</guid>
		<description><![CDATA[Recently I was contracted to write some software, and it&#8217;s just now been released. It&#8217;s called GrabUp. Basically, the whole purpose here is for zero-click sharing of screenshots. GrabUp is a daemon that sits in the background and waits for you to take a screenshot, then it instantly uploads it to the GrabUp servers and [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I was contracted to write some software, and it&#8217;s just now been released. It&#8217;s called <a href="http://www.grabup.com">GrabUp</a>. Basically, the whole purpose here is for zero-click sharing of screenshots. <a href="http://www.grabup.com">GrabUp</a> is a daemon that sits in the background and waits for you to take a screenshot, then it instantly uploads it to the GrabUp servers and puts the URL on your clipboard. It has a nice status item to let you know when it&#8217;s done. If you have GrabUp running and you want to share an image, just take the screenshot and then paste the URL anywhere. So far, GrabUp has been seen in <a href="http://www.tuaw.com/2008/04/15/grabup/" title="The Unofficial Apple Weblog">TUAW</a> and we also got a rather nice <a href="http://dbachrach.com/blog/2008/04/15/grabup-simply-amazing/" title="GrabUp: Simply Amazing">blog post</a> reviewing it.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/04/16/grabup-released/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>SafariSource v1.7.4 compatible with Safari Tidy</title>
		<link>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/</link>
		<comments>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/#comments</comments>
		<pubDate>Tue, 18 Mar 2008 22:10:47 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[Safari Tidy]]></category>
		<category><![CDATA[SafariSource]]></category>

		<guid isPermaLink="false">http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/</guid>
		<description><![CDATA[I&#8217;ve just pushed a new version of SafariSource out the door which is once again compatible with Safari Tidy. Please let me know if you have any problems. You can download it here. Note that this requires version 0.2.5 of Safari Tidy, which was just released today.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just pushed a new version of <a href="http://www.tildesoft.com/Misc.html#SafariSource">SafariSource</a> out the door which is once again compatible with <a href="http://zappatic.net/safaritidy/">Safari Tidy</a>. Please let me know if you have any problems. You can download it <a href="http://www.tildesoft.com/Files/SafariSource.zip">here</a>.</p>

<p>Note that this requires version 0.2.5 of Safari Tidy, which was just released today.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2008/03/18/safarisource-v174-compatible-with-safari-tidy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>tcltumblr 0.1</title>
		<link>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/</link>
		<comments>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/#comments</comments>
		<pubDate>Sat, 28 Apr 2007 09:01:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tcl]]></category>
		<category><![CDATA[tumblr]]></category>

		<guid isPermaLink="false">http://79a08f5b-8b87-4474-b34b-fa52b0f62111</guid>
		<description><![CDATA[tcltumblr 0.1 is available for immediate use. It is a Tcl library that provides access to the Tumblr API. Download]]></description>
			<content:encoded><![CDATA[<p><a href="http://kevin.sb.org/pages/tcltumblr">tcltumblr</a> 0.1 is available for immediate use. It is a Tcl library that provides access to the <a href="http://www.tumblr.com">Tumblr</a> <a href="http://www.tumblr.com/api">API</a>.</p>

<p><a href="/files/tcltumblr0.1.tgz">Download</a></p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2007/04/28/tcltumblr-0-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Method Swizzling reimplemented</title>
		<link>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/</link>
		<comments>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/#comments</comments>
		<pubDate>Sun, 31 Dec 2006 00:36:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Method Swizzling]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://755af07c-abcf-4e90-a7ea-729102b32de8</guid>
		<description><![CDATA[Update: This code was written pre-Leopard, and as such doesn&#8217;t run under ObjC 2. See JRSwizzle for an updated version that runs under Leopard and Snow Leopard. Method Swizzling is one common technique of people writing hacks, such as Safari Plugins. Unfortunately, it&#8217;s always suffered from a flaw, wherein swizzling inherited methods affects all classes [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Update</strong>: This code was written pre-Leopard, and as such doesn&#8217;t run under ObjC 2. See <a href="http://github.com/rentzsch/jrswizzle">JRSwizzle</a> for an updated version that runs under Leopard and Snow Leopard.</p>

<p>Method Swizzling is one common technique of people writing hacks, such as <a href="http://www.pimpmysafari.com" title="Pimp My Safari">Safari Plugins</a>.
Unfortunately, it&#8217;s always suffered from a flaw, wherein swizzling inherited methods affects all
classes which inherit that method (including the base class), rather than the intended subclass.
This problem is discussed on the <a href="http://www.cocoadev.com/index.pl?MethodSwizzling">CocoaDev Method Swizzling</a> page.</p>

<p>As part of writing <a href="http://kevin.sb.org/articles/2006/12/27/yubnubsearch-simbl-bundle">YubNubSearch</a>, I decided to solve this problem.</p>

<p>First I looked into dynamic subclass generation + posing. Unfortunately, this has a big problem. In
this technique, calling the original implementation would naturally be done through a <code>[super foo]</code> call.
Unfortunately, when the compiler sees <code>super</code>, it hardcodes a reference to the superclass at which to
start the search. This means you cannot write this code in, say, a category on NSObject, then pull up the IMP
into a dynamically-generated subclass and have it work. So that throws out that idea.</p>

<p>The other idea I had, which I eventually went with, was to copy inherited methods into the subclass that you
wish to swizzle, before swizzling. It turned out to be fairly easy, and still has the same semantics as the old,
flawed technique for calling the original implementation.</p>

<p>You can download my implementation <a href="http://www.tildesoft.com/Files/MethodSwizzle.tgz">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/12/30/method-swizzling-reimplemented/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>YubNubSearch SIMBL bundle</title>
		<link>http://kevin.sb.org/2006/12/27/yubnubsearch-simbl-bundle/</link>
		<comments>http://kevin.sb.org/2006/12/27/yubnubsearch-simbl-bundle/#comments</comments>
		<pubDate>Wed, 27 Dec 2006 11:36:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[bundle]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[simbl]]></category>
		<category><![CDATA[YubNub]]></category>

		<guid isPermaLink="false">http://e27b361b-e61a-47ed-a3da-d9d1997d0d9d</guid>
		<description><![CDATA[I just polished up my SIMBL plugin for release. It&#8217;s called YubNubSearch and it allows you to use YubNub as your default search engine in Safari. You can get it here.]]></description>
			<content:encoded><![CDATA[<p>I just polished up my <a href="http://www.culater.net/software/SIMBL/SIMBL.php" title="Simple Input Manager Bundle Loader">SIMBL</a> plugin for release. It&#8217;s called YubNubSearch and it
allows you to use <a href="http://www.yubnub.org">YubNub</a> as your default search engine in Safari.</p>

<p>You can get it <a href="http://www.tildesoft.com/Files/YubNubSearch.tgz">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/12/27/yubnubsearch-simbl-bundle/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Newest MacPorts committer</title>
		<link>http://kevin.sb.org/2006/12/13/newest-macports-committer/</link>
		<comments>http://kevin.sb.org/2006/12/13/newest-macports-committer/#comments</comments>
		<pubDate>Wed, 13 Dec 2006 16:47:54 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[commit]]></category>
		<category><![CDATA[MacPorts]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Tcl]]></category>

		<guid isPermaLink="false">http://62d10d35-73d1-41e6-beba-0eeca3e38eea</guid>
		<description><![CDATA[As of this afternoon, I am now an official committer for MacPorts. For those not in the know, MacPorts (née DarwinPorts) is an open-source package manager for Darwin (although it should work with other *nixes, it&#8217;s really intended for Darwin). I&#8217;ve been using it for quite some time, and even contributed a few Portfiles a [...]]]></description>
			<content:encoded><![CDATA[<p>As of this afternoon, I am now an official committer for <a href="http://www.macports.org">MacPorts</a>.</p>

<p>For those not in the know, <a href="http://www.macports.org">MacPorts</a> (née DarwinPorts) is an open-source package manager for Darwin
(although it should work with other *nixes, it&#8217;s really intended for Darwin). I&#8217;ve been
using it for quite some time, and even contributed a few Portfiles a while ago. Well, I
started poking at it again recently, and then jmpp on <a href="irc://chat.freenode.net/#macports">#macports</a> convinced me to
apply for a commit bit.</p>

<p>Now I just gotta do something to justify this shiny new bit.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/12/13/newest-macports-committer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objective-C caching and Method Swizzling</title>
		<link>http://kevin.sb.org/2006/11/16/objective-c-caching-and-method-swizzling/</link>
		<comments>http://kevin.sb.org/2006/11/16/objective-c-caching-and-method-swizzling/#comments</comments>
		<pubDate>Fri, 17 Nov 2006 01:46:03 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[c]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[obj]]></category>
		<category><![CDATA[objective]]></category>

		<guid isPermaLink="false">http://08e21bee-cd75-42a9-a777-72dd2fe54c09</guid>
		<description><![CDATA[(This post was adapted from an email I sent to Mike Solomon). Objective-C has a method caching mechanism that optimizes for the case where a small number of methods are called repeatedly on one (or more) objects of a given class. This happens very often; for example, if you iterate over an array to gather [...]]]></description>
			<content:encoded><![CDATA[<p>(This post was adapted from an email I sent to <a href="http://www.culater.net" title="culataer.net">Mike Solomon</a>).</p>

<p>Objective-C has a method caching mechanism that optimizes for the case where
a small number of methods are called repeatedly on one (or more) objects of a
given class. This happens very often; for example, if you iterate over an array
to gather the results of performing an operation on each element, you&#8217;re going to
be calling the same method on a bunch of instances of the same class. And in fact
the <code>-[NSEnumerator nextObject]</code> method itself will also be cached.</p>

<p>The fact that method caching exists is common knowledge. However, what isn&#8217;t generally
known is how that caching is implemented, and what it means for you if you want to
hack around on the internals of a class.</p>

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

<h3>Objective-C Method Caching</h3>

<p>The biggest reason why people might care about Objective-C method caching is if
they&#8217;re doing what&#8217;s commonly termed &#8220;Method Swizzling&#8221;. This is where you take
two methods with the same signature (same return value and argument types), and you
swap them so any code that tries to call the first will really call the second, and
vice versa. The primary use of this is when you want to patch an app you have no control
over - you can use a category to add a new method to the class, then swizzle that with
the original method.</p>

<p>The reason why this is a potential issue is, since nobody knows how the method caching
actually works, nobody knows if Method Swizzling can be affected by the method caching.</p>

<p>Well, the short answer is no.</p>

<p>Objective-C method caching works via a miniature hash table (of type <code>struct objc_cache</code>)
stored in the <code>cache</code> field in every <code>struct objc_class</code>. This hash table contains pointers
to recently-used <code>Method</code> objects, which are the same <code>Method</code> objects as found in the
<code>struct objc_method_list</code>s on each <code>struct objc_class</code>. The important part here is the
cached <code>Method</code> objects on a given class can actually belong to one of the class&#8217;s superclasses.
This is what makes the caching really useful &#8212; the method dispatch system doesn&#8217;t have to
trawl upwards through the class hierarchy to find the method if it&#8217;s already been cached.</p>

<p>The reason why Method Swizzling doesn&#8217;t have to worry about method caching is because of
the fact that the cached <code>Method</code> objects are the same ones from the <code>struct objc_method_list</code>s
in each class. When Method Swizzling modifies the Method object, the cache is modified at
the same time, so any subsequent cache hit will reflect this modified <code>Method</code>.</p>

<p>If for some reason you want to flush the cache for a class (and I can&#8217;t think of why), simply insert
<typo:tmcode theme="Space Cadet"></p>

<pre class="textmate-source"><span class="source source_objc"><span class="storage storage_type storage_type_c">void</span> _objc_flush_caches(<span class="storage storage_type storage_type_objc">Class</span> cls);</span></pre>

<p></typo:tmcode>
somewhere in your file and then call it, passing the class you wish to flush the cache of.
This particular method will also flush the cache of every superclass of the given class.</p>

<h3>Method Swizzling</h3>

<p>If you want to use Method Swizzling in your own app (or Input Manager, or <a href="http://culater.net/software/SIMBL/SIMBL.php" title="Simple Input Manager Bundle Loader">SIMBL</a> plugin, or&#8230;)
the following implementation is the best one I&#8217;m aware of.</p>

<p><typo:tmcode theme="Space Cadet"></p>

<pre class="textmate-source"><span class="source source_objc"><span class="storage storage_type storage_type_c">void</span><span class="meta meta_function meta_function_c"> <span class="entity entity_name entity_name_function entity_name_function_c">PerformSwizzle</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span><span class="storage storage_type storage_type_objc">Class</span> aClass, <span class="storage storage_type storage_type_objc">SEL</span> orig_sel, <span class="storage storage_type storage_type_objc">SEL</span> alt_sel, <span class="storage storage_type storage_type_objc">BOOL</span> forInstance<span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">)</span></span>
{
    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> First, make sure the class isn't nil
</span>    <span class="keyword keyword_control keyword_control_c">if</span> (aClass != <span class="constant constant_language constant_language_objc">nil</span>) {
        Method orig_method = <span class="constant constant_language constant_language_objc">nil</span>, alt_method = <span class="constant constant_language constant_language_objc">nil</span>;

        <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Next, look for the methods
</span>        <span class="keyword keyword_control keyword_control_c">if</span> (forInstance) {
            orig_method = class_getInstanceMethod(aClass, orig_sel);
            alt_method = class_getInstanceMethod(aClass, alt_sel);
        } <span class="keyword keyword_control keyword_control_c">else</span> {
            orig_method = class_getClassMethod(aClass, orig_sel);
            alt_method = class_getClassMethod(aClass, alt_sel);
        }

        <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> If both are found, swizzle them
</span>        <span class="keyword keyword_control keyword_control_c">if</span> ((orig_method != <span class="constant constant_language constant_language_objc">nil</span>) &amp;&amp; (alt_method != <span class="constant constant_language constant_language_objc">nil</span>)) {
            <span class="storage storage_type storage_type_objc">IMP</span> temp;

            temp = orig_method-&gt;method_imp;
            orig_method-&gt;method_imp = alt_method-&gt;method_imp;
            alt_method-&gt;method_imp = temp;
        } <span class="keyword keyword_control keyword_control_c">else</span> {
<span class="meta meta_preprocessor meta_preprocessor_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_c">if</span> DEBUG</span>
            <span class="support support_function support_function_cocoa">NSLog</span>(<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>PerformSwizzle Error: Original %@, Alternate %@<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>,(orig_method == <span class="constant constant_language constant_language_objc">nil</span>)?<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span> not found<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>:<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span> found<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>,(alt_method == <span class="constant constant_language constant_language_objc">nil</span>)?<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span> not found<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>:<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span> found<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>);
<span class="meta meta_preprocessor meta_preprocessor_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_c">endif</span></span>
        }
    } <span class="keyword keyword_control keyword_control_c">else</span> {
<span class="meta meta_preprocessor meta_preprocessor_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_c">if</span> DEBUG</span>
        <span class="support support_function support_function_cocoa">NSLog</span>(<span class="string string_quoted string_quoted_double string_quoted_double_objc"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_objc">@"</span>PerformSwizzle Error: Class not found<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_objc">"</span></span>);
<span class="meta meta_preprocessor meta_preprocessor_c">#<span class="keyword keyword_control keyword_control_import keyword_control_import_c">endif</span></span>
    }
}

<span class="storage storage_type storage_type_c">void</span><span class="meta meta_function meta_function_c"> <span class="entity entity_name entity_name_function entity_name_function_c">MethodSwizzle</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span><span class="storage storage_type storage_type_objc">Class</span> aClass, <span class="storage storage_type storage_type_objc">SEL</span> orig_sel, <span class="storage storage_type storage_type_objc">SEL</span> alt_sel<span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">)</span></span>
{
    PerformSwizzle(aClass, orig_sel, alt_sel, <span class="constant constant_language constant_language_objc">YES</span>);
}

<span class="storage storage_type storage_type_c">void</span><span class="meta meta_function meta_function_c"> <span class="entity entity_name entity_name_function entity_name_function_c">ClassMethodSwizzle</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span><span class="storage storage_type storage_type_objc">Class</span> aClass, <span class="storage storage_type storage_type_objc">SEL</span> orig_sel, <span class="storage storage_type storage_type_objc">SEL</span> alt_sel<span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">)</span></span>
{
    PerformSwizzle(aClass, orig_sel, alt_sel, <span class="constant constant_language constant_language_objc">NO</span>);
}</span></pre>

<p></typo:tmcode></p>

<p>This particular implementation swaps the <code>method_imp</code> pointers on the two methods, so calling the
first method will call the original implementation of the second, and vice versa. The elegant aspect
to this is when you want to call the original method &#8212; simply call your new method again. The following
example, adapted from <a href="http://pimpmysafari.com/plugins/safarisource-161">SafariSource</a>, demonstrates this.</p>

<p><typo:tmcode theme="Space Cadet"></p>

<pre class="textmate-source"><span class="source source_objc">- (<span class="storage storage_type storage_type_c">void</span>) mySetString:(<span class="support support_class support_class_cocoa">NSString</span> *)string {
    <span class="support support_class support_class_cocoa">NSUserDefaults</span> *defs = <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">[</span><span class="support support_class support_class_cocoa">NSUserDefaults</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">standardUserDefaults</span></span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">]</span></span>;
    <span class="keyword keyword_control keyword_control_c">if</span> (<span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">[</span>defs <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">boolForKey<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>SafariSourceEnabled</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">]</span></span>) {
        <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> do stuff here
</span>    } <span class="keyword keyword_control keyword_control_c">else</span> {
        <span class="meta meta_bracketed meta_bracketed_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">[</span><span class="variable variable_language variable_language_objc">self</span> <span class="meta meta_function-call meta_function-call_objc"><span class="support support_function support_function_any-method support_function_any-method_objc">mySetString<span class="punctuation punctuation_separator punctuation_separator_arguments punctuation_separator_arguments_objc">:</span></span>string</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_objc">]</span></span>;
    }
}</span></pre>

<p></typo:tmcode></p>

<p>When any code tries to call <code>setString:</code> on this class, the swizzled method <code>mySetString:</code> is called
again. But since the swizzling is done in both directions, trying to call <code>mySetString:</code> will in fact
call <code>setString:</code>. So when the code appears to be calling itself recursively, it&#8217;s really calling
the original function.</p>

<p>The biggest flaw with this implementation (and any others I&#8217;ve seen) is that if you want to swizzle
a method that&#8217;s actually implemented in a superclass, the swizzling will affect all instances of
that superclass instead of just instances of the subclass. There are a couple of possible solutions,
such as dynamically creating a new class and using it to pose as the old class, but none have
yet been implemented to my knowledge.</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/11/16/objective-c-caching-and-method-swizzling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CGSSetWindowWarp explained</title>
		<link>http://kevin.sb.org/2006/07/23/cgssetwindowwarp-explained/</link>
		<comments>http://kevin.sb.org/2006/07/23/cgssetwindowwarp-explained/#comments</comments>
		<pubDate>Sun, 23 Jul 2006 12:52:00 +0000</pubDate>
		<dc:creator>Kevin Ballard</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CGS]]></category>
		<category><![CDATA[CoreGraphics]]></category>
		<category><![CDATA[ironcoder]]></category>
		<category><![CDATA[window]]></category>

		<guid isPermaLink="false">http://8dd94ea3-dc27-40f6-9d77-c38db636270f</guid>
		<description><![CDATA[Ironcoder 0x2 wraps up in a few hours, and this time the API was CoreGraphics. As soon as I heard this, I knew I wanted to do something with window mesh deformation. What&#8217;s that? Why, it&#8217;s the private CoreGraphics call you can use to do the effects such as the Genie minimize effect, though I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.ironcoder.org">Ironcoder</a> 0x2 wraps up in a few hours, and this time the API was CoreGraphics. As soon as I heard this, I knew I wanted to do something with window mesh deformation. What&#8217;s that? Why, it&#8217;s the private CoreGraphics call you can use to do the effects such as the Genie minimize effect, though I believe it&#8217;s new in 10.3. It&#8217;s a function called CGSSetWindowWarp(), and it&#8217;s extremely poorly documented.</p>

<p>First, some history. CoreGraphics has a bunch of private calls that range from applying transitions to windows (such as the cube effect seen in Apple Remote Desktop and Quicksilver) to managing virtual desktops to setting alpha levels on groups of windows system-wide. As far as I am able to ascertain, Richard Wareham did the bulk of the work to expose these calls, as part of development on his <a href="http://desktopmanager.berlios.de/">Desktop Manager</a> program, the most well-known virtual desktop solution for OS X. He released a file named CGSPrivate.h that contained these basic calls, so others could use it. Since then, more private calls have been discovered, and among them were CGSSetWindowWarp().</p>

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

<p>For a while, only the name of the function was known. As far as I know, I was the first person to determine what the arguments to the function were, though this information wasn&#8217;t widely disseminated. Instead, I simply told Nicholas Jitkoff (author of <a href="http://quicksilver.blacktree.com">Quicksilver</a>), as he was the one who asked me to help him figure it out. At that time, I didn&#8217;t know how the function was actually <em>used</em>, I just knew what arguments it took. And then I forgot about it.</p>

<p>Since then other people have played with the function (having figured out the arguments on their own). The most visible documentation of this I could find was on <a href="http://www.cocoadev.com/index.pl?WildWindows">CocoaDev</a>, where the author of the splendid <a href="http://homepage.cs.latrobe.edu.au/wjtregaskis/">Rotated Windows</a> sample app said he figured out the arguments to the function but hadn&#8217;t yet figured out how it was actually used - basically, he did what I did.</p>

<p>At this point, what was known was the method signature:</p>

<p>typedef struct CGPointWarp {
        CGPoint local;
        CGPoint global;
    } CGPointWarp;</p>

<p>extern CGError CGSSetWindowWarp(CGSConnectionID, CGSWindowID, int w, int h, CGPointWarp mesh[w][h])</p>

<p>Most of this is pretty self-evident, but the tricky question is how the mesh works.</p>

<p>Well, some time ago I ran across a sample app called <a href="http://paste.lisp.org/display/2718">warp.c</a>, which simply produced a simple animation of a window being bent backwards (using a bezier curve). It wasn&#8217;t very complex, but it did help show how the deformation mesh was constructed. What the mesh does is maps local window coordinates to global screen coordinates. It&#8217;s a 2-dimensional array that forms a grid of points. From what I can determine, the local points are expected to form a regular, even grid. The vertical and horizontal deltas can be different, but they must be consistent. Changing a single point causes visual issues, from simply incorrect drawing to the window disappearing.</p>

<p>Based on this, I was able to construct my entry for <a href="http://www.ironcoder.org">ironcoder</a> that used CGSSetWindowWarp() as the main effect.</p>

<p>To summarize, the way CGSSetWindowWarp() is used is the mesh is a 2-dimensional grid of local points with associated global points. The local points are in the window&#8217;s coordinate system, whereas the global points are in the screen&#8217;s coordinate system.</p>

<p>One pitfall I discovered during this process is you need to be aware of the window being dragged. If you&#8217;re animating a window and someone starts to drag it, you can run into problems where the window keeps snapping back to its old location. Why is this? Because -[NSWindow frame] doesn&#8217;t update until you end the drag, so your global coordinates are going to be based on the window&#8217;s old position. Not to mention -[NSWindow frame] uses a flipped screen coordinate system from CGSSetWindowWarp(). There&#8217;s a good solution to this, however. That solution is to use another private method:</p>

<p>extern OSStatus CGSGetWindowBounds(CGSConnectionID cid, CGSWindowID wid, CGRect *bounds)</p>

<p>This will give you a CGRect (structurally and functionally equivalent to an NSRect) that contains the current frame of the window, taking a current drag into account, and using the same coordinate system that CGSSetWindowWarp expects. There&#8217;s also another similar function:</p>

<p>extern OSStatus CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *outRect)</p>

<p>There is one crucial difference, namely, that the CGRect given by this function is the rect that covers the entire rendered area of the window, meaning any window mesh deformations are taken into account. So this is not the right function to use when calculating the deformation mesh, because any pre-existing deformation will throw off the coordinates. So use CGSGetWindowBounds() always.</p>

<p>The last bit of information necessary to use CGSSetWindowWarp() is how to get the CGSConnectionID and CGSWindowID. This, luckily, is extremely simple. A CGSConnectionID can be retrieved with the private function:</p>

<p>extern CGSConnectionID _CGSDefaultConnection()</p>

<p>and the CGSWindowID is the result of calling <code>-[NSWindow windowNumber]</code> on your window. Incidentally both CGSConnectionID and CGSWindowID should be typedefs of <code>int</code>.</p>

<p>You should be aware that applying a deformation mesh to a window will cause the shadow to not draw. So if you want a normal shadow, you will need to draw it yourself. Additionally, the window warp can be removed (and shadow restored) by calling CGSSetWindowWarp() with 0, 0, and NULL.</p>

<p><strong>Update:</strong> My ironcoder entry is now <a href="http://ironcoder.org/entries/ironcoder_2/KevinBallardDC.zip" title="DaliClock">available</a>, in case you want another example of CGSSetWindowWarp().</p>
]]></content:encoded>
			<wfw:commentRss>http://kevin.sb.org/2006/07/23/cgssetwindowwarp-explained/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->
