tokoromのその他の日記
- vim関連: vimまっしぐら★
- それ以外: 寄り道ばかりの お勉強日記★
2011-12-25
uncaught exceptionが発生した場所を確認する
debug | |
uncaught exception でアプリリセット
uncaught exceptionでmain.mのUIApplicationMainのところでリセットが発生しているときに、以下のようなログが出て、
2011-12-26 02:14:41.837 test[64894:f803] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 1 beyond bounds [0 .. 0]' *** First throw call stack: (0x12e2052 0x1896d0a 0x12ce674 0x4a7f7 0x2ab7 0x22d9d6 0x22e8a6 0x23d743 0x23e1f8 0x231aa9 0x21cffa9 0x12b61c5 0x121b022 0x121990a 0x1218db4 0x1218ccb 0x22e2a7 0x22fa9b 0x27d9 0x1fc5)
「で、けっきょくこのExceptionどこで発生してんねん」と思ってしまうことがあります*1。
ふつーにぱっと見で認識できるスタックトレースとか出してくれればいいのにねって。
exception をキャッチしてデバッグ表示
それなら、uncaughtなexceptionをキャッチしてあげようということで、UIApplicationMainのところをtry/catchで囲ってデバッグ表示を追加してみました。
int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int retVal; @try { retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } @catch (NSException *exception) { NSLog(@"%@", [exception callStackSymbols]); //< ★1 @throw exception; //< ★2 } @finally { [pool release]; } return retVal; }
★1
どうもiOS4.0から、NSExceptionにcallStackSymbolsという便利メソッドが追加されたようなのでそれを利用。
そうすると、uncaughtなexceptionをキャッチして、以下ようにそのexceptionが発生するまでの経緯がログ出力されます。
2011-12-26 02:27:18.933 test[65600:f803] ( 0 CoreFoundation 0x012e206e __exceptionPreprocess + 206 1 libobjc.A.dylib 0x01896d0a objc_exception_throw + 44 2 CoreFoundation 0x012ce674 -[__NSArrayI objectAtIndex:] + 196 3 test 0x0004a6e7 -[RootViewController init] + 215 4 test 0x000029a7 -[AppDelegate application:didFinishLaunchingWithOptions:] + 567 5 UIKit 0x0022d9d6 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1292 6 UIKit 0x0022e8a6 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 508 7 UIKit 0x0023d743 -[UIApplication handleEvent:withNewEvent:] + 1027 8 UIKit 0x0023e1f8 -[UIApplication sendEvent:] + 68 9 UIKit 0x00231aa9 _UIApplicationHandleEvent + 8196 10 GraphicsServices 0x021cffa9 PurpleEventCallback + 1274 11 CoreFoundation 0x012b61c5 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53 12 CoreFoundation 0x0121b022 __CFRunLoopDoSource1 + 146 13 CoreFoundation 0x0121990a __CFRunLoopRun + 2218 14 CoreFoundation 0x01218db4 CFRunLoopRunSpecific + 212 15 CoreFoundation 0x01218ccb CFRunLoopRunInMode + 123 16 UIKit 0x0022e2a7 -[UIApplication _run] + 576 17 UIKit 0x0022fa9b UIApplicationMain + 1175 18 test 0x0000258b main + 187 19 test 0x00001d65 start + 53 )
これを見れば「RootViewControllerのinitメソッド内にダメなコードがあるんだね」ということがすぐに分かるようになります。
★2
ちなみにexceptionをキャッチしっぱなしだとアプリ的には異常がなかったという扱いになってしまうので、同じexceptionをそのままthrowしておきます。
DEBUGビルド時にだけこれを有効に
DEBUGビルド時にだけこれを有効にしたい場合には、以下のように「#ifdef DEBUG」で囲ってやるのが良いかもしれません。
int main(int argc, char *argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; int retVal; #ifdef DEBUG @try { #endif retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); #ifdef DEBUG } @catch (NSException *exception) { NSLog(@"%@", [exception callStackSymbols]); @throw exception; } @finally { #endif [pool release]; #ifdef DEBUG } #endif return retVal; }
ARCを利用する場合
ARCを利用する場合はもうちょっとシンプルにできる。
int main(int argc, char *argv[]) { int retVal; @autoreleasepool { #ifdef DEBUG @try { #endif retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); #ifdef DEBUG } @catch (NSException *exception) { NSLog( @"%@", [exception callStackSymbols] ); @throw exception; } #endif } return retVal; }
でも、こんなごちゃごちゃ書かなくてもよいかもしれない
ちなみに、uncaught exceptionを制御するための「NSSetUncaughtExceptionHandler」といった関数もあるようで、こちらを使えばもっとスマートな方法があるかもしれません*2。
もう眠くなったのと、↑でも特に困らなかったので今日はここまで。
2011-11-27
MacアプリでもUIKitを使ってみる with Chameleon
UIKit | |
Chameleon
Chameleon - UIKit for Mac development
このChameleonを使うとMacアプリの開発でもUIKitを使えるようになるとのこと。
前々から気になっていたので少し試してみた。
Chameleon自体はBigZaphod/Chameleon - GitHubからダウンロード可能。
また、Chameleonを試用した本記事のソースコード一式はtokorom/ChameleonUIKitDemo - GitHubからダウンロード可能。
今回は、UIViewControllerで画面を1つ作り、そこにUIImageViewやUIButtonを貼りつけて動かしてみるところまで実験。
まずはプロジェクトにChameleonを取り込む
※上記サイトからあらかじめChameleonをダウンロードしておくこと
まずはXcodeで空のMacアプリのプロジェクトを作成する。
そのプロジェクトにChameleonの中のUIKit.xcodeprojだけ追加する。
次に、Build PhasesのLink Binary With LibrariesにUIKit.frameworkを追加する。
↓このあたりの実施後の画面が↓になります↓
UIKitを他のコードから使えるようにimport
■ChameleonUIKitDemo-Prefix.pch
プロジェクトの中にはじめからあるプリコンパイル済みヘッダで、上記のように
UIKit/UIKit.h
UIKit/UIKitView.h
をimportしておく。
もちろん、各ソースコードから個別にimportしても構わない。
UIKit用のAppDelegateを作っておく
■ChameleonAppDelegate.h
■ChameleonAppDelegate.m
ここは普段のiOS用アプリ開発とほぼ同じでOK!
唯一違うのは、windowやViewControllerのautoresizingMaskを明示的に指定するコードを追加するくらい。
UIViewControllerがそのまま使えるというのは素晴らしい!
はじめに表示するRootViewControllerを作っておく
ここはiOS用アプリ開発と全く同じ!
ここではUIImageViewとUIButtonを追加している。
※必要な画像はあらかじめプロジェクトに追加しておくこと
■RootViewController.h
■RootViewController.m
Mac用のAppDelegateをUIKit用AppDelegateに接続
■AppDelegate.h
■AppDelegate.m
ここでは、UIKitViewと先ほど作成したChameleonAppDelegate(UIKit用のAppDelegate)を追加する。
UIKitViewは後ほどInterface Builderで接続するためIBOutletを付けておく。
そして、applicationDidFinishLaunchingの中で、UIKit用AppDelegateに移管するため、UIKitViewのインスタンスに対してlaunchApplicationWithDelegateをコールして引数にUIKit用AppDelegateのインスタンスを指定する。
Interface Builder で最後の仕上げ
最後に、Interface BuilderでMainMenu.xibを開き、WindowsのメインViewにUIKitViewを追加する。
UIKitViewというオブジェクトはツール上は存在しないので、代わりにCustom Viewというのを貼り付ける。
そして、そのClass名をUIKitViewに変更する。
※このあたりは↑のスクリーンキャプチャのとおりです
これができたら、そのUIKitViewをApp Delegateに作っておいたOutlet(chameleonView)に接続する。
以上で完了。
ビルド&ラン!
実行してみたところUIImageViewもUIButtonもきっちり動き、ボタン押下のアクションも問題なくハンドリングされていました。
なかなか面白いですね!
UIKit.frameworkをappの中に含める設定
なお、このままだとappとして出力した後にUIKit.frameworkが見つからなくて動作しなくなってしまう。
そのため、Builde PhasesにCopy Filesという項を追加し、そこにUIKit.frameworkを設定しておく必要がある。
2011-07-09
VimでのiOSアプリ開発に便利なsnippetsファイル作りました
VimでのiOSアプリ開発生活を快適にするために、
- Foundation.framework
- UIKit.framework
のクラス、メソッドなどをヘッダーファイル*1から抜いてVim用のsnippetsファイルを作成しました。
snipMate.vim や neocomplcache で利用できる見込み*2です。
もし必要なかたがいらっしゃいましたら
からダウンロードをお願いします。
例えば、pushViewController:animated: のsnippetは、
snippet pushViewController:animated: pushViewController:${1:(UIViewController*)viewController} animated:${2:(BOOL)animated}
のように定義されており、どのメソッドも引数のところがプレースホルダになっています*3。
なお、スニペット名をメソッドの名前そのままにして長いので、neocomplcasheによるスニペット補完の利用が推奨されます*4。
以下、自分用メモ。
各フレームワークのtagsの作成
例えば、Foundation.frameworkとUIKit.frameworkのtagsを作成する場合、
$ ctags -R --language-force=ObjC /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/Foundation.framework/Headers /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk/System/Library/Frameworks/UIKit.framework/Headers
とする。
ObjCに対応したctagsを利用する必要あり。
他のフレームワークのやつも欲しければ、ヘッダーファイルが入っているフォルダのパスを加えればOK。
tagsからsnippetsファイルを作成
今回は、rubyでスクリプトを書いて対応。
- tags2vimsnippets.rb
inputFileName = ARGV[0] outputFileName = ARGV[1] result = [] snippets = [] IO.foreach( inputFileName ) {|l| result = l.scan(/^[+-]([:a-zA-Z0-9_-]+).*\/\^[+-] \([^)]*\)([^;]+);/) if !result.empty? next if 6 > result[0][0].length snippets.push( sprintf("snippet %s", result[0][0]) ) t = result[0][1] t = t.gsub(' *', '*').gsub(' (', '(') count = 0 while /([^{][^0-9]+?:)(\(.+?\)[^() ]+)/ =~ t count = count + 1 t = t.sub(/([^{][^0-9]+?:)(\(.+?\)[^() ]+)/, sprintf('\1${%d:\2}', count)) break if 64 < count end snippets.push( sprintf("\t%s", t) ) next end result = l.scan(/^([:a-zA-Z0-9_]+)/) if !result.empty? next if 6 > result[0][0].length snippets.push( sprintf("snippet %s", result[0][0]) ) snippets.push( sprintf("\t%s", result[0][0]) ) end } snippets.uniq! out = open( outputFileName, 'w' ) snippets.each {|k| out.puts k } out.close
このスクリプトに先ほど作ったtagsファイルを渡してやる。
$ ruby tags2vimsnippets.rb tags objc.snippets
これでsnippetsファイル完成。
変な部分があったら正規表現を見直す必要あり。
Kalyn2011/09/16 19:19You know what, I'm very much inlcnied to agree.
ppoyzurt2011/09/16 20:49dShnsD <a href="http://lfyzjbluhbqu.com/">lfyzjbluhbqu</a>
hgvcreus2011/09/17 21:369XOHOe , [url=http://sggbqokkwiui.com/]sggbqokkwiui[/url], [link=http://yzdkxnyyohny.com/]yzdkxnyyohny[/link], http://yommpsvjyaop.com/
gifkjbjbry2011/09/19 00:08HVLjji <a href="http://wwxbkjkabkiw.com/">wwxbkjkabkiw</a>
2011-04-25
じつはもっと簡単なAdHocアプリ(ipa)の作成方法があった件... for Xcode4
xcode | |
昨日AdHoc版の作り方について記事を書いたが...
この後、Twitterでnovi_さんから
あれ、これって普通にReleaseビルドして、Shareの時にCode Signじゃだめでしたっけ。
というご指摘。
要するに、
- AdHoc用Configurationとかは作らなくてもOK
- Edit SchemeとかしなくてもOK
ということ。
実際、novi_さんの言うとおりやってみると、たしかにそれだけでOKでした。
ご指摘ありがとうございます!
以下、AdHocアプリ(ipa)作成の短縮版、まとめさせていただきます。
事前準備
前回と同様、
- 自分のPCにDistribution(配信用)の証明書がインストールされていること
- iOS Provisioning Portal に、AdHoc用アプリをインストールする対象端末のUDIDが登録されていること
- 対象端末のUDIDが登録されたDistribution用provisioningファイルを取得してあること
の3つの準備がされていることを前提とする。
オーガナイザにAdHoc用provisioningファイルを登録する
この手順はまだやってなければ前回と同様に必要。
Xcode4の画面の右上のほうに[Organizer]というボタンがあるのでそれをクリックし、オーガナイザを表示する。
次に、オーガナイザの[Devices]タブを選択し、オーガナイザの左側のリストから[LIBRARY]→[Provisioning Profiles]を選択する。
すると、オーガナイザには現在登録されているprovisioningファイルの一覧が表示されるため、そこに今回用のAdHoc用provisioningファイルをドラッグ&ドロップして登録しておく。
Let's Archive!
デフォルトではArchiveを実行すると、Release用Configurationが利用されるようになっている。
AdHoc用として特に変更する内容がなければそのままRelease用設定を使えばOKということ。
ということで、Release用Configurationが利用されるデフォルト設定のまま、Xcode4のメニューから[Procust]→[Archive]と選択してArchiveを実行する*1。
すると下図のようにArchiveした結果の一覧画面みたいのが表示される。
ここで[Share...]ボタンをクリックすると、出力方式として「ipa」が選択可能になっている。
ここでipaを選択し、Identityの項で"AdHoc用provisioning"をきちんと選択さえすれば、あとは[Next]ボタンを押して出力するだけ。
ipaファイルが出力できたら、これまでどおりiTunesに
- ipa
- provisioning
の2ファイルをドラック&ドロップして同期をとってAdHocアプリのインストール完了です!
まとめ
なんと、こんな簡単なことだったのか!
要するに、novi_さんからのご指摘どおり、Archive実行後にAdHoc用のprovisioningファイルを選択してSignするだけ。
前回記事に書いたように、律儀にAdHoc用のConfigurationを作るのは
- Release用ConfigurationとAdHoc用ConfigurationでCode Signing以外に変更すべき箇所がある場合
のみということでしょう。
*1:Archiveが実行できない場合、Destinationが実機向けになっていることを要確認
NamfonYou're on top of the game. Thanks for sahirng.
pwuoiniiXoApRo <a href="http://uwonnqrubqkf.com/">uwonnqrubqkf</a>
ksjaflupngwx6auYW , [url=http://ummczstbdrte.com/]ummczstbdrte[/url], [link=http://ptymfcamjcyn.com/]ptymfcamjcyn[/link], http://eorivdakqmdq.com/
gwniqecldviGShFEG <a href="http://rjcdrwhnwmkq.com/">rjcdrwhnwmkq</a>
wmochxucfrSunT , [url=http://ntbtunnxrjmu.com/]ntbtunnxrjmu[/url], [link=http://ktoerrvgkfkb.com/]ktoerrvgkfkb[/link], http://hehaidhlfyno.com/
2011-04-24
Xcode4でのAdHocアプリ(ipa)の作成方法詳解
xcode | |
はじめに注意!
この記事を書いた後にTwitterでもっと簡単な方法があるよというのをご教示いただきました。
そのため、より簡単な方法については、次の記事をご参照願います。
こちらの記事は、
- AdHoc配信用に専用の設定(Configuration)が必要な場合
のみご参照ください。
Xcode4になって
どうもこれまでと同じかんじではAdHocアプリを作成できないとか。
自分の場合、今日までXcode4さえインストールできていなかったので、これを機会にXcode4をインストールしてAdHoc用ビルドをしてipa形式で出力するところまでを試してみようと思い立った。
なお、基本的には
のとおりにやっただけ。
そのため、英語がNGでないかたは↑をそのまま見てもらったほうがよいかと。
以下、基本的にはXcode3→Xcode4の差分しか記載しておりません。
事前準備
この記事は、Xcode3以前でAdHocなアプリをビルドした経験のあるかたを対象とし、provisioningファイルの作成やCertificationについては言及しない。
そのため事前に
- 自分のPCにDistribution(配信用)の証明書がインストールされていること
- iOS Provisioning Portal に、AdHoc用アプリをインストールする対象端末のUDIDが登録されていること
- 対象端末のUDIDが登録されたDistribution用provisioningファイルを取得してあること
の3つの準備がされていることを前提とする。
オーガナイザにAdHoc用provisioningファイルを登録する
この手順は基本的にはXcode3までと同じである。
Xcode4の画面の右上のほうに[Organizer]というボタンがあるのでそれをクリックし、オーガナイザを表示する。
次に、オーガナイザの[Devices]タブを選択し、オーガナイザの左側のリストから[LIBRARY]→[Provisioning Profiles]を選択する。
すると、オーガナイザには現在登録されているprovisioningファイルの一覧が表示されるため、そこに今回用のAdHoc用provisioningファイルをドラッグ&ドロップして登録しておく。
AdHoc用Configurationを作成する
まずはXcode3のときと同様にAdHoc用のConfigurationを作成する必要がある。
Xcode4では、まず、該当PROJECTを選択し、[Info]タブを選択する。
すると、下図のようにDebugとReleaseというConfigurationが並んでいるはずなので、ReleaseをベースにしてAdHocを追加することにする。
それには、Configurationsの下にある[+]ボタンをクリックし、「Duplication "Release" Configuration」を選択する。
すると、Releaseをベースとした新しいConfigurationが作成されるので名前を "AdHoc" に設定する。
AdHoc用ConfigurationにAdHoc用のprovisioningファイルを設定する
次に、AdHoc用ビルドの際に、AdHoc用のprovisioningファイルが利用されるように設定する。
該当PROJECTを選択し、今度は[Build Settings]タブを選択する。
Xcode3までと違い、各Configurationの設定項目がマージされた形で表示される。
この中の[Code Signing]→[Code Signing Identity]→[AdHoc]→[Any iOS SDK]の値の部分をクリックし、先ほどオーガナイザに登録したAdHoc用provisioningファイルを選択する。
SchemeのArchiveの項でAdHoc用Configurationが利用されるよう設定する
次に、Schemeの設定を変更する。
Schemeの設定変更は、Xcode4の左上の下図の赤枠のところをクリックし「Edit Scheme...」を選択することで可能。
こうして表示した編集ダイアログの左から「Archive」を選択し、「Build Configuration」の項をさきほど作成した「AdHoc」に変更する。
あとは、Desitinationも「iOS Device」にしておく*1。
これで[OK]ボタンをクリックすれば、Schemeの設定変更は完了。
Let's Archive!
あとは出力するだけ*2だ。
Xcode4のメニューから[Procust]→[Archive]と選択してArchiveを実行する*3。
すると下図のようにArchiveした結果の一覧画面みたいのが表示される。
ここで[Share...]ボタンをクリックすると、出力方式として「ipa」が選択可能になっている。
ここでipaを選択し、Identityできちんと該当のAdHoc用provisioningを選択さえすれば、あとは[Next]ボタンを押して出力するだけ。
ipaファイルが出力できたら、これまでどおりiTunesに
- ipa
- provisioning
の2ファイルをドラック&ドロップして同期をとってAdHocアプリのインストール完了です!












iPhoneプログラミング UIKit詳解リファレンス
詳解 EZアプリ(BREW)プログラミング