<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss1japanesefull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns="http://purl.org/rss/1.0/"><channel rdf:about="http://blog.boreal-kiss.com"><title>boreal-kiss.com</title><link>http://blog.boreal-kiss.com</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rdf+xml" href="http://feeds.feedburner.com/bbk" /><description>Flash ActionScript関連のメモ</description><dc:language>ja</dc:language><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/bbk" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="bbk" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><items><rdf:Seq><rdf:li rdf:resource="http://blog.boreal-kiss.com/?p=404" /><rdf:li rdf:resource="http://blog.boreal-kiss.com/?p=403" /><rdf:li rdf:resource="http://blog.boreal-kiss.com/?p=397" /><rdf:li rdf:resource="http://blog.boreal-kiss.com/?p=389" /><rdf:li rdf:resource="http://blog.boreal-kiss.com/?p=388" /></rdf:Seq></items></channel><item rdf:about="http://blog.boreal-kiss.com/?p=404"><title>Associative Storage: カテゴリに疑似インスタンス変数を追加</title><link>http://blog.boreal-kiss.com/2010/03/07000052.html</link><dc:subject>未分類</dc:subject><dc:subject>Cocoa</dc:subject><dc:subject>DesignPatterns</dc:subject><dc:subject>Objective-C</dc:subject><dc:creator>borealkiss</dc:creator><dc:date>2010-03-06T07:00:52-08:00</dc:date><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h1>イントロダクション</h1>
<p>Objective-Cのカテゴリはサブクラスを作ることなくメソッドの拡張(またはメソッドごとの分類)が行える点で強力だ。しかしメソッドの定義はできてもインスタンス変数の追加ができない。そこでCocoaのKey Value Coding (KVC)の機能を用いてカテゴリに擬似的にインスタンス変数を生成させる。これにより元クラスを手直しすることなくインスタンス変数を追加することができる。なおこの手法は、よりフレキシブルという理由で<a href="http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/NSMapTable_class/Reference/NSMapTable.html">NSMapTable</a>を用いるのが一般的なようだが、ここでは<a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSMutableDictionary_Class/Reference/Reference.html">NSMutableDictionary</a>を代用した。理由は使い慣れているからだ。NSMapTableを用いた方法は<a href="http://www.amazon.co.jp/exec/obidos/ASIN/0321535022/borealkiss-22/">Buck and Yacktman - Cocoa Design Patterns</a>が詳しい。</p>
<h1>具体例</h1>
<p>簡単な例としてボタンを押すとアラートを表示するアプリケーションを考える。ボタンプッシュ後の動作はAppControllerクラスで以下のように定義されているとする。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController.m</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span>, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>ここで「一度アラート表示された場合は再度アラートを表示させない」仕様に変更するとしよう。AppControllerにBOOL値を格納するインスタンス変数を追加して制御するのが手っ取り早いが、ここではAppControllerのカテゴリ(ShowAtOnce)を新規に定義して制御することにする。カテゴリ作成の大まかな手順は以下のようになる。</p>
<ol>
<li>疑似インスタンス変数格納用にNSMutableDictionary変数をカテゴリに定義</li>
<li>疑似インスタンス変数としたいオブジェクトを上記NSMutableDictionary変数に格納。その際のキーストリングはAppControllerインスタンスに固有のものを用いる</li>
<li>格納したオブジェクトのAccesors (Setters/Getters)をカテゴリに定義</li>
<li>インスタンスの解放時にNSMutableDictionaryからオブジェクトを消去するメソッドをカテゴリに定義</li>
</ol>
<p>以下順にみていこう。</p>
<h2>1. 疑似インスタンス変数格納用変数の定義</h2>
<p>疑似インスタンス変数にしても情報を格納する場所は必要になる。そこで疑似インスタンス変数を格納する場所としてNSMutableDictionaryオブジェクトをカテゴリ(ShowAtOnce)に定義する。さらにこのオブジェクトのAccesorsをクラスメソッドとして定義する。つまりこの格納用のNSMutableDictionaryオブジェクトはAppControllerインスタンスすべてで使い回されることになる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController <span style="color: #002200;">&#40;</span>ShowAtOnce<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_simulatedIVars<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>_simulatedIVars <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #a61390;">return</span> _simulatedIVars;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<h2>2. インスタンス固有のキーストリング</h2>
<p>上記例のアプリケーションの仕様を実現するためには、一度アラートが表示されたかどうかを調べるBOOL値を(NSMutableDictionary *)_simulatedIVarsに格納できればよさそうだ。しかし今は疑似インスタンス変数を作りたいのでAppControllerインスタンスごとに異なる値を格納できるようにする必要がある。そこでまず「AppControllerインスタンスに固有なNSStringオブジェクト」を生成するメソッドを定義する。このメソッドは-[AppController self]のストリング表現を返す。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_instanceID<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>さらに「疑似インスタンス変数名に相当するNSStringオブジェクト」を用意する。これはクラス全体で使い回しができるようにすればよい。ここではAlertHasEverBeenShownKeyStringという名前で定義しておこう。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span> <span style="color: #a61390;">const</span> AlertHasEverBeenShownKeyString <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;alertHasEverBeenShown&quot;</span>;</pre></div></div>

<p>あとは「AppControllerインスタンスに固有なNSStringオブジェクト」と「疑似インスタンス変数名に相当するNSStringオブジェクト」を適当に繋げて「あるAppControllerインスタンスの疑似インスタンス変数に固有なNSStringオブジェクト」を作成するメソッドを定義する。このメソッドの返り値が(NSMutableDictionary *)_simulatedIVarsへの格納用キーストリングとして利用されるわけだ。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_objectKeyForKeyString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aKeyString<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%@&quot;</span>, 
		<span style="color: #002200;">&#91;</span>self _instanceID<span style="color: #002200;">&#93;</span>, aKeyString<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>現在までのAppController (ShowAtOnce)の中身をまとめると以下のようになっているはずだ。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span> <span style="color: #a61390;">const</span> AlertHasEverBeenShownKeyString <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;alertHasEverBeenShown&quot;</span>;
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController <span style="color: #002200;">&#40;</span>ShowAtOnce<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_simulatedIVars<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>_simulatedIVars <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #a61390;">return</span> _simulatedIVars;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #6e371a;">#pragma mark -</span>
<span style="color: #6e371a;">#pragma mark Utilities</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_instanceID<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_objectKeyForKeyString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aKeyString<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%@&quot;</span>, 
		<span style="color: #002200;">&#91;</span>self _instanceID<span style="color: #002200;">&#93;</span>, aKeyString<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<h2>3. 疑似インスタンス変数のAccesors</h2>
<p>上記メソッド群を利用してカテゴリ(ShowAtOnce)に定義する。Settersは-[AppController _setAlertHasEverBeenShown:]、Gettersは-[AppController _alertHasEverBeenShown]としよう。ここはstraightforwardだと思う。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>_alertHasEverBeenShown<span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">id</span> object <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> objectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>object <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		<span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>object boolValue<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_setAlertHasEverBeenShown<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>yn<span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> 
		setObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span>yn<span style="color: #002200;">&#93;</span> forKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>あとはAppController内でこのメソッドを使ってやればよい。具体的には以下のようになるだろう。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController.m</span>
&nbsp;
<span style="color: #6e371a;">#import &quot;AppController-ShowAtOnce.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>self _alertHasEverBeenShown<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		NSRunAlertPanel<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span>, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
		<span style="color: #002200;">&#91;</span>self _setAlertHasEverBeenShown<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<h2>4. 疑似インスタンス変数を解放</h2>
<p>AppControllerインスタンスごとに(NSMutableDictionary *)_simulatedIVarsに登録されるのだからAppControllerインスタンスが不要になったら疑似インスタンス変数も解放する必要がある。そのために以下のようなメソッドをAppController(ShowAtOnce)に定義しておく。このメソッドは呼ばれれば不要になった疑似インスタンス変数を解放する。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_removeSimulatedIVars<span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">id</span> object <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> objectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>object<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> removeObjectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>さてこれまでAppControllerそのものを一切変更しないように実装すると言ってきたが実は嘘で、AppControllerそのものを手直しする必要がでてくる。というのも疑似インスタンス変数の解放を呼ぶメソッドをカテゴリに書くことは危険だからだ。例えば-[AppController dealloc]をカテゴリ(ShowAtOnce)に再定義することは可能だが、もし他に疑似インスタンス変数を持つ別カテゴリが同様の-[AppController dealloc]を実装した場合どちらの-[AppController dealloc]が呼び出されるかわからなくなるからだ(結果どちらかのカテゴリの疑似インスタンス変数は解放メソッドを呼ばれないがために生き残ってしまう)。したがって疑似インスタンス変数の解放メソッドを呼び出すのはAppControllerとするのがよいだろう。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController.m</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self _removeSimulatedIVars<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<h1>全ソースコード</h1>
<p>最終的なコードは以下のようになっている。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController.h</span>
&nbsp;
<span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AppController <span style="color: #002200;">:</span> <span style="color: #400080;">NSObject</span> <span style="color: #002200;">&#123;</span>
&nbsp;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController.m</span>
&nbsp;
<span style="color: #6e371a;">#import &quot;AppController.h&quot;</span>
<span style="color: #6e371a;">#import &quot;AppController-ShowAtOnce.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">!</span><span style="color: #002200;">&#91;</span>self _alertHasEverBeenShown<span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		NSRunAlertPanel<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span>, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
		<span style="color: #002200;">&#91;</span>self _setAlertHasEverBeenShown<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self _removeSimulatedIVars<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.h</span>
&nbsp;
<span style="color: #6e371a;">#import &lt;Cocoa/Cocoa.h&gt;</span>
<span style="color: #6e371a;">#import &quot;AppController.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@interface</span> AppController <span style="color: #002200;">&#40;</span>ShowAtOnce<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_simulatedIVars;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_removeSimulatedIVars;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>_alertHasEverBeenShown;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_setAlertHasEverBeenShown<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>yn;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_instanceID;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_objectKeyForKeyString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aKeyString;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//AppController-ShowAtOnce.m</span>
&nbsp;
<span style="color: #6e371a;">#import &quot;AppController-ShowAtOnce.h&quot;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Private</span>
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span> <span style="color: #a61390;">const</span> AlertHasEverBeenShownKeyString <span style="color: #002200;">=</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;alertHasEverBeenShown&quot;</span>;
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController <span style="color: #002200;">&#40;</span>ShowAtOnce<span style="color: #002200;">&#41;</span>
&nbsp;
<span style="color: #a61390;">static</span> <span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span>_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMutableDictionary</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_simulatedIVars<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>_simulatedIVars <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		_simulatedIVars <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSMutableDictionary</span> alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
	<span style="color: #a61390;">return</span> _simulatedIVars;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_removeSimulatedIVars<span style="color: #002200;">&#123;</span>
	NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%s&quot;</span>, __FUNCTION__<span style="color: #002200;">&#41;</span>;
&nbsp;
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">id</span> object <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> objectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
&nbsp;
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>object<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> removeObjectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#125;</span>
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #6e371a;">#pragma mark -</span>
<span style="color: #6e371a;">#pragma mark Setters Getters</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>_alertHasEverBeenShown<span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">id</span> object <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> objectForKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
	<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span>object <span style="color: #002200;">==</span> <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
		<span style="color: #a61390;">return</span> <span style="color: #a61390;">NO</span>;
	<span style="color: #002200;">&#125;</span>
&nbsp;
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>object boolValue<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>_setAlertHasEverBeenShown<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>yn<span style="color: #002200;">&#123;</span>
	<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>aKey <span style="color: #002200;">=</span> 
		<span style="color: #002200;">&#91;</span>self _objectKeyForKeyString<span style="color: #002200;">:</span>AlertHasEverBeenShownKeyString<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> _simulatedIVars<span style="color: #002200;">&#93;</span> 
		setObject<span style="color: #002200;">:</span><span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span>yn<span style="color: #002200;">&#93;</span> forKey<span style="color: #002200;">:</span>aKey<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #6e371a;">#pragma mark -</span>
<span style="color: #6e371a;">#pragma mark Utilities</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_instanceID<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>_objectKeyForKeyString<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aKeyString<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSString</span> stringWithFormat<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@:%@&quot;</span>, 
		<span style="color: #002200;">&#91;</span>self _instanceID<span style="color: #002200;">&#93;</span>, aKeyString<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

]]></content:encoded><description>イントロダクション
Objective-Cのカテゴリはサブクラスを作ることなくメソッドの拡張(またはメソッドごとの分類)が行える点で強力だ。しかしメソッドの定義はできてもインスタンス変数の追加ができない。そこでCocoaのKey Value Coding (KVC)の機能を用いてカテゴリに擬似的にインスタンス変数を生成させる。これにより元クラスを手直しすることなくインスタンス変数を追加することができる。なおこの手法は、よりフレキシブルという理由でNSMapTableを用いるのが一般的なようだが、ここではNSMutableDictionaryを代用した。理由は使い慣れているからだ。NSMapTableを用いた方法はBuck and Yacktman - Cocoa Design Patternsが詳しい。
具体例
簡単な例としてボタンを押すとアラートを表示するアプリケーションを考える。ボタンプッシュ後の動作はAppControllerクラスで以下のように定義されているとする。

//AppController.m
&amp;#160;
@implementation AppController
&amp;#160;
-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	NSRunAlertPanel&amp;#40;@&amp;#34;Alert&amp;#34;, @&amp;#34;This is an alert.&amp;#34;, @&amp;#34;OK&amp;#34;, nil, nil&amp;#41;;
&amp;#125;
&amp;#160;
@end

ここで「一度アラート表示された場合は再度アラートを表示させない」仕様に変更するとしよう。AppControllerにBOOL値を格納するインスタンス変数を追加して制御するのが手っ取り早いが、ここではAppControllerのカテゴリ(ShowAtOnce)を新規に定義して制御することにする。カテゴリ作成の大まかな手順は以下のようになる。

疑似インスタンス変数格納用にNSMutableDictionary変数をカテゴリに定義
疑似インスタンス変数としたいオブジェクトを上記NSMutableDictionary変数に格納。その際のキーストリングはAppControllerインスタンスに固有のものを用いる
格納したオブジェクトのAccesors (Setters/Getters)をカテゴリに定義
インスタンスの解放時にNSMutableDictionaryからオブジェクトを消去するメソッドをカテゴリに定義

以下順にみていこう。
1. 疑似インスタンス変数格納用変数の定義
疑似インスタンス変数にしても情報を格納する場所は必要になる。そこで疑似インスタンス変数を格納する場所としてNSMutableDictionaryオブジェクトをカテゴリ(ShowAtOnce)に定義する。さらにこのオブジェクトのAccesorsをクラスメソッドとして定義する。つまりこの格納用のNSMutableDictionaryオブジェクトはAppControllerインスタンスすべてで使い回されることになる。

//AppController-ShowAtOnce.m
&amp;#160;
@implementation AppController &amp;#40;ShowAtOnce&amp;#41;
&amp;#160;
static NSMutableDictionary *_simulatedIVars = nil;
&amp;#160;
+&amp;#40;NSMutableDictionary *&amp;#41;_simulatedIVars&amp;#123;
	if &amp;#40;_simulatedIVars == nil&amp;#41;&amp;#123;
		_simulatedIVars = &amp;#91;&amp;#91;NSMutableDictionary alloc&amp;#93; init&amp;#93;;
	&amp;#125;
	return _simulatedIVars;
&amp;#125;
&amp;#160;
@end

2. インスタンス固有のキーストリング
上記例のアプリケーションの仕様を実現するためには、一度アラートが表示されたかどうかを調べるBOOL値を(NSMutableDictionary *)_simulatedIVarsに格納できればよさそうだ。しかし今は疑似インスタンス変数を作りたいのでAppControllerインスタンスごとに異なる値を格納できるようにする必要がある。そこでまず「AppControllerインスタンスに固有なNSStringオブジェクト」を生成するメソッドを定義する。このメソッドは-[AppController self]のストリング表現を返す。

//AppController-ShowAtOnce.m
&amp;#160;
-&amp;#40;NSString *&amp;#41;_instanceID&amp;#123;
	return &amp;#91;NSString stringWithFormat:@&amp;#34;%@&amp;#34;, self&amp;#93;;
&amp;#125;

さらに「疑似インスタンス変数名に相当するNSStringオブジェクト」を用意する。これはクラス全体で使い回しができるようにすればよい。ここではAlertHasEverBeenShownKeyStringという名前で定義しておこう。

//AppController-ShowAtOnce.m
&amp;#160;
static NSString * const AlertHasEverBeenShownKeyString = @&amp;#34;alertHasEverBeenShown&amp;#34;;

あとは「AppControllerインスタンスに固有なNSStringオブジェクト」と「疑似インスタンス変数名に相当するNSStringオブジェクト」を適当に繋げて「あるAppControllerインスタンスの疑似インスタンス変数に固有なNSStringオブジェクト」を作成するメソッドを定義する。このメソッドの返り値が(NSMutableDictionary *)_simulatedIVarsへの格納用キーストリングとして利用されるわけだ。

//AppController-ShowAtOnce.m
&amp;#160;
-&amp;#40;NSString *&amp;#41;_objectKeyForKeyString:&amp;#40;NSString *&amp;#41;aKeyString&amp;#123;
	return &amp;#91;NSString stringWithFormat:@&amp;#34;%@:%@&amp;#34;, 
		&amp;#91;self _instanceID&amp;#93;, [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.boreal-kiss.com/2010/03/07000052.html/feed</wfw:commentRss></item><item rdf:about="http://blog.boreal-kiss.com/?p=403"><title>Higher Order Messaging (HOM)</title><link>http://blog.boreal-kiss.com/2010/03/04000014.html</link><dc:subject>未分類</dc:subject><dc:subject>Cocoa</dc:subject><dc:subject>NSInvocation</dc:subject><dc:subject>NSProxy</dc:subject><dc:subject>Objective-C</dc:subject><dc:creator>borealkiss</dc:creator><dc:date>2010-03-03T07:00:14-08:00</dc:date><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h1>イントロダクション</h1>
<p><a href="http://blog.boreal-kiss.com/2010/03/02000040.html">-[NSObject performSelector:withObject]に複数の引数を渡す - boreal-kiss.com</a>で少しだけ言及していたHigher Order Messaging (HOM)の例をいくつか挙げておく。なおCocoaにおけるHOMは<a href="http://www.metaobject.com/">Metaobject</a>による<a href="http://download.cnet.com/MPWFoundation/3000-2247_4-37318.html">MPWFoundation</a>の機能の一部として利用することができる(ようである)。</p>
<h1>ケース1</h1>
<p>ボタンを押す(-[AppController buttonPressed:])とアラートを表示する(-[AppController openAlert])アプリケーションを考えよう。アプリケーションのコントローラー部分は以下のように記述されているとする。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self openAlert<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openAlert<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span>, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>1秒後にアラート表示をさせたい場合は-[NSObject performSelector:withObject:afterDelay:]を用いると以下のように書き換えることができる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>openAlert<span style="color: #002200;">&#41;</span> withObject<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>この書き方でももちろんかまわないが、HOMを用いるとメッセージ内容がより直感的に表現される。新しくNSProxyのサブクラス(DelayedTrampoline)を導入してHOM的な書き方をした場合は以下のようになる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;DelayedTrampoline.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span> openAlert<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openAlert<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert&quot;</span>, <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span>, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>DelayedTrampoline <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>afterDelay<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span>delay<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>DelayedTrampoline delayedTrampolineWithTarget<span style="color: #002200;">:</span>self 
			afterDelay<span style="color: #002200;">:</span>delay<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> DelayedTrampoline <span style="color: #002200;">:</span> <span style="color: #400080;">NSProxy</span> <span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">id</span> _target;
	NSTimeInterval _delay;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget afterDelay<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span>delay;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>delayedTrampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget afterDelay<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span>delay;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> DelayedTrampoline
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget afterDelay<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span>delay<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> aTarget;
	_delay <span style="color: #002200;">=</span> delay;
	<span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>delayedTrampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget afterDelay<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span>NSTimeInterval<span style="color: #002200;">&#41;</span>delay<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> alloc<span style="color: #002200;">&#93;</span> initWithTarget<span style="color: #002200;">:</span>aTarget 
				afterDelay<span style="color: #002200;">:</span>delay<span style="color: #002200;">&#93;</span> autorelease<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMethodSignature</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>methodSignatureForSelector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>_target methodSignatureForSelector<span style="color: #002200;">:</span>aSelector<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>forwardInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>anInvocation<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>anInvocation performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>invokeWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span> 
		withObject<span style="color: #002200;">:</span>_target afterDelay<span style="color: #002200;">:</span>_delay<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
	<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>以下に比較したい箇所だけを抜き出す。HOMの場合メッセージ(afterDelay:)の引数がメッセージ(openAlert)であるかのように書くことができることがわかる。これがHOMの&#8221;Higher Order&#8221;たる所以である。[NSObject performSelector:withObject:afterDelay:]を用いた従来の書き方よりもより直感的に理解できる表現だ。もちろん引数に書かれたメッセージは実際に引数を持つことができるため柔軟性も高い(例: <a href="http://blog.boreal-kiss.com/2010/03/02000040.html">-[NSObject performSelector:withObject]に複数の引数を渡す - boreal-kiss.com</a>)。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//Normal</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>openAlert<span style="color: #002200;">&#41;</span> withObject<span style="color: #002200;">:</span><span style="color: #a61390;">nil</span> afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//HOM</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">1.0</span><span style="color: #002200;">&#93;</span> openAlert<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<h1>ケース2</h1>
<p>HOMは同じ内容を繰り返し記述しなければならない場合などにも便利だ。例えばdelegateメソッドを実行する際にターゲットであるdelegateが実際にメソッドを実装しているか確認する次のようなコードを大量に書いて(あるいはコピペして)骨が折れた経験はないだろうか。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>delegate respondsToSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>doSomething<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>delegate doSomething<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span></pre></div></div>

<p>この場合あらかじめdelegateオブジェクトになるクラス(DelegateObject)にHOMを実装しておけば問題は回避可能だ。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;IfRespondsToTrampoline.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> DelegateObject
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IfRespondsToTrampoline <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>ifRespondsTo<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>IfRespondsToTrampoline ifRespondsToTrampolineWithTarget<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> IfRespondsToTrampoline <span style="color: #002200;">:</span> <span style="color: #400080;">NSProxy</span> <span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">id</span> _target;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>ifRespondsToTrampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget;
<span style="color: #a61390;">@end</span></pre></div></div>


<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> IfRespondsToTrampoline
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> aTarget;
	<span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>ifRespondsToTrampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> alloc<span style="color: #002200;">&#93;</span> initWithTarget<span style="color: #002200;">:</span>aTarget<span style="color: #002200;">&#93;</span> autorelease<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMethodSignature</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>methodSignatureForSelector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>_target methodSignatureForSelector<span style="color: #002200;">:</span>aSelector<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>forwardInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>anInvocation<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>anInvocation invokeWithTarget<span style="color: #002200;">:</span>_target<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
	<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>以下に比較したい箇所だけ抜粋する。delegateオブジェクトに上記のようなHOMが実装されていれば、メソッドがあれば実行、なければ何もしない(実際には内部でNSProxyによるNSInvalidArgumentExceptionが挙がる)というコードが一行で書けてしまう。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #11740a; font-style: italic;">//Normal</span>
<span style="color: #a61390;">if</span> <span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>delegate respondsToSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>doSomething<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>delegate doSomething<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//HOM</span>
<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>delegate ifRespondsTo<span style="color: #002200;">&#93;</span> doSomething<span style="color: #002200;">&#93;</span>;</pre></div></div>

]]></content:encoded><description>イントロダクション
-[NSObject performSelector:withObject]に複数の引数を渡す - boreal-kiss.comで少しだけ言及していたHigher Order Messaging (HOM)の例をいくつか挙げておく。なおCocoaにおけるHOMはMetaobjectによるMPWFoundationの機能の一部として利用することができる(ようである)。
ケース1
ボタンを押す(-[AppController buttonPressed:])とアラートを表示する(-[AppController openAlert])アプリケーションを考えよう。アプリケーションのコントローラー部分は以下のように記述されているとする。

@implementation AppController
&amp;#160;
-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	&amp;#91;self openAlert&amp;#93;;
&amp;#125;
&amp;#160;
-&amp;#40;void&amp;#41;openAlert&amp;#123;
	NSRunAlertPanel&amp;#40;@&amp;#34;Alert&amp;#34;, @&amp;#34;This is an alert&amp;#34;, @&amp;#34;OK&amp;#34;, nil, nil&amp;#41;;
&amp;#125;
&amp;#160;
@end

1秒後にアラート表示をさせたい場合は-[NSObject performSelector:withObject:afterDelay:]を用いると以下のように書き換えることができる。

-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	&amp;#91;self performSelector:@selector&amp;#40;openAlert&amp;#41; withObject:nil afterDelay:1.0&amp;#93;;
&amp;#125;

この書き方でももちろんかまわないが、HOMを用いるとメッセージ内容がより直感的に表現される。新しくNSProxyのサブクラス(DelayedTrampoline)を導入してHOM的な書き方をした場合は以下のようになる。

#import &amp;#34;DelayedTrampoline.h&amp;#34;
&amp;#160;
@implementation AppController
&amp;#160;
//New
-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	&amp;#91;&amp;#91;self afterDelay:1.0&amp;#93; openAlert&amp;#93;;
&amp;#125;
&amp;#160;
-&amp;#40;void&amp;#41;openAlert&amp;#123;
	NSRunAlertPanel&amp;#40;@&amp;#34;Alert&amp;#34;, @&amp;#34;This is an alert&amp;#34;, @&amp;#34;OK&amp;#34;, nil, nil&amp;#41;;
&amp;#125;
&amp;#160;
//New
-&amp;#40;DelayedTrampoline *&amp;#41;afterDelay:&amp;#40;NSTimeInterval&amp;#41;delay&amp;#123;
	return &amp;#91;DelayedTrampoline delayedTrampolineWithTarget:self 
			afterDelay:delay&amp;#93;;
&amp;#125;
&amp;#160;
@end


@interface DelayedTrampoline : NSProxy &amp;#123;
	id _target;
	NSTimeInterval _delay;
&amp;#125;
&amp;#160;
-&amp;#40;id&amp;#41;initWithTarget:&amp;#40;id&amp;#41;aTarget afterDelay:&amp;#40;NSTimeInterval&amp;#41;delay;
+&amp;#40;id&amp;#41;delayedTrampolineWithTarget:&amp;#40;id&amp;#41;aTarget afterDelay:&amp;#40;NSTimeInterval&amp;#41;delay;
@end


@implementation DelayedTrampoline
&amp;#160;
-&amp;#40;id&amp;#41;initWithTarget:&amp;#40;id&amp;#41;aTarget afterDelay:&amp;#40;NSTimeInterval&amp;#41;delay&amp;#123;
	_target = aTarget;
	_delay = delay;
	return self;
&amp;#125;
&amp;#160;
+&amp;#40;id&amp;#41;delayedTrampolineWithTarget:&amp;#40;id&amp;#41;aTarget afterDelay:&amp;#40;NSTimeInterval&amp;#41;delay&amp;#123;
	return &amp;#91;&amp;#91;&amp;#91;&amp;#91;self class&amp;#93; [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.boreal-kiss.com/2010/03/04000014.html/feed</wfw:commentRss></item><item rdf:about="http://blog.boreal-kiss.com/?p=397"><title>-[NSObject performSelector:withObject]に複数の引数を渡す</title><link>http://blog.boreal-kiss.com/2010/03/02000040.html</link><dc:subject>未分類</dc:subject><dc:subject>Cocoa</dc:subject><dc:subject>DesignPatterns</dc:subject><dc:subject>NSInvocation</dc:subject><dc:subject>NSProxy</dc:subject><dc:subject>Objective-C</dc:subject><dc:creator>borealkiss</dc:creator><dc:date>2010-03-01T07:00:40-08:00</dc:date><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h1>イントロダクション</h1>
<p>あるメソッドを遅延して実行したい場合、-[NSObject performSelector:withObject:afterDelay]を用いることが多々ある。しかし対象のメソッドが複数の引数を持つものであった場合、この方法は直接的には用いることができなくなってしまう。そこでNSInvocationクラスとNSProxyクラスを用いて複数引数を持つメソッドでも適用できるように工夫する。なおこの方法はHigher Order Messaging(メッセージを引数に持つメッセージという意味合い)と呼ばれる。</p>
<h1>問題の一例</h1>
<p>例えば以下のようなコントローラークラスを考える。このコントローラーではUI中のボタン(Show Alert)が押されるとアラートが表示される仕組みになっている。</p>
<pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self openAlertWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span> message<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>
		defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openAlertWithTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aTitle
				message<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aMessage
				defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aDefaultButtonTitle<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span>aTitle, aMessage, aDefaultButtonTitle, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre>
<p>このままだと、ボタンが押された途端にアラートが表示され、ボタンの描画状態がプッシュ中のままになることがわかる。気持ちわるい。</p>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2010/03/alert_nondelayed.png" alt="" title="alert_nondelayed" width="500" height="277" class="alignnone size-full wp-image-401" /></p>
<p>そこで-[NSObject performSelector:withObject:afterDelay:]を用いてアラートを遅延表示させるのが得策だろう。しかし-[NSObject performSelector:withObject:afterDelay:]では-[AppController showAlertWithTitle:message:defaultButtonTitle:]を正しく実行できない。引数が複数あるためだ。それではどうすればよいだろうか。解決策のひとつとして複数の引数をひとつにまとめてしまう方法が考えられる。</p>
<h1>NSInvocation</h1>
<p><a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html">NSInvocation</a>はメソッドをオブジェクト化したクラスである。デザインパターンで言うところの<a href="http://ja.wikipedia.org/wiki/Command_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3">Commandパターン</a>に相当するもので、これを利用することで上記問題を解決することができる。具体的には以下のような手順を踏むことになるだろう。</p>
<ol>
<li>-[NSObject performSelector:withObject:afterDelay:]で本来実行したい複数引数を持つメソッドをNSInvocationオブジェクトとしてひとつにまとめてしまう(メソッドのオブジェクト化)</li>
<li>作成したNSInvocationオブジェクトを実行するための新たなメソッド(引数はNSInvocationオブジェクトひとつのみ)を定義、それを-[NSObject performSelector:withObject:afterDelay:]で実行する。単一引数なので問題なし</li>
<li>NSInvocationオブジェクトの中身(本来実行したいメソッド)を実行する</li>
</ol>
<p>以下では新しく-[AppController openDelayedAlertWithTitle:message:defaultButtonTitle:]としてアラートの遅延表示を実現している。</p>
<pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self openDelayedAlertWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span> message<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>
		defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openAlertWithTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aTitle
	message<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aMessage
	defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aDefaultButtonTitle<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span>aTitle, aMessage, aDefaultButtonTitle, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openDelayedAlertWithTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aTitle
	message<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aMessage
	defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aDefaultButtonTitle<span style="color: #002200;">&#123;</span>
&nbsp;
	<span style="color: #400080;">NSMethodSignature</span> <span style="color: #002200;">*</span>aSignature <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span>
		instanceMethodSignatureForSelector<span style="color: #002200;">:</span>
		<span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>openAlertWithTitle<span style="color: #002200;">:</span>message<span style="color: #002200;">:</span>defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span>anInvocation <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSInvocation</span>
		invocationWithMethodSignature<span style="color: #002200;">:</span>aSignature<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>anInvocation setTarget<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>anInvocation setArgument<span style="color: #002200;">:&amp;</span>aTitle atIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">2</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>anInvocation setArgument<span style="color: #002200;">:&amp;</span>aMessage atIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">3</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>anInvocation setArgument<span style="color: #002200;">:&amp;</span>aDefaultButtonTitle atIndex<span style="color: #002200;">:</span><span style="color: #2400d9;">4</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>anInvocation setSelector<span style="color: #002200;">:</span>
		<span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>openAlertWithTitle<span style="color: #002200;">:</span>message<span style="color: #002200;">:</span>defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
	<span style="color: #002200;">&#91;</span>self performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>performInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span>
		withObject<span style="color: #002200;">:</span>anInvocation afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">0.0</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>performInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>anInvocation<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>anInvocation invokeWithTarget<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
&nbsp;
<span style="color: #a61390;">@end</span></pre>
<p>実行結果。アラート表示が遅延されボタンがプッシュ状態でなくなっているのがわかる。気持ちいい。</p>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2010/03/alert_delayed.png" alt="" title="alert_delayed" width="500" height="277" class="alignnone size-full wp-image-402" /></p>
<p>上記例からメソッドをオブジェクト化するというNSInvocationクラスの有用性が実感できた。反面、NSInvocationオブジェクトは作成するまでの手順が面倒なこともわかったと思う(例えば引数が10個あるメソッドをNSInvocationオブジェクト化するためには10回も-[NSInvocation setArgument:atIndex:]を書かないといけない)。実は適当なメッセージを送るとメッセージ内容をNSInvocationオブジェクトにしてくれる便利クラスが存在する。NSProxyだ。</p>
<h1>NSProxy</h1>
<p><a href="http://developer.apple.com/mac/library/DOCUMENTATION/Cocoa/Reference/Foundation/Classes/NSProxy_Class/Reference/Reference.html">NSProxy</a>はデザインパターンで言うところの<a href="http://ja.wikipedia.org/wiki/Proxy_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3">Proxyパターン</a>を実現するものである。NSProxyは自分が理解できないメッセージをとりあえずNSInvocationオブジェクトにしてしまうという機能を持っているのでこれを利用する。NSProxyはメッセージを受け取ると以下のような手順でNSInvocationオブジェクトを作成し、NSInvocationオブジェクトをどのように扱うのか指示を待つ。</p>
<ol>
<li>-[NSProxy methodSignatureForSelector:]を呼び出しNSMthodSignatureオブジェクトを作成する。ただしNSMethodSignatureオブジェクトを作成するための必要な情報(ターゲット etc.)はメソッド内に適切に与えてやる必要がある</li>
<li>NSMethodSignatureオブジェクトを元にNSInvocationオブジェクトを作成する</li>
<li>-[NSProxy forwardInvocation:]を呼び出しメソッド内容の指示に従う</li>
</ol>
<p>自動作成されたNSInvocationオブジェクトは-[NSProxy forwardInvocation:]の引数に渡されるので、あとはこのNSInvocationオブジェクトの扱い方を内部に記述してやればよい。以下ではNSProxyのサブクラスとしてTrampolineクラスを用いてNSInvocationオブジェクトを作成させている。AppControllerの中身の変更にも注目してもらいたい。</p>
<pre class="objc" style="font-family:monospace;"><span style="color: #6e371a;">#import &quot;Trampoline.h&quot;</span>
&nbsp;
<span style="color: #a61390;">@implementation</span> AppController
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>IBAction<span style="color: #002200;">&#41;</span>buttonPressed<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>sender<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>self openDelayedAlertWithTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Alert&quot;</span> message<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;This is an alert.&quot;</span>
		defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;OK&quot;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openAlertWithTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aTitle
	message<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aMessage
	defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aDefaultButtonTitle<span style="color: #002200;">&#123;</span>
	NSRunAlertPanel<span style="color: #002200;">&#40;</span>aTitle, aMessage, aDefaultButtonTitle, <span style="color: #a61390;">nil</span>, <span style="color: #a61390;">nil</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>openDelayedAlertWithTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aTitle
	message<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aMessage
	defaultButtonTitle<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>aDefaultButtonTitle<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self trampoline<span style="color: #002200;">&#93;</span> openAlertWithTitle<span style="color: #002200;">:</span>aTitle
		message<span style="color: #002200;">:</span>aMessage defaultButtonTitle<span style="color: #002200;">:</span>aDefaultButtonTitle<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>performInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>anInvocation<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>anInvocation invokeWithTarget<span style="color: #002200;">:</span>self<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//New</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>Trampoline <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>trampoline<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>Trampoline trampolineWithTarget<span style="color: #002200;">:</span>self
		selector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>performInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
&nbsp;
&nbsp;
<span style="color: #a61390;">@end</span></pre>
<pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@interface</span> Trampoline <span style="color: #002200;">:</span> <span style="color: #400080;">NSProxy</span> <span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">id</span> _target;
	<span style="color: #a61390;">SEL</span> _selector;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithtarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget selector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>trampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget selector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector;
&nbsp;
<span style="color: #a61390;">@end</span></pre>
<pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> Trampoline
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>initWithtarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget selector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> aTarget;
	_selector <span style="color: #002200;">=</span> aSelector;
	<span style="color: #a61390;">return</span> self;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">+</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>trampolineWithTarget<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">id</span><span style="color: #002200;">&#41;</span>aTarget selector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>self class<span style="color: #002200;">&#93;</span> alloc<span style="color: #002200;">&#93;</span> initWithtarget<span style="color: #002200;">:</span>aTarget selector<span style="color: #002200;">:</span>aSelector<span style="color: #002200;">&#93;</span>
		autorelease<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSMethodSignature</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>methodSignatureForSelector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span>aSelector<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span>_target methodSignatureForSelector<span style="color: #002200;">:</span>aSelector<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//Override</span>
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>forwardInvocation<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>anInvocation<span style="color: #002200;">&#123;</span>
	<span style="color: #002200;">&#91;</span>_target performSelector<span style="color: #002200;">:</span>_selector withObject<span style="color: #002200;">:</span>anInvocation afterDelay<span style="color: #002200;">:</span><span style="color: #2400d9;">0.0</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>dealloc<span style="color: #002200;">&#123;</span>
	_target <span style="color: #002200;">=</span> <span style="color: #a61390;">nil</span>;
	<span style="color: #002200;">&#91;</span>super dealloc<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre>
<h1>References</h1>
<ul>
<li><a href="http://www.metaobject.com/papers/Higher_Order_Messaging_OOPSLA_2005.pdf">Higher Order Messaging (pdf)</a></li>
</ul>
]]></content:encoded><description>イントロダクション
あるメソッドを遅延して実行したい場合、-[NSObject performSelector:withObject:afterDelay]を用いることが多々ある。しかし対象のメソッドが複数の引数を持つものであった場合、この方法は直接的には用いることができなくなってしまう。そこでNSInvocationクラスとNSProxyクラスを用いて複数引数を持つメソッドでも適用できるように工夫する。なおこの方法はHigher Order Messaging(メッセージを引数に持つメッセージという意味合い)と呼ばれる。
問題の一例
例えば以下のようなコントローラークラスを考える。このコントローラーではUI中のボタン(Show Alert)が押されるとアラートが表示される仕組みになっている。
@implementation AppController
&amp;#160;
-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	&amp;#91;self openAlertWithTitle:@&amp;#34;Alert&amp;#34; message:@&amp;#34;This is an alert.&amp;#34;
		defaultButtonTitle:@&amp;#34;OK&amp;#34;&amp;#93;;
&amp;#125;
&amp;#160;
-&amp;#40;void&amp;#41;openAlertWithTitle:&amp;#40;NSString *&amp;#41;aTitle
				message:&amp;#40;NSString *&amp;#41;aMessage
				defaultButtonTitle:&amp;#40;NSString *&amp;#41;aDefaultButtonTitle&amp;#123;
	NSRunAlertPanel&amp;#40;aTitle, aMessage, aDefaultButtonTitle, nil, nil&amp;#41;;
&amp;#125;
&amp;#160;
@end
このままだと、ボタンが押された途端にアラートが表示され、ボタンの描画状態がプッシュ中のままになることがわかる。気持ちわるい。

そこで-[NSObject performSelector:withObject:afterDelay:]を用いてアラートを遅延表示させるのが得策だろう。しかし-[NSObject performSelector:withObject:afterDelay:]では-[AppController showAlertWithTitle:message:defaultButtonTitle:]を正しく実行できない。引数が複数あるためだ。それではどうすればよいだろうか。解決策のひとつとして複数の引数をひとつにまとめてしまう方法が考えられる。
NSInvocation
NSInvocationはメソッドをオブジェクト化したクラスである。デザインパターンで言うところのCommandパターンに相当するもので、これを利用することで上記問題を解決することができる。具体的には以下のような手順を踏むことになるだろう。

-[NSObject performSelector:withObject:afterDelay:]で本来実行したい複数引数を持つメソッドをNSInvocationオブジェクトとしてひとつにまとめてしまう(メソッドのオブジェクト化)
作成したNSInvocationオブジェクトを実行するための新たなメソッド(引数はNSInvocationオブジェクトひとつのみ)を定義、それを-[NSObject performSelector:withObject:afterDelay:]で実行する。単一引数なので問題なし
NSInvocationオブジェクトの中身(本来実行したいメソッド)を実行する

以下では新しく-[AppController openDelayedAlertWithTitle:message:defaultButtonTitle:]としてアラートの遅延表示を実現している。
@implementation AppController
&amp;#160;
-&amp;#40;IBAction&amp;#41;buttonPressed:&amp;#40;id&amp;#41;sender&amp;#123;
	&amp;#91;self openDelayedAlertWithTitle:@&amp;#34;Alert&amp;#34; message:@&amp;#34;This is an alert.&amp;#34;
		defaultButtonTitle:@&amp;#34;OK&amp;#34;&amp;#93;;
&amp;#125;
&amp;#160;
-&amp;#40;void&amp;#41;openAlertWithTitle:&amp;#40;NSString *&amp;#41;aTitle
	message:&amp;#40;NSString *&amp;#41;aMessage
	defaultButtonTitle:&amp;#40;NSString *&amp;#41;aDefaultButtonTitle&amp;#123;
	NSRunAlertPanel&amp;#40;aTitle, aMessage, aDefaultButtonTitle, nil, nil&amp;#41;;
&amp;#125;
&amp;#160;
//New
-&amp;#40;void&amp;#41;openDelayedAlertWithTitle:&amp;#40;NSString *&amp;#41;aTitle
	message:&amp;#40;NSString *&amp;#41;aMessage
	defaultButtonTitle:&amp;#40;NSString *&amp;#41;aDefaultButtonTitle&amp;#123;
&amp;#160;
	NSMethodSignature *aSignature = &amp;#91;&amp;#91;self class&amp;#93;
		instanceMethodSignatureForSelector:
		@selector&amp;#40;openAlertWithTitle:message:defaultButtonTitle:&amp;#41;&amp;#93;;
	NSInvocation *anInvocation = &amp;#91;NSInvocation
		invocationWithMethodSignature:aSignature&amp;#93;;
	&amp;#91;anInvocation setTarget:self&amp;#93;;
	&amp;#91;anInvocation setArgument:&amp;#38;aTitle atIndex:2&amp;#93;;
	&amp;#91;anInvocation setArgument:&amp;#38;aMessage atIndex:3&amp;#93;;
	&amp;#91;anInvocation setArgument:&amp;#38;aDefaultButtonTitle atIndex:4&amp;#93;;
	&amp;#91;anInvocation setSelector:
		@selector&amp;#40;openAlertWithTitle:message:defaultButtonTitle:&amp;#41;&amp;#93;;
	&amp;#91;self [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.boreal-kiss.com/2010/03/02000040.html/feed</wfw:commentRss></item><item rdf:about="http://blog.boreal-kiss.com/?p=389"><title>[iPhone] cocos2dを静的ライブラリ化して使う</title><link>http://blog.boreal-kiss.com/2009/08/29000009.html</link><dc:subject>未分類</dc:subject><dc:subject>cocos2d</dc:subject><dc:subject>iPhone</dc:subject><dc:creator>borealkiss</dc:creator><dc:date>2009-08-28T08:00:09-07:00</dc:date><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3>[イントロダクション]</h3>
<p><a href="http://www.cocos2d-iphone.org/">cocos2d for iPhone</a>はiPhoneアプリケーション製作用のフレームワークで、主に2Dゲームを作る際の基盤に用いられているようである。UIKitより使い勝手が良いと思える点は以下の通り。</p>
<ol>
<li>オブジェクトの扱い方がFlashの感覚にかなり近い。Cocoa touch特有のframeやboundsを気にしなくてよく、-[Sprite addChild:]などおなじみの操作も行える。</li>
<li>メモリ管理をほとんど気にしなくてよい。cocos2dオブジェクトに関しては内部で適切に処理されるようになっている(ようである)。</li>
<li>シーン遷移機能が標準装備されている。エフェクトの種類も豊富。</li>
</ol>
<p>個人的にはFlash的に操作できるという点が一番の恩恵だと思っており、最近はXcodeのプロジェクト作成時にcocos2d用テンプレートしか使っていない。テンプレートを使うのであれば例えば<a href="http://www.bit-101.com/blog/?p=2115">Cocos2d &#8211; 2D OpenGL for the iPhone made Easy. Part 1.</a>に簡素なものがある。自分で作るのであれば<a href="http://iphone.longearth.net/2009/08/09/%E3%80%90xcode%E3%80%91%E8%A8%AD%E5%AE%9A%E3%81%97%E3%81%A6%E3%81%8A%E3%81%8F%E3%81%A8%E4%BE%BF%E5%88%A9%E3%81%AA%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA%E3%81%84%E3%82%8D%E3%81%84/">【Xcode】設定しておくと便利なカスタマイズいろいろ</a>が参考になる。</p>
<h4>[追記: 2009/09/02]</h4>
<p>cocos2d for iPhone v0.8.1-betaよりプロジェクトテンプレートが用意されている。詳しくは<a href="http://www.cocos2d-iphone.org/wiki/doku.php/release_notes:0_8_1_beta">release_notes:0_8_1_beta    [cocos2d for iPhone]</a>のTemplateの項参照。</p>
<h3>[本題]</h3>
<p>このCocos2d for iPhoneだが、ライブラリの状態で配布されていない。そのまま使用するのであれば大量のcocos2dソースファイルをプロジェクトに追加する形になる。これはコンパイルに結構時間がかかるし、ソースファイルに誤って書き込んでしまう可能性がある。そこでcocos2dを静的ライブラリ化することにする。以下で使用したのはcocos2d for iPhone v0.8。</p>
<h4>[手順0. その前に]</h4>
<p>実は、単純に静的ライブラリを作ってもiPhoneシミュレータとiPhone実機両方で使用することができない。というのはiPhoneシミュレータとiPhone実機のアーキテクチャ(ハードの構造)が異なるためである。したがって両者で動くようなライブラリを作るのには一工夫必要となる。</p>
<h4>[手順1. iPhoneシミュレータ用静的ライブラリを作る]</h4>
<ol>
<li>とりあえずiPhoneシミュレータ用を作る(iPhone用が先でもかまわない)。cocos2dプロジェクト内に新規Static Libraryを追加(ターゲット追加 > 新規ターゲット > Cocoa touch Static Library)、名前を&#8221;cocos2d-simulator&#8221;とする(名前はシミュレータ用であると自分でわかればなんでもよい)。</li>
<li>必要なファイル(cocos2dだけであればcocos2dフォルダ内のファイル一式)をターゲット配下に追加する。具体的には「ヘッダをコピー」にヘッダファイルを、「ソースをコンパイル」にソースファイルを、「バイナリをライブラリにリンク」に使用フレームワーク(Foundation, UIKit, CoreGraphics, OpenGLES, QuartzCoreの5種類)を追加する。
</li>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-simulator.png" alt="" title="cocos2d-simulator" width="499" height="518" class="alignnone size-full wp-image-391" /></p>
<li>ターゲット情報のアーキテクチャの項目のベースSDKを&#8221;iPhone Simulator 3.0&#8243;にする(バージョンはお好みで)。
</li>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-simulator-info.png" alt="" title="cocos2d-simulator-info" width="500" height="675" class="alignnone size-full wp-image-392" /></p>
<li>ターゲットを&#8221;cocos2d-simulator&#8221;にしてビルドするとbuild配下に&#8221;libcocos2d-simulator.a&#8221;が出来ている(シミュレータ用静的ライブラリ完成)。ReleaseバージョンやDebugバージョンなどはお好みで。</li>
</ol>
<h4>[手順2. iPhoneOS用静的ライブラリを作る]</h4>
<p>上記シミュレータ用ライブラリ作成手順とほぼ同じ。</p>
<ul>
<li>cocos2dプロジェクト内に新規Static Libraryを追加、名前を&#8221;cocos2d-iphoneos&#8221;とする(名前は適宜)。</li>
<li>ターゲット配下に必要なファイルを追加する(内容は上記シミュレータ用のものと同様)。</li>
<li>ターゲット情報のアーキテクチャの項目のベースSDKを&#8221;iPhone Device 3.0&#8243;にする(バージョンはお好みで)</li>
<li>ターゲットをビルドして&#8221;libcocos2d-iphoneos.a&#8221;を作成(iPhone用静的ライブラリ完成)。</li>
</ul>
<h4>[手順3. 上記二種類の静的ライブラリをマージする]</h4>
<p>&#8220;lipo&#8221;と呼ばれるコマンドラインツールがマージをしてくれる。詳細は<a href="http://d.hatena.ne.jp/paella/20090219/1235037185">iPhone OS用のほぼFrameworkの作り方</a>や<a href="http://dev.byteclub.com/blog/1-iphone-sdk/48-how-to-almost-create-your-own-iphone-os-framework">How to (almost) create your own iPhone OS framework</a>が詳しい。</p>
<ol>
<li>cocos2dプロジェクト内に新規Shell Script Targetを追加する(ターゲット追加 > 新規ターゲット > Other > Shell Script Target)、名前を&#8221;cocos2d-0.8&#8243;とする(名前は自分で識別できれば何でもかまわない)。
</li>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-shell-target.png" alt="" title="cocos2d-shell-target" width="499" height="518" class="alignnone size-full wp-image-393" /></p>
<li>ターゲット配下の&#8221;スクリプトを実行&#8221;に以下のコマンドを記述する。コマンドを注意深く見てもらえばわかると思うが、シミュレータ・iPhone用のライブラリ名は自分が作成したものに適宜変更する必要がある。マージ後のライブラリ名はお好みで。</li>
<pre>
rm -rf build/${BUILD_STYLE}-iphoneos/cocos2d-0.8-${BUILD_STYLE}.a

lipo -create "build/${BUILD_STYLE}-iphoneos/libcocos2d-iphoneos.a" \
"build/${BUILD_STYLE}-iphonesimulator/libcocos2d-simulator.a" \
-output "build/${BUILD_STYLE}-iphoneos/cocos2d-0.8-${BUILD_STYLE}.a"
</pre>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-shell-script.png" alt="" title="cocos2d-shell-script" width="500" height="627" class="alignnone size-full wp-image-394" /></p>
<li>ターゲットを&#8221;cocos2d-0.8&#8243;に設定してビルドするとマージされた静的ライブラリが作成される。上記のコマンドの例だと例えば&#8221;build/Release-iphoneos/libcocos2d-iphoneos.a&#8221;と&#8221;build/Release-iphonesimulator/libcocos2d-simulator.a&#8221;のファイルをマージして&#8221;build/Release-iphoneos/cocos2d-0.8-Release.a&#8221;が作成されることになる。マージされたライブラリはシミュレータでもiPhone実機でも使うことができる。</li>
</ol>
<h3>[実際の使用方法]</h3>
<p>上記手順でシミュレータでもiPhone実機でも使える静的ライブラリ&#8221;cocos2d-0.8-Release.a&#8221;ができているとする。このファイルだけでcocos2dが使えるのかと思いきや、ヘッダーファイルの実態への参照を用意しなくてはいけない。具体的には以下の二点の作業を行えばプロジェクト内でcocos2dが動作する。</p>
<ol>
<li>プロジェクトに&#8221;cocos2d-0.8-Release.a&#8221;を(例えばFrameworksの項目に)追加。</li>
<li>プロジェクト情報のヘッダ検索パスにcocos2dプロジェクト全体を追加(ファインダーからドラッグでok)。ヘッダーファイルのあるcocos2dフォルダだけでもよい(要はどこにcocos2dに関係したヘッダーファイルがあるかXcodeに教える必要があるというだけである)。ヘッダ検索オプションの&#8221;再帰的&#8221;にチェックを忘れずに。</li>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-header.png" alt="" title="cocos2d-header" width="500" height="661" class="alignnone size-full wp-image-395" /></p>
<p><img src="http://blog.boreal-kiss.com/wp/wp-content/uploads/2009/08/cocos2d-header-info.png" alt="" title="cocos2d-header-info" width="444" height="278" class="alignnone size-full wp-image-396" />
</ol>
]]></content:encoded><description>[イントロダクション]
cocos2d for iPhoneはiPhoneアプリケーション製作用のフレームワークで、主に2Dゲームを作る際の基盤に用いられているようである。UIKitより使い勝手が良いと思える点は以下の通り。

オブジェクトの扱い方がFlashの感覚にかなり近い。Cocoa touch特有のframeやboundsを気にしなくてよく、-[Sprite addChild:]などおなじみの操作も行える。
メモリ管理をほとんど気にしなくてよい。cocos2dオブジェクトに関しては内部で適切に処理されるようになっている(ようである)。
シーン遷移機能が標準装備されている。エフェクトの種類も豊富。

個人的にはFlash的に操作できるという点が一番の恩恵だと思っており、最近はXcodeのプロジェクト作成時にcocos2d用テンプレートしか使っていない。テンプレートを使うのであれば例えばCocos2d &amp;#8211; 2D OpenGL for the iPhone made Easy. Part 1.に簡素なものがある。自分で作るのであれば【Xcode】設定しておくと便利なカスタマイズいろいろが参考になる。
[追記: 2009/09/02]
cocos2d for iPhone v0.8.1-betaよりプロジェクトテンプレートが用意されている。詳しくはrelease_notes:0_8_1_beta    [cocos2d for iPhone]のTemplateの項参照。
[本題]
このCocos2d for iPhoneだが、ライブラリの状態で配布されていない。そのまま使用するのであれば大量のcocos2dソースファイルをプロジェクトに追加する形になる。これはコンパイルに結構時間がかかるし、ソースファイルに誤って書き込んでしまう可能性がある。そこでcocos2dを静的ライブラリ化することにする。以下で使用したのはcocos2d for iPhone v0.8。
[手順0. その前に]
実は、単純に静的ライブラリを作ってもiPhoneシミュレータとiPhone実機両方で使用することができない。というのはiPhoneシミュレータとiPhone実機のアーキテクチャ(ハードの構造)が異なるためである。したがって両者で動くようなライブラリを作るのには一工夫必要となる。
[手順1. iPhoneシミュレータ用静的ライブラリを作る]

とりあえずiPhoneシミュレータ用を作る(iPhone用が先でもかまわない)。cocos2dプロジェクト内に新規Static Libraryを追加(ターゲット追加 &gt; 新規ターゲット &gt; Cocoa touch Static Library)、名前を&amp;#8221;cocos2d-simulator&amp;#8221;とする(名前はシミュレータ用であると自分でわかればなんでもよい)。
必要なファイル(cocos2dだけであればcocos2dフォルダ内のファイル一式)をターゲット配下に追加する。具体的には「ヘッダをコピー」にヘッダファイルを、「ソースをコンパイル」にソースファイルを、「バイナリをライブラリにリンク」に使用フレームワーク(Foundation, UIKit, CoreGraphics, OpenGLES, QuartzCoreの5種類)を追加する。


ターゲット情報のアーキテクチャの項目のベースSDKを&amp;#8221;iPhone Simulator 3.0&amp;#8243;にする(バージョンはお好みで)。


ターゲットを&amp;#8221;cocos2d-simulator&amp;#8221;にしてビルドするとbuild配下に&amp;#8221;libcocos2d-simulator.a&amp;#8221;が出来ている(シミュレータ用静的ライブラリ完成)。ReleaseバージョンやDebugバージョンなどはお好みで。

[手順2. iPhoneOS用静的ライブラリを作る]
上記シミュレータ用ライブラリ作成手順とほぼ同じ。

cocos2dプロジェクト内に新規Static Libraryを追加、名前を&amp;#8221;cocos2d-iphoneos&amp;#8221;とする(名前は適宜)。
ターゲット配下に必要なファイルを追加する(内容は上記シミュレータ用のものと同様)。
ターゲット情報のアーキテクチャの項目のベースSDKを&amp;#8221;iPhone Device 3.0&amp;#8243;にする(バージョンはお好みで)
ターゲットをビルドして&amp;#8221;libcocos2d-iphoneos.a&amp;#8221;を作成(iPhone用静的ライブラリ完成)。

[手順3. 上記二種類の静的ライブラリをマージする]
&amp;#8220;lipo&amp;#8221;と呼ばれるコマンドラインツールがマージをしてくれる。詳細はiPhone OS用のほぼFrameworkの作り方やHow to (almost) create [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.boreal-kiss.com/2009/08/29000009.html/feed</wfw:commentRss></item><item rdf:about="http://blog.boreal-kiss.com/?p=388"><title>-[NSObject performSelector:]の返り値</title><link>http://blog.boreal-kiss.com/2009/08/28000038.html</link><dc:subject>未分類</dc:subject><dc:subject>Cocoa</dc:subject><dc:subject>iPhone</dc:subject><dc:subject>Objective-C</dc:subject><dc:creator>borealkiss</dc:creator><dc:date>2009-08-27T08:00:38-07:00</dc:date><content:encoded xmlns:content="http://purl.org/rss/1.0/modules/content/"><![CDATA[<h3>まとめ</h3>
<ul>
<li>-[NSObject performSelector:]の返り値として不適切なものが存在する。</li>
<li>それら不適切なものを扱う場合の対処法について。</li>
</ul>
<h3>イントロダクション</h3>
<p>NSObjectのインスタンスメソッド</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #002200;">-</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">void</span><span style="color: #002200;">&#41;</span>performSelector<span style="color: #002200;">:</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">SEL</span><span style="color: #002200;">&#41;</span> aSelector</pre></div></div>

<p>はvoid型となっているが、「引数にセットされたメソッドの返り値」を自分の返り値に持つことができる。ただしその場合、-[NSObject performSelector:]の返り値はid型(オブジェクトポインタ)になるので適切にキャストしてやる必要がある。例えば、以下のようなNSStringを返すメソッドを持つTest1クラスを考える。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> Test1
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>stringValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;Hello&quot;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>このTest1クラスに-[NSObject performSelector:]を使って-[Test1 stringValue]を呼び、NSStringにキャストして返り値を受け取るとたしかに@&#8221;Hello&#8221;が返ってきていることがわかる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">Test1 <span style="color: #002200;">*</span>test1 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>Test1 alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
<span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span>stringValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span>test1 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>stringValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, stringValue<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// Hello</span></pre></div></div>

<h3>本題</h3>
<p>-[NSObject performSelector:]の返り値はid型であり、id型はオブジェクトへのポインタであると説明した。つまり、-[NSObject performSelector:]は「オブジェクトではないものを返り値とするメソッド」の返り値を受け取ることができない可能性があることがわかる。例を見てみよう。Test2クラスに以下のようなメソッドがあるとする。どのメソッドの返り値もオブジェクトではない。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> Test2
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span>boolValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #a61390;">YES</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span>intValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #2400d9;">10</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span>floatValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #2400d9;">2.0</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span>CGPoint<span style="color: #002200;">&#41;</span>point<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">100.0</span>, <span style="color: #2400d9;">100.0</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>先ほどと同様にこれらのメソッドを-[NSObject performSelector:]を使って呼び出し、返り値を確認すると以下のような結果になった。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">Test2 <span style="color: #002200;">*</span>test2 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>Test2 alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">//warning: cast from pointer to integer of different size</span>
<span style="color: #a61390;">BOOL</span> boolValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">BOOL</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span>test2 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>boolValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%i&quot;</span>, boolValue<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 1</span>
&nbsp;
<span style="color: #a61390;">int</span> intValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">int</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span>test2 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>intValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%i&quot;</span>, intValue<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 10</span>
&nbsp;
<span style="color: #11740a; font-style: italic;">//error: pointer value used where a floating point value was expected</span>
<span style="color: #a61390;">float</span> floatValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span><span style="color: #a61390;">float</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span>test2 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>floatValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%f&quot;</span>, floatValue<span style="color: #002200;">&#41;</span>;
&nbsp;
<span style="color: #11740a; font-style: italic;">//error: conversion to non-scalar type requested</span>
CGPoint point <span style="color: #002200;">=</span> <span style="color: #002200;">&#40;</span>CGPoint<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#91;</span>test2 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>point<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, NSStringFromCGPoint<span style="color: #002200;">&#40;</span>point<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;</pre></div></div>

<p>結果をまとめると以下のようになる。</p>
<ul>
<li>返り値BOOLについては警告が出たが返り値の受け取りができた。</li>
<li>返り値intについては警告は出ず返り値の受け取りができた。</li>
<li>返り値floatについてはコンパイルエラーが生じ実行できなかった。</li>
<li>返り値CGPointについてはコンパイルエラーが生じ実行できなかった。</li>
</ul>
<h3>対処法</h3>
<p>上記のテスト結果から、-[NSObject performSelector:]から「オブジェクトではないものを返り値とするメソッド」の返り値を受け取るためには何かしらの工夫をしなければならないことがわかった(int型・BOOL型などの例外もある)。以下に二種類の対処法を挙げておく。</p>
<ol>
<li>-[NSObject performSelector:]で呼び出すメソッドの返り値をオブジェクトにしておく。</li>
<li>-[NSObject performSelector:]の代わりに[NSInvocation invoke]を用いる。</li>
</ol>
<p>順に見てみよう。</p>
<h4>対処法1</h4>
<p>二つ目の対処法より簡単である。返り値int, BOOL, floatについてはNSNumberオブジェクトによるラッピング、返り値CGPoint(CGRect, CGSizeなども含む)についてはNSStringオブジェクトに変換することで簡単に対処できる。以下に、Test2クラスの4メソッドの返り値を全てオブジェクトに変更したTest3クラスを挙げる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;"><span style="color: #a61390;">@implementation</span> Test3
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>boolValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithBool<span style="color: #002200;">:</span><span style="color: #a61390;">YES</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>intValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithInt<span style="color: #002200;">:</span><span style="color: #2400d9;">10</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSNumber</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>floatValue<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSNumber</span> numberWithFloat<span style="color: #002200;">:</span><span style="color: #2400d9;">2.0</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #002200;">-</span><span style="color: #002200;">&#40;</span><span style="color: #400080;">NSString</span> <span style="color: #002200;">*</span><span style="color: #002200;">&#41;</span>point<span style="color: #002200;">&#123;</span>
	<span style="color: #a61390;">return</span> NSStringFromCGPoint<span style="color: #002200;">&#40;</span>CGPointMake<span style="color: #002200;">&#40;</span><span style="color: #2400d9;">100.0</span>, <span style="color: #2400d9;">100.0</span><span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;
<span style="color: #002200;">&#125;</span>
&nbsp;
<span style="color: #a61390;">@end</span></pre></div></div>

<p>この場合、各メソッドの返り値はオブジェクトであるため、それらオブジェクトから必要な値を復元してやればよい。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">Test3 <span style="color: #002200;">*</span>test3 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>Test3 alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #a61390;">BOOL</span> boolValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>test3 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>boolValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span> boolValue<span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%i&quot;</span>, boolValue2<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 1</span>
&nbsp;
<span style="color: #a61390;">int</span> intValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>test3 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>intValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span> intValue<span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%i&quot;</span>, intValue2<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 10</span>
&nbsp;
<span style="color: #a61390;">float</span> floatValue <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>test3 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>floatValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span> floatValue<span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%f&quot;</span>, floatValue2<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 2.000000</span>
&nbsp;
CGPoint point <span style="color: #002200;">=</span> CGPointFromString<span style="color: #002200;">&#40;</span><span style="color: #002200;">&#91;</span>test3 performSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>point<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span><span style="color: #002200;">&#41;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%@&quot;</span>, NSStringFromCGPoint<span style="color: #002200;">&#40;</span>point2<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// {100, 100}</span></pre></div></div>

<h4>対処法2</h4>
<p>-[NSObject performSelector:]の代わりにNSInvocationを用いると、返り値がオブジェクトであろうとなかろうと受け取ることが可能になる。例えば、-[Test2 floatValue]の返り値を受け取る場合には、以下のような手続きをとる。</p>

<div class="wp_syntax"><div class="code"><pre class="objc" style="font-family:monospace;">Test2 <span style="color: #002200;">*</span>test2 <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>Test2 alloc<span style="color: #002200;">&#93;</span> init<span style="color: #002200;">&#93;</span>;
&nbsp;
<span style="color: #a61390;">float</span> floatValue;
<span style="color: #400080;">NSMethodSignature</span> <span style="color: #002200;">*</span>aSigniture 
        <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #002200;">&#91;</span>test2 class<span style="color: #002200;">&#93;</span> instanceMethodSignatureForSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>floatValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #400080;">NSInvocation</span> <span style="color: #002200;">*</span>anInvocation 
        <span style="color: #002200;">=</span> <span style="color: #002200;">&#91;</span><span style="color: #400080;">NSInvocation</span> invocationWithMethodSignature<span style="color: #002200;">:</span>aSigniture<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>anInvocation setSelector<span style="color: #002200;">:</span><span style="color: #a61390;">@selector</span><span style="color: #002200;">&#40;</span>floatValue<span style="color: #002200;">&#41;</span><span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>anInvocation setTarget<span style="color: #002200;">:</span>test2<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>anInvocation invoke<span style="color: #002200;">&#93;</span>;
<span style="color: #002200;">&#91;</span>anInvocation getReturnValue<span style="color: #002200;">:&amp;</span>floatValue<span style="color: #002200;">&#93;</span>;
NSLog<span style="color: #002200;">&#40;</span><span style="color: #bf1d1a;">@</span><span style="color: #bf1d1a;">&quot;%f&quot;</span>, floatValue<span style="color: #002200;">&#41;</span>;<span style="color: #11740a; font-style: italic;">// 2.000000</span></pre></div></div>

<p>NSInvocationを用いると汎用性は高くなるが、一般的にソースが煩雑になる。</p>
<h3>参考</h3>
<ul>
<li><a href="http://objective-audio.jp/2008/06/nsinvocation.html">NSInvocationの作成 - Objective-Audio</a></li>
</ul>
]]></content:encoded><description>まとめ

-[NSObject performSelector:]の返り値として不適切なものが存在する。
それら不適切なものを扱う場合の対処法について。

イントロダクション
NSObjectのインスタンスメソッド

- &amp;#40;void&amp;#41;performSelector:&amp;#40;SEL&amp;#41; aSelector

はvoid型となっているが、「引数にセットされたメソッドの返り値」を自分の返り値に持つことができる。ただしその場合、-[NSObject performSelector:]の返り値はid型(オブジェクトポインタ)になるので適切にキャストしてやる必要がある。例えば、以下のようなNSStringを返すメソッドを持つTest1クラスを考える。

@implementation Test1
&amp;#160;
-&amp;#40;NSString *&amp;#41;stringValue&amp;#123;
	return @&amp;#34;Hello&amp;#34;;
&amp;#125;
&amp;#160;
@end

このTest1クラスに-[NSObject performSelector:]を使って-[Test1 stringValue]を呼び、NSStringにキャストして返り値を受け取るとたしかに@&amp;#8221;Hello&amp;#8221;が返ってきていることがわかる。

Test1 *test1 = &amp;#91;&amp;#91;Test1 alloc&amp;#93; init&amp;#93;;
NSString *stringValue = &amp;#40;NSString *&amp;#41;&amp;#91;test1 performSelector:@selector&amp;#40;stringValue&amp;#41;&amp;#93;;
NSLog&amp;#40;@&amp;#34;%@&amp;#34;, stringValue&amp;#41;;// Hello

本題
-[NSObject performSelector:]の返り値はid型であり、id型はオブジェクトへのポインタであると説明した。つまり、-[NSObject performSelector:]は「オブジェクトではないものを返り値とするメソッド」の返り値を受け取ることができない可能性があることがわかる。例を見てみよう。Test2クラスに以下のようなメソッドがあるとする。どのメソッドの返り値もオブジェクトではない。

@implementation Test2
&amp;#160;
-&amp;#40;BOOL&amp;#41;boolValue&amp;#123;
	return YES;
&amp;#125;
&amp;#160;
-&amp;#40;int&amp;#41;intValue&amp;#123;
	return 10;
&amp;#125;
&amp;#160;
-&amp;#40;float&amp;#41;floatValue&amp;#123;
	return 2.0;
&amp;#125;
&amp;#160;
-&amp;#40;CGPoint&amp;#41;point&amp;#123;
	return CGPointMake&amp;#40;100.0, 100.0&amp;#41;;
&amp;#125;
&amp;#160;
@end

先ほどと同様にこれらのメソッドを-[NSObject performSelector:]を使って呼び出し、返り値を確認すると以下のような結果になった。

Test2 *test2 = &amp;#91;&amp;#91;Test2 alloc&amp;#93; init&amp;#93;;
&amp;#160;
//warning: cast from pointer to integer of different size
BOOL boolValue = &amp;#40;BOOL&amp;#41;&amp;#91;test2 performSelector:@selector&amp;#40;boolValue&amp;#41;&amp;#93;;
NSLog&amp;#40;@&amp;#34;%i&amp;#34;, boolValue&amp;#41;;// 1
&amp;#160;
int intValue = &amp;#40;int&amp;#41;&amp;#91;test2 performSelector:@selector&amp;#40;intValue&amp;#41;&amp;#93;;
NSLog&amp;#40;@&amp;#34;%i&amp;#34;, intValue&amp;#41;;// [...]</description><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blog.boreal-kiss.com/2009/08/28000038.html/feed</wfw:commentRss></item></rdf:RDF>
