<?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; Objective-C</title>
	<atom:link href="http://lain.heavy.jp/lain/category/computer/program/objective-c/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/2012/04/09/548</link>
		<comments>http://lain.heavy.jp/lain/2012/04/09/548#comments</comments>
		<pubDate>Sun, 08 Apr 2012 15:12:58 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[APNS]]></category>
		<category><![CDATA[ios]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2012/04/09/548</guid>
		<description><![CDATA[以前の記事、「プッシュ通知(APNs)の初期確認ダイアログについて」の続き。今になってはじめて気がついたというか、前々から変だと思っていたけど端末のせいにして自分は悪くない！と思っていた自分が一番馬鹿だった、というもので [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>以前の記事、「<a href="http://lain.heavy.jp/lain/2012/01/28/473" target="_blank">プッシュ通知(APNs)の初期確認ダイアログについて</a>」の続き。今になってはじめて気がついたというか、前々から変だと思っていたけど端末のせいにして自分は悪くない！と思っていた自分が一番馬鹿だった、というものです。</p>
<p>&nbsp;</p>
<p>プッシュ通知の確認ダイアログ自体は書いたとおり一度しか表示されない、というのは変わらないのです。が、特定の再通知条件を満たさない間に再インストールするとデバイストークンが取得できないというものです。特殊なパターンなので具体的な例で言えば、</p>
<ol>
<li>enabledRemoteNotificationTypesをコールして現在のプッシュ通知が有効かどうかを調べる</li>
<li><strong><font color="#ff0000">有効なtypeがない場合に</font></strong>registerForRemoteNotificationTypesをコールして通知ダイアログを表示する</li>
<li>アプリケーションを再インストールする</li>
<li>enabledRemoteNotificationTypesの値は正常なのにデバイストークンの値が取れない</li>
</ol>
<p>というパターン。確認する限りは、再インストールの場合は既に[設定]上にプッシュ通知が有効になっているものの再度enabledRemoteNotificationTypesをコールしないとdidRegisterForRemoteNotificationsWithDeviceTokenがコールされないようで、これがデバイストークンの値を取得できない要因となっていたようです。なので、解決策としては2.で既に有効になっていてもregisterForRemoteNotificationTypesをコールする、ってのが手っ取り早い模様。</p>
<p>何も考えずにそれをコールしていればこんなにハマることはなかったのでしょうが、何かを変えるということはそれだけリスクを伴う場合があるってことですね。いい勉強になりました。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2012/04/09/548/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>プッシュ通知(APNs)の初期確認ダイアログについて</title>
		<link>http://lain.heavy.jp/lain/2012/01/28/473</link>
		<comments>http://lain.heavy.jp/lain/2012/01/28/473#comments</comments>
		<pubDate>Sat, 28 Jan 2012 08:53:02 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[APNS]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2012/01/28/473</guid>
		<description><![CDATA[iOS環境ではプッシュ通知が重要だよ、的な周り口で1セッションの通信において複数デバイスにプッシュ通知を行うという記事を投稿しました(因みに自分ではまだやってないのですけどね、同僚が私の作ったモジュールを使って動いている [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>iOS環境ではプッシュ通知が重要だよ、的な周り口で1セッションの通信において<a href="http://lain.heavy.jp/lain/2011/11/14/312">複数デバイスにプッシュ通知を行う</a>という記事を投稿しました(因みに自分ではまだやってないのですけどね、同僚が私の作ったモジュールを使って動いているよ～って言ってるから動いているのでしょう)。</p>
<p>プッシュ通知は重要ながらもチュートリアル的な実装をそのままコピペで実装してしまうと優れた機能も非常に残念なことになります。というのも、例えばよくあるパターンではゲームに対してプッシュ通知が実装されている場合、タイトル画面といった起動した瞬間に「○○はプッシュ通知を送信します。よろしいですか？」と出現するパターン(<strong>画像はあくまでサンプル画面です</strong>が、実際に私が指摘する最悪なパターンを再現してくれたものです)。</p>
<p><a href="http://lain.heavy.jp/lain/wp-content/uploads/apns_dialog.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px; padding-top: 0px" title="apns_dialog" border="0" alt="apns_dialog" src="http://lain.heavy.jp/lain/wp-content/uploads/apns_dialog_thumb.jpg" width="324" height="484"/></a></p>
<p>少しはユーザのことを考えればわかることですが、これって開発側からのエゴの何物でもないですよね。だって、リアルな環境に置き換えるならば、試供品を受け取った段階で</p>
<p align="center"><font color="#ff0000" size="4"><strong>とりあえずDM(ダイレクトメール)送りたいんだけど受け取りますか？</strong></font></p>
<p>と言われているに近しいものだと思うのです。</p>
<p>因みに私はこのパターンは絶対にプッシュ通知を許可しません。だってウザったいかもしれない通知が来るかもしれないのにそれを許可する理由なんてないですから。</p>
<p>&nbsp;</p>
<p>ってことで、長々とウンチクを垂れましたが、端的に言えばプッシュ通知をすべき場所を今一度見直して、細かく制御しましょうよ、と。プッシュ通知はUIAPplicationのインスタンスメソッドとして定義されていて以下の3つがあります。</p>
<ul>
<li><strong>registerForRemoteNotificationTypes</strong>…プッシュ通知を有効にしようとします。ユーザにダイアログでプッシュ通知の確認が求められます  </li>
<li><strong>unregisterForRemoteNotifications</strong>…登録されたプッシュ通知を破棄します  </li>
<li><strong>enabledRemoteNotificationTypes</strong>…(どのような種類の)プッシュ通知が有効かどうかを取得します</li>
</ul>
<p>なので、チュートリアル通りにapplication:didFinishLaunchingWithOptions:でregisterForRemoteNotificationTypesをコールするのではなくて、<strong>どのような目的でプッシュ通知を行いたいかを述べたうえで初めてregisterForRemoteNotificationTypesをコールしましょう</strong>、と。これをやっているのがGameloftの”レッツ！ゴルフ3”ですね。</p>
<p><em></em>&nbsp;</p>
<p>・・・・、と<strong>ここまでが前置き</strong>。そしてようやくタイトルの話になります。上述の通りにプッシュ通知のダイアログが出るタイミングというのは非常に貴重なもので、本当にこのタイミングでよいのかどうかを試験したい場合がありますが、一度この確認でどちらかを選択してしまうと開発中でも中々出てくれません。で、かるーくググってみると大好きなStackoverflowでこんな投稿がありました。</p>
<ul>
<li><a href="http://stackoverflow.com/questions/2438400/reset-push-notification-settings-for-app"><font size="3">Reset push notification settings for app</font></a><font size="3"> (Stackoverflow)</font></li>
</ul>
<p>相変わらずの精度が低いほげ脳内翻訳によれば</p>
<blockquote><p>アプリケーションが初回にプッシュ通知を有効にしようとするならば、iOSはユーザにアプリケーションから通知を受け取るか否かを確認します。一度でもその警告(プッシュ通知の同意ダイアログ)に応答した場合は、デバイスをリストアするか、若しくはアンインストールを行ったうえで少なくとも1日以上経過する必要があるでしょう。</p>
<p>もしあなたが初回のプッシュ通知をシミュレートしたいとするならばアンインストールを行ったうえで1日経過させる必要があります。但し、<em><font color="#ff0000">システムクロックを1日以上経過させたうえで一度デバイスをシャットダウンし、再度デバイスを起動することで後者(=アンインストール後に1日以上経過するという条件)を満たすことができるでしょう</font>。</em></p>
</blockquote>
<p>と書いた本人ですが、実際に試していないのであしからず。</p>
<p>&nbsp;</p>
<p>今回の記事をまとめるとこんな感じ</p>
<ul>
<li>プッシュ通知はアプリケーションが非アクティブ状態でもアプリ提供者側からユーザに情報通知が可能な数少ない手段です。</li>
<li>ダイアログを表示することでプッシュ通知の同意を求める貴重なアプローチは1回のみです。もし本当にプッシュ通知を利用して欲しいのであればこのアプローチを行う前にユーザにプッシュ通知を行う利便性を説くべきでしょう。</li>
<li>プッシュ通知は登録(登録要求)・解除・状態取得の3つのメソッドがあります。</li>
<li>プッシュ通知の初回のアプローチはstackoverflowに書かれているような方法で再度確認を行うことができる(はず)です。アプリの提出前に本当にユーザが望ましい形でそのアプローチが行われているか確認しましょう。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2012/01/28/473/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objective-Cとブロック構文</title>
		<link>http://lain.heavy.jp/lain/2011/11/24/337</link>
		<comments>http://lain.heavy.jp/lain/2011/11/24/337#comments</comments>
		<pubDate>Thu, 24 Nov 2011 13:00:00 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[ブロック構文]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/11/24/337</guid>
		<description><![CDATA[如何にもプログラマチックなタイトルですが、何のことは無い！　自分がほげグラムをする中でこれはブロック構文にしたほうが明らかに美しいと思われる部分を適当に選んだもの。 UIAlertView(alertView:didDi [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>如何にもプログラマチックなタイトルですが、何のことは無い！　自分がほげグラムをする中でこれはブロック構文にしたほうが明らかに美しいと思われる部分を適当に選んだもの。</p>
<ul>
<li>UIAlertView(<strong>alertView:didDismissWithButtonIndex:)…</strong>アラートビューのボタン押下が決定した瞬間に通知されるデリゲートイベント。<a href="https://github.com/jivadevoe/UIAlertView-Blocks">UIAlertView-Blocks</a>とか<a href="https://github.com/MugunthKumar/UIKitCategoryAdditions">UIKitCategoryAdditions</a>が使えるらしい</li>
<li>SKPaymentKit(<strong>paymentQueue:updatedTransactions</strong> <img src='http://lain.heavy.jp/lain/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> …マネタイズが必須なプロジェクトで使いまわしたいけど、ということで<a href="http://lain.heavy.jp/lain/2011/11/08/310">サンプル的に自分の過去ログ</a></li>
<li>UIView Animation (<strong>animateWithDuration:animations:</strong>)…iOS4.0以降で新規に追加されたプロトコル。多分、<a href="http://stackoverflow.com/questions/3237431/does-animatewithdurationanimations-block-main-thread">does animateWithDuration:animations: block main thread?</a>あたりが有用かもしれない</li>
<li>NSURLConnection (<strong>connection:didReceiveResponse:</strong>, <strong>connection:didFailWithError:</strong>, <strong>connection:didReceiveData:</strong>, <strong>connectionDidFinishLoading:</strong>)…NSURLConnectionの非同期通信を使ったときに、非常に煩雑になる部分で有用だと思われるstackverflow投稿より<a href="http://stackoverflow.com/questions/5037545/nsurlconnection-and-grand-central-dispatch">NSURLConnection and grand central dispatch</a></li>
</ul>
<p>リンク先の記事の内容をすべて実践したわけではないので本当に使えるかどうか、については保証しかねますということと、私が関わったほんの一部であり、CoreAudioフレームワークのAudioBufferあたりはブロック構文にしても良いかもしれないかな、とか。</p>
<p>一方で、ブロック構文には気を付けるべきことが幾つかあるようなので(といっても有用なページが見つけられず案内できませんが)、使う前には予めその性質を理解しておくことも重要ですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/11/24/337/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Objective-Cのブロック構文</title>
		<link>http://lain.heavy.jp/lain/2011/11/08/310</link>
		<comments>http://lain.heavy.jp/lain/2011/11/08/310#comments</comments>
		<pubDate>Tue, 08 Nov 2011 14:51:55 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[コールバック]]></category>
		<category><![CDATA[ブロック構文]]></category>

		<guid isPermaLink="false">https://lain.heavy.jp/lain/2011/11/08/310</guid>
		<description><![CDATA[iOS AppのInAppPurchaseの処理、となると大抵の場合はAppleから提供されているサンプルコードを利用すれば異なります。もちろん私もこのコードを使いながらも自分が使いやすいように購入部分のみをシングルトン [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>iOS AppのInAppPurchaseの処理、となると大抵の場合は<a href="http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/AddingaStoretoYourApplication/AddingaStoretoYourApplication.html">Appleから提供されているサンプルコード</a>を利用すれば異なります。もちろん私もこのコードを使いながらも自分が使いやすいように購入部分のみをシングルトンクラスへ処理を移して、</p>
<pre><pre class="brush: plain; title: ; notranslate">

Environment *environment = [Environment instance]
assert(environment);

BOOL request = [environment requestPurchase:@&quot;MY_PRODUCT_ID&quot;];
if (request == NO) { 
  UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:....] autorelease];
  [alert show];
}

</pre>
<p>&nbsp;</p>
<p>のようなコードを打てば好きなタイミングでプロダクトIDさえ渡せば処理は勝手にやってくれます。購入後にサーバ側で購入に対するデータ処理は行ってくれるので特にクライアントはそれ以上の処理が必要ないぢゃんと踏んでいたのですが・・・・。バカだったと反省した今日この頃です。となると、最終的にAppleサンプルでいうcompleteTransaction, failedTransactionの部分にデリゲートをコールするなんていう仕掛けを追加しなければならないのですが、結構デリゲート嫌いなんです。特に、今回のような1デリゲートに1プロトコルしか必要のない時は。</p>
<p>ここで思い出したのが、最近GameCenterで見かけたコール部分に関数定義を渡すような方法。この名前を知らずにググっていたらStackoverflowに引っかかりました。</p>
<ul>
<li><a href="http://stackoverflow.com/questions/1015608/how-to-perform-callbacks-in-objective-c">How to perform Callbacks in Objective-C</a>
</li>
<li><a href="http://stackoverflow.com/questions/4824038/how-to-simplify-callback-logic-with-a-block">How to simplify callback logic with a Block?</a></li>
</ul>
<p>これを見ると単純に”blocks”としか書いてないですが、日本語の場合はブロック構文というみたいですね、多分。正直、このサンプルを見たときには意味不明な構文過ぎて理解しがたかったですが、それを除いても使う価値はあるものだな、と。ちなみに、私が書くとこんな感じになります。</p>
<pre><pre class="brush: plain; title: ; notranslate">

Environment *environment = [Environment instance]
assert(environment);

BOOL request = [environment requestPurchase:@&quot;MY_PRODUCT_ID&quot; callback:^(BOOL result){
  // ここで購入後の適切な処理をする
}];

// ここのエラーブロックはリクエストそのものに失敗した場合
if (request == NO) { 
  UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:....] autorelease];
  [alert show];
}

-------

@interface Environment

void (^_cbPurchaseHandler)(BOOL result);



@implements Environment

- (void)requestPurchase:(NSString *)product_id callback:(void(^)(BOOL))cbHandler {
  // 適切なproduct_idかどうかを調べたり、各種購入の前確認を行う
  ...(略)...
  
  if (invalid) {
    return NO;
  }

  // コールバックのハンドラーをコピーする
  _cbPurchaseHandler = [cbHandler];
  
  // 購入処理を走らせる
  [[SKPaymentQueue defaultQueue] addPayment:payment];
  
  return YES;
}

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
  // Your application should implement these two methods.
  [self recordTransaction: transaction];

  // コールバックを呼び出して購入処理に対する付与処理を行う
  _cbPurchaseHandler(YES);
  [_cbPurchaseHandler release];
  _cbPurchaseHandler = nil;
  
  // Remove the transaction from the payment queue.
  [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
  // キャンセルも含めて購入が失敗したことをコールバックに通知する
  _cbPurchaseHandler(NO);
  [_cbPurchaseHandler release];
  _cbPurchaseHandler = nil;

  [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

</pre>
<p>&nbsp;</p>
<p>あ、所詮ほげったほげぐらまが書くコードなのであまり突っ込まないでね。いつもほげほげしていますが、今日はいつになく有意義なものを覚えました、とさ。なんでこんな回りくどい実装をしたかというと、プロダクトIDを渡して購入処理をする部分(恐らく大抵のアプリで共通)、とその結果を受けて付与する部分(アプリ固有の処理)で分けたかったから。</p>
<p>大層な処理ブロックでもないのでコピーすればいいぢゃん、なんですがそこは宗教が許さないのでしょう。だって宗教なんだもん・・・・</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/11/08/310/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<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>
		<item>
		<title>本日のハマった一行</title>
		<link>http://lain.heavy.jp/lain/2011/09/28/216</link>
		<comments>http://lain.heavy.jp/lain/2011/09/28/216#comments</comments>
		<pubDate>Tue, 27 Sep 2011 16:14:49 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[singleton]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/09/28/216</guid>
		<description><![CDATA[プログラムをしているとたった一行だけのはずなのに何故か動かなかったりすることがあるかと思います。時々そんな一行をやらかすのですが、本日この一行で1時間ほどハマってました。 正常動作 [[Audio instance] p [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>プログラムをしているとたった一行だけのはずなのに何故か動かなかったりすることがあるかと思います。時々そんな一行をやらかすのですが、本日この一行で1時間ほどハマってました。</p>
<ul>
<li>正常動作</li>
</ul>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:e1b32305-57de-4179-8a4b-d4f542b2e9c6" class="wlWriterEditableSmartContent">
<pre class="brush: text;">[[Audio instance] play:[[AudioSource alloc] initWithPath:@"bgm.m4a"]];</pre>
</div>
<ul>
<li>異常動作</li>
</ul>
<div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:f32c3428-b7e9-4f15-a8ea-c502c7ff2e88:a614b0ac-663a-499a-bea9-6a41e964bded" class="wlWriterEditableSmartContent">
<pre class="brush: text;">AudioSource *source = [[AudioSource alloc] initWithPath:@"bgm.m4a"];
[[Audio instance] play:source];</pre>
</div>
<p>コードだけ見ると要はAudioSourceのインスタンス確保と初期化、そしてAudioクラスによる再生を行っています。Audioクラスはsingletonにより管理されていて常に唯一のインスタンスを返し、サウンド(ソース)の再生・停止を行います。</p>
<p>が、このAudioクラスが自分で作ったにも関わらずハマったという情けない話で、Audioクラスが最初にインスタンス化される際にはinitメソッドをコールするようになっています。つまりは、singletonクラスメソッドであるinstanceをコールした際にはご丁寧にもOpenALの初期化まで行っています。</p>
<p>ここまで書くと答えは明白で、異常動作のほうはOpenALの初期化前にALBufferを確保しようとして失敗していたと。たった一行や二行でも本気でわからないものです。</p>
<p>ちなみにこのオチに気がついたのが隣の同僚に「なんでだろ～」と聞いていた最中でふと思いつきました。その同僚はObjective-Cを知らないというのに無茶振り質問したわけなんですが・・・。いざ話してみると見落としがちな部分も気がつくものですね。</p>
<p># 話す前に自分で気がつけって？、うん、自分でもそうしたいのですけどね。巧く行かないものなんです orz</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/09/28/216/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Provisioningの注意事 @Xcode3系</title>
		<link>http://lain.heavy.jp/lain/2011/09/20/208</link>
		<comments>http://lain.heavy.jp/lain/2011/09/20/208#comments</comments>
		<pubDate>Tue, 20 Sep 2011 09:12:59 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[CodeSigning]]></category>
		<category><![CDATA[Provisioning]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/09/20/208</guid>
		<description><![CDATA[iOSの開発をしているとプログラム以外の割と煩わしいものにProvisioning(プロビジョニング)とCodeSigning(コードサイニング)なるものがあります。この2つは以下のことをコンパイルされたプログラムに情報 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>iOSの開発をしているとプログラム以外の割と煩わしいものにProvisioning(プロビジョニング)とCodeSigning(コードサイニング)なるものがあります。この2つは以下のことをコンパイルされたプログラムに情報提示するものです。</p>
<ul>
<li>自分がAppleより認定された正規のiOSディベロッパである</li>
<li>プロダクトの署名が有効期限内に限って正しいものである (開発時のみ)</li>
<li>コンパイルされたコードは改ざんされてはいないコードである</li>
<li>デプロイ(インストール)先のデバイスが開発者から正式に認定されたデバイスである (開発時のみ)</li>
<li>InAppPurchase, Push Notification, Game Centerに関して有効 or 無効である情報をアプリケーションに与える</li>
</ul>
<p>多分、思いつく限りでこんな感じ～のはず・・・・なんですが、適当です。なので、InAppPurchaseを使うにもInAppPurchaseが有効とされたAppIDに対して、その際に設定した適切なBundleIDをplistに設定して、更に適切なProvisiningを発行して、更の更にiTunesConnectでInAppPurchase用のアイテムを登録してようやく課金が行える・・・・なんて手間が必要なわけで。</p>
<p>とりあえず、InAppPurchase云々はさておき、未だ現役である可能性が非常に大きいXcode3系の、プロビジョニング／コードサイニングでハマる部分を以下に示します。<strong><font color="#ff0000">適切なプロビジョニングを設定しているのにCodeSigningでWarningが出た場合</font></strong>は以下を確認してみてください(一部先日コメントしたInAppPurchaseにも関連します、多分)。</p>
<p><strong>1. InAppPurchase、GameCenterが有効であることを確認する</strong></p>
<p><a href="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning1.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Provisioning1" border="0" alt="Provisioning1" src="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning1_thumb.png" width="644" height="175"/></a> </p>
<p>iOS Provisioning Portal(iOS Dev Center内)のAppIDタブで一意なBundleID(ワイルドカードを含まないBundleID)ではない場合は図のようにInAppPurchase, GameCenterの部分にEnableが付きません。まずはここで適切なAppIDが登録されていることを確認しましょう。その上で、Provisioningタブからプロビジョニングを発行 or 再生成し、ダウンロードしてみましょう。</p>
<p><strong>2. 適切なプロビジョニングを設定する</strong></p>
<p>Xcode3系のバグなのか、プロジェクトツリーの[Project]→(右クリック)→[Get Info]からプロジェクトの設定を行っても適切に設定情報が反映されない場合があります。その場合は以下の手順で設定を行ってみましょう。</p>
<p><a href="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Provisioning2" border="0" alt="Provisioning2" src="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning2_thumb.png" width="644" height="450"/></a> </p>
<p>[Get Info]からではなくて、[Project]メニューの[Edit Active Target]から設定画面を出すのがコツです。私がコレにはまったときは2時間ほど困って1時間ほどググった挙句にようやく海外のとあるBlogerのホームページで対処を見つけました(が、原文はいずこかに消えました)。</p>
<p><a href="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning3.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Provisioning3" border="0" alt="Provisioning3" src="http://lain.heavy.jp/lain/wp-content/uploads/Provisioning3_thumb.png" width="644" height="455"/></a> </p>
<p>書くまでもないですがこれは通常通りの操作、CodeSigningの際に使用するProvisiningを設定するだけです。</p>
<p><strong>3. Xcode上でおまじないをする</strong></p>
<p>今からほぼ2年前に私にiOSの開発を教えてくれたドイツ人のMさんが、非常に悩ましい顔をしながら「おまじないをするとコンパイルが通る場合があります」という事を言いました。もちろん、コンピュータ上で動くプログラムにそんな曖昧な要素などあるわけがないのですが、意外やこれが良く効くおまじないで。</p>
<ol>
<li>[Build]メニューから[Clean All Target]を選択する</li>
<li>[Xcode]メニューから[Empty Caches]を選択する</li>
<li>Xcodeを終了する (ランチャーにランプが付いている場合は右クリックで[Quit]選択)</li>
<li>Finderからプロジェクト直下のBuildフォルダを削除する</li>
<li>Xcodeを起動してコンパイル開始</li>
</ol>
<p>CodeSigningに使用するProvisioning(2.の操作)を変更してもどこかにキャッシュが残っているのか、おまじないが本気で有効な場合があります。慌てずにおまじないまでキッチリやった後にコンパイルすることをお勧めいたします。</p>
<p>って、情報を1年前に出しておけば救われた人が多かったかもしれませんね。まだ3ヶ月に満たないBlogですが、ハッハハハー、アーハッハハ＠オーマイオキー風。</p>
<p>※ Warningが出たときの詳細メッセージがただ今再現できないので、再現できた場合は検索にかかるように更新します。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/09/20/208/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iOS sandbox上での不具合と思われる現象</title>
		<link>http://lain.heavy.jp/lain/2011/09/14/190</link>
		<comments>http://lain.heavy.jp/lain/2011/09/14/190#comments</comments>
		<pubDate>Tue, 13 Sep 2011 16:46:54 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[iOSアプリ]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>
		<category><![CDATA[GameCenter]]></category>
		<category><![CDATA[InApp Purchase]]></category>
		<category><![CDATA[ios]]></category>
		<category><![CDATA[sandbox]]></category>
		<category><![CDATA[サンドボックス]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/09/14/190</guid>
		<description><![CDATA[iOS上で開発をする上で、特にゲームを開発する上で重要となる主機能では以下の2つは避けられないといっても過言ではない今日この頃だったりします。 InApp Purchase…アプリ内課金、アプリを先にダウンロードさせて機 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>iOS上で開発をする上で、特にゲームを開発する上で重要となる主機能では以下の2つは避けられないといっても過言ではない今日この頃だったりします。</p>
<ul>
<li>InApp Purchase…アプリ内課金、アプリを先にダウンロードさせて機能を課金アンロックさせたり、オンラインゲームで仮想通貨を発行したり、新聞などの定期購読をサポートしたりと。</li>
<li>Game Center…SNSとしての機能をゲームに絞ったようなもの。リーダーボード(スコアランキング)や、アーチブメント(実績解除)を始めとして、ゲームの招待なども。</li>
</ul>
<p>もちろん、その他多くの機能をiOSは含んでいるのですが、上記は開発環境としてiOS4.x上でサンドボックスが提供されている3機能の2機能だったりします(多分あっているはず)。で、この2つの機能をサンドボックスで利用するに当たってここ数日間不可解なエラーに見舞われたりして非常に時間を無駄にしたりと。</p>
<p>なので、ネットを調べたり自分の経験則上でこうしたら直った説(あくまで「説」です。Apple公式解決法ではありません)を書きたいと思います。</p>
<p>&nbsp;</p>
<p><strong><font color="#ff0000" size="4">Case.1</font> InApp Purchaseで「iTunesStoreに接続できません」「Cannot connect to itunes store」のエラーが通知され、InApp Purchaseのトランザクションがコミットできない</strong></p>
<p>よくある話でてっきりアカウントがsandboxアカウントから本番アカウントに移ったとか憶測していましたが、<a href="http://d.hatena.ne.jp/corrupt/20110714/1310646344" name="1310646344">In-App-Purchaseにテストアカウントから接続できない</a>(<a href="http://d.hatena.ne.jp/corrupt/">自堕落なぺぇじ</a>)を参照して直りました。こちらにも同様、手順を記載します(自分は1, 2が逆でも大丈夫でした)。</p>
<ol>
<li>開発アプリケーションを削除</li>
<li>設定→ストア→サインアウト、でテストアカウントを破棄</li>
<li>Xcodeよりデバッグを開始し、インストール &amp; デバッガ実行</li>
<li>InApp Purchsaeで「既存のアカウントを利用」を選択し、iTunesConnectのテストアカウントを入力</li>
</ol>
<p><strong><font color="#ff0000" size="4"></font></strong>&nbsp;</p>
<p><strong><font color="#ff0000" size="4">Case.2</font> Game Centerで「このゲームはGame Centerにより認識されません」「this game is not recognized by game center」のエラーが通知され、Game Centerにログインできない</strong></p>
<p>これも1日毎に1回起きる現象で、当初はiTunesConnectよりGameCenterのenable/disableを切り替えていました。が、もちろんアプリがリリースされた後にこんな操作はしたくないわけで。恐らくググるとBundleIDが異なるとか、プロビジョニング周りのアドバイスが多いようですが、それが原因でないのであれば以下の操作で解決するかもしれません。</p>
<ol>
<li>アプリを終了し、ホーム画面に戻る</li>
<li>GameCenter(OS標準のアプリ)を起動する</li>
<li>GameCenterのログインアカウントをテストユーザ(sandboxアカウント)に切り替える</li>
<li>ゲームのタブを押して、登録されている開発アプリケーションを選択する</li>
<li>リーダーボード、アーチブメントなどを一通り表示してみる (表示されればOK)</li>
<li>GameCenterを終了し、開発アプリケーションを再度起動する</li>
</ol>
<p>&nbsp;</p>
<p>どちらも不可解な操作ですが恐らくこれで直るかと思われます。他プラットフォームでエラーが意味不明とかイラっとしますがその期間が少しでも短くなることを祈っております。</p>
<p># でもね、Microsoftの製品で不可解なエラーがでたら速攻で問い合わせインシデントを使うんだっ！</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/09/14/190/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>uniqueIdentifierがdeprecation@iOS5</title>
		<link>http://lain.heavy.jp/lain/2011/08/24/171</link>
		<comments>http://lain.heavy.jp/lain/2011/08/24/171#comments</comments>
		<pubDate>Tue, 23 Aug 2011 15:05:04 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[iOSアプリ]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[エンターテイメント]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[プログラム]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/08/24/171</guid>
		<description><![CDATA[割とiOS関係者ではホットな話題かな～と思う、UIDeviceクラスのuniqueIdentifierが非推奨(deprecated)に指定されました。どのような背景でこれが非推奨に指定されたのかわかりませんが、これに対 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>割とiOS関係者ではホットな話題かな～と思う、UIDeviceクラスのuniqueIdentifierが非推奨(deprecated)に指定されました。どのような背景でこれが非推奨に指定されたのかわかりませんが、これに対しての対応を迫られるアプリケーションは多そうですね。ってか、私が今作っているアプリも(ry</p>
<p>私の場合は自業自得なんですけどね。JailBreakされた端末でAPIをフックされたら成りすましが可能だ、ということ知っていてそれを行っていたのですかｒ・・・（ごめんなさい、ごめんなさい</p>
<p>さておき、ゲーム的な側面で言うとちょっとイヤーンな状態は少なからずあるような。というのも、アカウント用途ではなくて純粋に機体識別を行いたい場合に何を使おうか、と。例えば無料ゲームを出しておいて誘われたユーザからインセンティブを与える、なんてのはソーシャルゲームでは割と普通なんですがこれに関してはユーザではなくて機体識別で行いたい、とか。</p>
<ul>
<li>UIID(Unique Installation Identifier)を使った場合はユーザが複製可能であるので、インセンティブが何回も発生可能であると思われる</li>
<li>Appleが推奨する、ゲームのアカウントとしてはGameCenterのplayerIdを使うと良い、というのもAppleID毎なので複製は可能であると思われる</li>
<li>ぢゃあ・・・・、結果的にインセンティブが過剰に増やされないためにはどぉすればいいんだろう→機体制約なら物理以上に出回ることはない、かもしれない</li>
</ul>
<p>とまぁ、こんな感じかな、と思ったり。さておき、個人的に怖いのが開発者なら割とMACアドレスは取得可能で、それも機体を一意に断定できる固有IDだよね！！！、とかいってMACアドレスを乱用するアプリが増えないかなとか。最初に言ったようにuniqueIdentifierが非推奨になった経緯はさっぱりわかりませんが、UDIDより推測可能なんです、多分。(上位6バイトがベンダID、下位6バイトが連番なので)</p>
<p>セキュリティにそこまで詳しいわけでもないし、非推奨となった経緯を改めて知った上で今後どうするべきかを判断するのも有りなのかな、と思いつつアプリを作るしかないですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/08/24/171/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Unreal engineとか</title>
		<link>http://lain.heavy.jp/lain/2011/07/11/144</link>
		<comments>http://lain.heavy.jp/lain/2011/07/11/144#comments</comments>
		<pubDate>Sun, 10 Jul 2011 15:51:52 +0000</pubDate>
		<dc:creator><![CDATA[st.lain]]></dc:creator>
				<category><![CDATA[iOSアプリ]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[エンターテイメント]]></category>
		<category><![CDATA[コンピュータ]]></category>
		<category><![CDATA[Unreal engine]]></category>

		<guid isPermaLink="false">http://lain.heavy.jp/lain/2011/07/11/144</guid>
		<description><![CDATA[つい先日PROPEなるゲームを購入しました。Unreal engineによるフル3Dの脱出ゲームです。正直、Infinity Bladeに続き改めてUnrealの凄さを痛感させられました。特に私は3Dが全くの無知なだけに [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>つい先日PROPEなるゲームを購入しました。Unreal engineによるフル3Dの脱出ゲームです。正直、Infinity Bladeに続き改めてUnrealの凄さを痛感させられました。特に私は3Dが全くの無知なだけに本気ですごいなと。</p>
<p>一方で気になる部分を挙げると、なんで脱出なんだろう、、、。Unreal engine、確か特殊なライセンス形態なのですよね。<br />
間違っているかもしれませんが、、、</p>
<p>誤り。。。。。。。<br />
・初期リリース時に$5,000<br />
・売り上げが$500,000を超えた段階でレベニューシェア25%</p>
<p>訂正<br />
・売り上げが$50,000を超えた段階でレベニューシェア25%</p>
<p>桁間違えた上に条件も違っていた。。。。でもレベニューシェアなんですよね。</p>
<p>Appleに30%、Unrealに25%なんて取られたら儲けがないぢゃん。大ヒットならまだしも、それ意外なら赤字にならないかな、、、。その点私はやはりUnity3Dをオススメしますが。</p>
<p>うーん、なぜUnrealを選択したのか知りたいですね。</p>
]]></content:encoded>
			<wfw:commentRss>http://lain.heavy.jp/lain/2011/07/11/144/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
