ホームページ開発ツール>Xcode and iOS SDK コラム

Xcode and iOS SDK コラム

目次
 UIView上のタッチスクロールが遅い(解決済)

 UIViewに画像を表示し、タッチによってスクロールさせようとすると、動作が劇的に遅くなる場合があったので、記しておきます。
(注:本件はシミュレータでは発生しません。実機(iPod touch 5thGで確認)でのみ発生します。)

 遅くなったのは、以下のケースです。(実際にはもう少し複雑な処理をしていますが、説明のため、簡略化しています。)
  1. プロジェクトは、Single View Application
  2. 表示方向はポートレート(今回は、320x568)
  3. ViewContorollerとViewを新規に作成。ViewContorollerのビューにViewをaddSubview。ViewContorollerはappDelegateのウィンドウにaddSubview
  4. 568x320のイメージを作成して画像をコピー(コンテキストを経由)し、その後、90度回転してからUIImageの配列に登録
  5. タッチスクロールは、touchesBegan/touchesMoved/touchesEnded/touchesCancelledをオーバーライドして実装
  6. 起動したら、画像を配列から選んで表示
 この状態でスクロールしようとすると、カクカクした動きになる上、タッチを離すと、あらぬ位置でストップします。
 スクロールの度に再描画が発生する訳ですが、全く間に合っていない感じです。

 結局、320x568のイメージを作成し、画像をコピーするときにコンテキストを回転するようにしたら解消しました。

 シミュレータでは発生しないことから、ハードウェア依存だということは想像つきますが、因果関係については今ひとつよく分かりません。
回転して登録したものが遅くなるということは、UIImageってビットマップで持っている訳ではなく、回転とかは表示時にリアルタイムに行っているってこと?

 cssのみでiPhone風ボタンを作る

 iOS向けに、webkitを使って、cssのみでテーブルビュー風のUIを作れないかと思って調べてみたのですが、詳細表示ボタンが見つからなかったので、作ってみました。
(若干いびつでグラデも微妙ですが、必要なら調整して下さい。)
 htmlのサンプルは以下の通りです。
<div class="detailDisclosureButton"></div>
 cssは以下の通りです。
.detailDisclosureButton {
	width:22px;
	height:22px;
	border:2px solid #FFFFFF;
	border-radius:13px;
	box-shadow:1px 1px 2px rgba(0, 0, 0, 0.6);
	background:-webkit-gradient(linear, center top, center bottom, from(#2385BA), color-stop(0.49, #2385BA), color-stop(0.5, #236ed8), to(#236ed8));
	background:-moz-linear-gradient(top, #2385BA, #2385BA 49%, #236ed8 50%, #236ed8);
	/*float:right;
	margin:-3px 5px 5px 15px;*/
}

.detailDisclosureButton::before {
	position:relative;
	content:"";
	display:block;
	background:#FFFFFF;
	width:3;
	height:10;
	top:4;
	left:11;
	-webkit-transform:rotate(-45deg);
	-moz-transform:rotate(-45deg);
}

.detailDisclosureButton::after {
	position:relative;
	content:"";
	display:block;
	background:#FFFFFF;
	width:3;
	height:10;
	top:-1;
	left:11;
	-webkit-transform:rotate(45deg);
	-moz-transform:rotate(45deg);
}
 注1)-moz-はFirefoxに必要なもので、iPhoneでのみ利用する場合は不要。
 注2)コメント化してあるパラメータは、セル内に配置する場合に必要なもので、marginの値は現物合わせで調整します。


 UIScrollView上でUIButtonをハイライト表示する

 UIScrollView上にUIButtonを置くと、ボタンを押してもハイライトせずに実行されてしまいます。
 理由は、UIScrollViewが、画面への接触が「タップ」なのか「スワイプ」なのかを判定するために、若干の待ち時間を設けているため、ボタンの方が先に反応して実行されてしまう、ということのようです。(なので、暫く押し続けているとハイライトされます。)

 どうにかならないものかと検索してみたのですが、自分の期待するような動作をするものは見つかりませんでした。
 ちなみに、それらはtouchesShouldCancelInContentViewをオーバーライドする、scrollView.delaysContentTouchesをNOにする、といった、UIScrollView側を操作するものでした。
 が、ふと「UIScrollViewの判定を早めるのではなく、UIButtonの実行を遅くすればいいのでは?」と思い、再度検索してみたら、performSelectorが見つかりました。

 結局、以下の様にすることで、ハイライトされるようになりました。
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];  // ボタン生成
…
[btn addTarget:self action:@selector(buttonDidPush1:) forControlEvents:UIControlEventTouchUpInside];  // ボタンが押された時の飛び先を指定
…

- (void)buttonDidPush1:(UIButton *)btn {  // スクロールビュー上でボタンのハイライトを確実に行うため、0.12秒のディレイを設ける
	[self performSelector:@selector(buttonDidPush2:) withObject:btn afterDelay:0.12];  // ディレイ満了後の飛び先を指定
}
- (void)buttonDidPush2:(UIButton *)btn {
	// ボタンを押された時の処理を記述
}
 ディレイ値(上記例では0.12秒)は現物合わせで調整すればいいと思います。
 あと、副作用?として、ボタン上でスワイプ(フリック)しても、(ディレイの期間内であれば?)スクロールするようになりました。


 Xcode 4でビルドしたアプリを初代iPod touchで動かす(2)

 先日、しばらくぶりに初代iPod touchを動かそうとしたのですが、またしても動かなくなっていました。
 結論から書くと、以下の通り対処する事で、動くようになりました。
  1. Xcodeのバージョンを「4.4.1」にダウングレードする
  2. libSystem.B.dylibを「Optional」にする
注)前提となる検証環境は、前回と同じ。(ただし、メインは最新にしておきたいので、サブ(OSX 10.7 + Xcode 4.6)で実施している。)
 当初は初代iPod touchが切り捨てられていたことを知らずに、最新のXcode(4.6)で動かそうとしたのですが、オーガナイザで未対応(赤マーク)と表示されてしまいました。
 調べてみたら、4.5から対応しなくなったとのこと。

 仕方がないので、(4.5の一つ前の)4.4.1から試して、ダメなら遡ることにしました。
 4系のアンインストールはゴミ箱に入れるだけなので、まずは4.6をゴミ箱に捨て、iOS Dev Centerから4.4.1をダウンロードしてインストール(アプリ単体のみの配布なので、アプリケーションフォルダにドラッグするだけ)。
 オーガナイザで見たら、しっかり対応(緑マーク)していましたので、遡らずには済みました。

 とはいえ、実機で実行すると、アプリが起動しかかったところでエラーが出て止まってしまいます。
 エラーメッセージでググってみたところ、こちらに対応策が示されていました。(ハマケン100%開発: libSystem.B.dylibってなんだろう
libSystem.B.dylibは、元々のリストにはないので、わざわざ追加した後にOptionalに設定し直すのがなんとも。(RequiredでないものはデフォでOptionalに、とかできないのだろうか…)
 これらの対処により、正常に動作するようになりました。
参考)本件と関係あるかは不明ですが、Safari 5.1.7が動かなくなっていました。再インストールしようとしたのですが、10.7用のSafariは単体では用意されておらず、ソフトウェアアップデートは何度実行しても(Safariが最新でないのにも関わらず)「お使いのソフトウェアは最新のものです」となってしまいました。半ば諦めていたのですが、Security Update 2013-001のタイミングで6.0.3がリストに現れ、そのままインストール。起動後、正常動作を確認しました。

 Xcode 4でビルドしたアプリを初代iPod touchで動かす

 Xcode 4でビルドしたアプリを、初代iPod touch(iOS 3.1.3)で動かそうとしたのですが、一筋縄ではいきませんでした。
 結論から書くと、以下の通り対処する事で、動くようになりました。
  1. Deployment Targetを「3.1」にする
  2. Architecturesに「armv6」を追加する
  3. Debuggerを「LLDB」から「GDB」に変更する
注)前提となる検証環境は、以下の通り。
・検証用アプリは、以前、Xcode 3 + iOS 3.1ベースで作成し、初代iPod touchで正常動作を確認済のもの。
・同アプリ(のプロジェクト)をXcode 4で開き、標準の手続きでコンバートしたものを、シミュレータで動作確認。
・同アプリを初代iPad(iOS 5.1)で実行し、動作を確認。
 なお、本検証の過程で、旧iOS用の追加SDKのインストールを促されたので、実行しています。
 1.と2.については、例えばこちらにまとめられています。(EZ-NET: Xcode 4.2 で iOS 4 用のアプリをビルドする : Objective-C プログラミング

 これらの対処により、アプリが実機に転送され、起動するところまではいきました。
 ですが、起動はするものの、メインウィンドウが表示されず、ハングアップ状態になります。
 Xcodeでの実行を一度終了し、実機単体で起動すると、ちゃんと動作しますので、どうも、アプリとXcodeの間で通信が出来ていないような感じです。

 ググってみたのですが、(探し方が悪かったのか)有用な情報が見つからず、仕方なく、アプリ-Xcode間通信に関係のありそうなところを、片っ端から弄ってみたところ、DebuggerをLLDBからGDBに変更したところで、正常に動作するようになりました。



スキーム名をクリックするとメニューが表示されるので、Edit Scheme...を選択すると、右のダイアログが表示されます。
注1)TestタブにもDebuggerを選択する項目があるのですが、こちらは起動の可否には関係ないようです。(合わせておいた方がいい?)
注2)何かのタイミングで「デバッガをLLDBにするか?」というダイアログが表示される事がありますが、選択しないようにします。
 いずれにしても、デバッガは真面目に使っていないので、設定の変更がどう影響するかは定かではありません。
 なので、これが正しい対処法なのかはよく分かりませんが、とりあえず実行は可能という事で、メモしておきます。


[Home]  [MacSoft]  [Donation]  [History]