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

<channel>
	<title>ほげぐらまの別館 &#187; setNeedsDisplay</title>
	<atom:link href="http://lain.heavy.jp/lain/tag/setneedsdisplay/feed" rel="self" type="application/rss+xml" />
	<link>http://lain.heavy.jp/lain</link>
	<description>プログラムに限らずてきとーに、ね？</description>
	<lastBuildDate>Sat, 29 Aug 2015 14:47:38 +0000</lastBuildDate>
	<language>ja</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.7.41</generator>
	<item>
		<title>iOSのコントロールを即時で描画更新させる</title>
		<link>http://lain.heavy.jp/lain/2011/10/01/217</link>
		<comments>http://lain.heavy.jp/lain/2011/10/01/217#comments</comments>
		<pubDate>Sat, 01 Oct 2011 02:58:13 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[NSRunLoop]]></category>
		<category><![CDATA[runUntilDate]]></category>
		<category><![CDATA[setNeedsDisplay]]></category>
		<category><![CDATA[再描画]]></category>
		<category><![CDATA[強制]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/10/01/217</guid>
		<description><![CDATA[iOSのプログラムをしていたらひょんな事にハマりました。処理の例としては以下の感じ。 ユーザーに「DOWNLOAD」ボタンを押させる NSURLConnection:sendAsynchronousRequest:que [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>iOSのプログラムをしていたらひょんな事にハマりました。処理の例としては以下の感じ。</p>
<ol>
<li>ユーザーに「DOWNLOAD」ボタンを押させる  </li>
<li><strong>NSURLConnection:sendAsynchronousRequest:queue:completionHandler:</strong>を使って<strong>非同期的に</strong>所定の<strong>NSURLRequest</strong>にリクエストを送信、<strong>NSData</strong>を取得する (もちろん、NSDataで受信時はプログレスバーを更新する)  </li>
<li>NSDataをGZipのストリームと判断し解凍する  </li>
<li>2～3の操作を数回繰り返す</li>
</ol>
<p>2. で受信プログレスを更新する際にはUIProgressView.progressにより随時更新の後、100%＝1.0の場合はそのまま解凍処理を走らせるのだから処理上では問題ないですが、以下のプログラムにすると恐らくプログレスバーが100%にならないです。</p>
<p>
<pre>
<pre class="brush: plain; title: ; notranslate">
// TODO: 受信したデータを結合する
...(略)...

// プログレスバーを更新する
_progressView.progress = CLAMP([data length] / filesize, 0.0f, 1.0f);
if ([data length] &lt; filesize) { return; }

// TODO: 100%ダウンロードできたので解凍処理をする
...(略)...

// 次のダウンローダをリクエストする
[self requestNextRequest];

</pre>
</p>
<p>処理が連続する場合にコントロールの再描画が必要となるプロパティ変更を行っても即時で再描画されない、言い換えれば、<strong>UIView:setNeedsDisplayが画面に対して即時処理されない</strong>ということ、です。ここでWindowsの話を持ち出すのはナンセンスだとは思っていますが、あえて出させてもらうと<strong>InvalidateRect(HWND, LPRECT, BOOL)</strong>だけコールして<strong>UpdateWindow(HWND)</strong>をコールしてない事になります。さて、ではどのようにiOSのコントロールを再描画させるか。あ、ちなみに間違っても<strong>UIView:drawRect:</strong>を直接コールしないでねっ！</p>
<p>答えは簡単、NSRunLoop:runUntilDate:をコールして現在のRunLoopに対して処理のゆとり？を与えるということ。再描画フラグ自体は立っているのでその処理時間を与える、というイメージだと思われます(iOS専門ぢゃないから怪しいけど)。引数がNSDateなのでどこまでの時間を渡せばいいかということですが、かなり適当です。</p>
<p>
<pre>
<pre class="brush: plain; title: ; notranslate">
// TODO: 受信したデータを結合する
...(略)...


// プログレスバーを更新する
_progressView.progress = CLAMP([data length] / filesize, 0.0f, 1.0f);
if ([data length] &lt; filesize) {
    return;
}

// 解凍処理(しばらくの間の重い処理)に入る前に、再描画をさせる
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];

// TODO: 100%ダウンロードできたので解凍処理をする
...(略)...


// 次のダウンローダをリクエストする
[self requestNextRequest];

</pre>
</p>
<p>という感じ。</p>
<p>0.05＝50ミリ秒ですが、これで十分だと思われます。10ミリ秒でもiPod Touch 4genでは正常に再描画されましたので、恐らくそれでも大丈夫だと思います。</p>
<p>あ、後、CLAMPマクロは独自定義なのであしから。やってることは #define CLAMP(v, x, y) MIN(MAX((v), (x)), (y)) なだけです。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/10/01/217/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
