iOS:objective-cとjavaScriptの連携(3)

前回の問題を解決

デリゲートの設定

javaScriptからobjective-cの処理を実行するshouldStartLoadWithRequestを
利用するためにはデリゲートの設定が必要でした。これは前回利用した以下の
処理なのですが
——————————————————————-
webView.delegate = self;
——————————————————————-
前回説明したように警告が表示されてしまいます。
 
では何が問題だったかというと、上記の設定をするためには
ヘッダファイルに以下の様なUIWebViewDelegateの設定をする必要があったのです。
——————————————————————-
@interface test_2ViewController : UIViewController <UIWebViewDelegate> {
——————————————————————-
この設定をすることで、UIWebViewの各種イベントが利用できるようになります。
→参考:@ITさま「アプリ内でWebページを開いてiOS標準アプリと連携するには
 
 
 

動画で説明

今回作成したサンプルはUIWebView上で表示しているチェックボタンをクリックしたら
現在チェックの入っているIDをiOS上のラベルに表示するものです。
UIWebViewで表示しているhtmlはこちらです。
情報を送っている部分は以下のjQueryです。
——————————————————————-
window.location = “webview://saveFunc?”+checkArray;
——————————————————————-
独学xcode: javaScriptからobjective-cの処理を実行

これでjavaScriptとobjective-cの連携が完成しました。
※iOSとは関係ないのですが、afterEffectで字幕を付けている最中に間違って
オリジナルのmovファイルを上書きして無くしてしまいました…ショック。
 
 
 

説明

shouldStartLoadWithRequestメソッド内の処理について説明します。
※このメソッドはUIWebViewで表示しているURLが変更される時に実行されます。
——————————————————————-
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:@”webview”]) {
 [self performSelector:NSSelectorFromString([NSString stringWithFormat:@”%@:”,[URL host]]) withObject:[URL query]];
 return NO;
}
return YES;
——————————————————————-

URLオブジェクトに利用できるメソッド達

UIWebViewの各種イベントではURLオブジェクトが作成でき、これにメソッドを利用する
ことで、さまざまな情報を取得できます。上記ソースの1行目でURLオブジェクトを取得し
2行目でscheme, 3行目でhost, queryを利用しました。
これでスキームがwebViewだった時、host名のメソッドを実行し、引数で文字列部分を
渡すことができます。
→参考:逆引きObjective-C様「URLから様々な情報を取得す
また、shouldStartLoadWithRequest内でNOをreturnで返すことで、
実際のリンク処理をOFFにすることができます。
 
 
 

メモ

文字列の比較

objective-cでは文字列を比較する際isEqualToStringを利用して以下の様に
記述します。javaScriptでは「==」なのに、こんな長い文を書くなんて…
——————————————————————-
[URL scheme] isEqualToString:@”webview”]
——————————————————————-
 

文字列からメソッドを実行

shouldStartLoadWithRequest内でURLのホスト名のメソッド(今回はsaveFunc)を実行
するようにしていますが、そのためにはホスト名という文字列をメソッド名として実行させる
テクニックを利用しています。これにはperformSelectorメソッドを利用するのですが
構文がちょっと複雑なので上記ソースの3行目のように長文になってしまいました。
※これは以前にも説明したリフレクションのテクニックです。
→参考;極上の人生さま「文字列からセレクタを生成したい時はNSSelectorFromStringを使う
→参考;マイナビさま「ダイナミックObjective-C
→参考:YoheiM.net様
 
またobjective-cでもjQueryと同じようにセレクタがあります。でもjQueryよりも
難しそうなので以下のサイトをメモ
→参考:セレクタ
 
 

疑問点

URLオブジェクトから取得できる情報は文字列だと思うのですよ。
以下の様にisEqualToStringで比較できるのだし。
——————————————————————-
if ([[URL scheme] isEqualToString:@”webview”]) {
——————————————————————-
だから、以下の部分でstringWithFormatメソッドを利用してhost名を文字列に
する必要はないと思うのですよ。
——————————————————————-
[self performSelector:NSSelectorFromString([NSString stringWithFormat:@”%@:”,[URL host]]) withObject:[URL query]];
——————————————————————-
ですが実際にstringWithFormatを外すと機能しません。何故?
——————————————————————-
[self performSelector:NSSelectorFromString([URL host])]; 
——————————————————————-
しかしwithObjectで引数を渡す必要がない場合は、以下の様にstringWithFormatを
利用しなくても機能しました。何故?

iOS:objective-cとjavaScriptの連携(2)

javaScriptからobjective-cが実行できなくて…

前回紹介した以下のサイトを含め、javaScriptからobjective-cの処理を実行する方法を
説明するページはたくさん見つかったのですが…
私の環境では、まったく機能せず解決に丸1日くらい費やすことになりました。
→参考:Web&ハイブリッドアプリ開発者ブログさま
 
 

経緯

javaScriptからobjective-cの処理を直接実行する手段はないため、URLの変更を
フックして擬似的に処理を実行しなければなりません。このURLが変更する時に実行される
のがshouldStartLoadWithRequestメソッド(イベント?)です。
しかし、私の環境では一向に実行されません…。
 
ネット上で調べている過程で、以下のサイトをチェックしている際にデリゲートが正常に
設定されていないとの考えに至りました。
→参考:iPhone開発虎の巻「UIWebView」のUIWebViewの使用例
 
ということでデリゲートの設定を追加したのですが、私の環境では以下の様に警告が表示
され、正常に機能しません..。
warning
 
それからも色々調べてみたのですが糸口が掴めず、可能性は低いと思ったのですが
気分転換も兼ねて「OSをアップデートして最新のxcode4.6で挑戦しよう!」となりました。
 
とはいえ、以前説明したようにOSのアップデートに不安があるので、メインマシンの
MacProではなく、PacBookProにインストールすることにしました。
 
その結果!….やっぱりダメ…。
これは予想していたことなのですが、やはりショック。
※アプリを作成するのはobjective-cで、xcodeは開発環境にすぎません。
 
気を取り直して、再度ネットを探索…。
shouldStartLoadWithRequestは利用していないのですが、以下のサイトで
コードをダウンロードできるので、ダウンロードしてソースに
shouldStartLoadWithRequestを追加したところ…機能しました!!
→参考:iPhoneプログラミング広場さま「Web View サンプルプログラム
 
このサンプルからshouldStartLoadWithRequestが機能するための
最小限の設定を抽出して、なんとかサンプルを完成させることができました。
完成したサンプルの紹介は次回。
 
 
 

xcode4.6のメモ

xcode4.6を利用した感想をメモ。上記の通り、xcode4.6でも問題は解決できなかった
ので、利用した時間は短いのですが…。
xcode4
画像をクリックすると拡大します。
 

ストーリーボード

まず戸惑ったのが、interfaceBuilder書類のxibファイルが無いことです。
これはxcode4.2から登場したストーリーボードに取って代わられたためです。
→参考:ITpro様「Xcodeのストーリーボードの使い方
 

ターゲット

以前説明したようにローカルのjavaScriptを機能させるために、ターゲットで
javaScriptをコンパイルしないようにする必要があります。
しかし、左のカラムにターゲットが存在しません。すこし調べたのですが
分からず、いま直面している問題と関係ないので、ローカルではなく
ネットにアップしたhtmlを利用することで問題を回避しました。
現時点でも分からないままです。
 

Resources フォルダについて

xcode4ではResourcesフォルダが無いことは、以前の調査で知っていた
のですが、すこし納得いかない部分があったのでメモ。
 
Resourcesフォルダを作成した後で、実際のフォルダと関連づけるのですが
それでも、実際にhtmlファイルなどを登録する際にはxcode上のResourcesフォルダに
ドラッグ&ドロップする必要があります。
関連づけたのですから、自動的にResourcesフォルダの内容が反映されても
良さそうなのに…。関連づけないでもResourcesフォルダを作成できるので
その場合との違いは何なんだろう?
 
メモ終わり。
 
 
 
 

 
 

iOS:objective-cとjavaScriptの連携(1)

とりあえずobjective-c → javaScript

objective-cとjavaScriptの連携は簡単だと思っていたのですが、予想外に時間が
掛かってしまいました…とりあえず、objective-cからjavaScriptを実行する部分は
簡単だったので、ここではobjective-cからjavaScriptについてメモしておこうと思います。
→参考:Web&ハイブリッドアプリ開発者ブログさま
 
 
 

動画で確認

今回作成したサンプルはobjective-c側で作成した「引数を渡す」ボタンをクリックすると
表示しているhtmlのjavaScriptに引数を渡して処理(チェックボックス操作)を実行します。
また返値も受け取ることができるので、「返値を受取」ボタンをクリックすると
チェックボックスの状態を受け取りラベルに表示するようにしました。
独学xcode: objective-cからjavaScriptの処理を実行

 
 
 

説明

stringByEvaluatingJavaScriptFromString

objective-cからjavaScriptを実行するにはstringByEvaluatingJavaScriptFromString
メソッドを利用します。名前からも想像できるように文字列を設定します。
実行したいjavaScriptは時に長くなるため、以下のテクニックを覚えておくと良さそうです。
→参考:Prototype様「stringBy……: の可読性を改善する
 

引数を渡す

上記のテクニックを紹介しつつも、実際に作成したのは以下のソース。
単純に文字列を足して、それを設定しました。
内容としてはwebViewに表示したhtmlのloadFuncを実行しています。その際に引数として
ラベル「myLabel1」の内容を配列として送りました。
—————————————————————————
NSString *str1 = @”loadFunc([“;
NSString *str2 = myLabel1.text;//—ラベル1から情報取得(1,3)
NSString *str3 = @”]);”;
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@”%@%@%@”,str1,str2,str3]];
—————————————————————————
ポイントは2行目で、引数で渡したい値をラベルから取得している点です。これで
特定の変数を引数として渡せることを確認したかったのです。
 

返値を受け取る

返値を受け取る部分は、さらに簡単で、以下の様に普通に受け取れます。
このサンプルでは受け取った情報をラベルに表示するようにしました。
—————————————————————————
NSString *str = [webView stringByEvaluatingJavaScriptFromString:@”saveFunc()”];
myLabel2.text = str;
—————————————————————————
 
 
といった感じで、objective-cからjavaScriptを実行することはすぐにできたのですが
逆にjavaScriptからobjective-cを実行する部分はほぼ丸1日掛かってしまいました。
詳細は次回の記事にて。
 
 
 

iOS:情報の記憶

情報の記憶

ユーザーが設定した状態を保持するというのは、多くのアプリで必要になる
テクニックだと思います(ゲームのセーブにも利用できるし)。
ということで、今回は情報の記憶に挑戦しました。
youtubeの動画で確認できるようにテキストフィールドに設定した文字を記憶し、
次回起動する際に記憶した文字を表示するだけのシンプルなコンテンツです。
 
独学xcode: 独学xcode: ローカルのhtmlを表示する
 
 
 
 

テキストフィールド

情報の記憶の前に、色々躓いた部分があるので、まずはそれらについてメモ。
 
テキストフィールドはinterfaceBuilderで簡単に作成できるのですが
入力が終わってもキーボードが消えない!現象に悩みました…。
原因はイベントの設定でした。最初は以下の画像の黄色枠「EditingDidEnd」
を選択していたのですが、これだとキーボードの「enter」を押しても
キーボードは消えません。

しかし「Did End On Exit」に選択しなおしたら「enter」をタップ後に
キーボードが閉じました。
→参考:初心者から始めるxcode様
 
でもイベントをコレにしただけではダメという情報も発見。念のためメモ。
→参考:とある下っ端プログラマーのおぼえがき様
 
他にもinterFaceBuildeの以下の部分で表示するキーボードや、returnキーの
文字を変更したりできます。

 
 
 

アラートについて

記憶する前にアラートで確認するようにしてみたのですが、思いの外大変だったので
メモしておきます。
アラートウインドウの表示に関しては以下のサイトが詳しいです。今回は2つボタンに
しましたが、1つボタンにしたりバリエーションを付けることができます。
→参考:iPhoneアプリ開発の虎の巻「UIAlertView
 
 

表示の手順について

何かを作成して表示する手順は、大まかに以下の様になります。
[メモリを確保]→[作成]→[表示]→[メモリから解放]
メモリを確保するメソッドは「alloc」で、これから他の所でも多く出てきそう。
今回のサンプルではまとめて設定する書き方をしているのですが、上記にで
紹介したiPhoneアプリ開発の虎の巻「UIAlertView」では、allocしてから作成する
以下の様なサンプルコードもありました。
——————————————————
UIAlertView *alert = [[UIAlertView alloc] init];
alert.title = @”お知らせ”;
alert.message = @”完了しました”;
[alert addButtonWithTitle:@”確認”];
[alert show];
——————————————————
interFaceBuilderで作成した要素は、この様な部分を自動的にしてくれて
いるのでしょうね。きっと。
 
 

delegateの設定

iPhoneアプリ開発の虎の巻「UIAlertView」ではdelegateの設定がnilになっていますが、
これをselfにしておかないと、alertViewイベントがviewに来ないので
変更しました。
——————————————————
UIAlertView *myAlert = [
 [UIAlertView alloc]
 initWithTitle:@”確認”
 message:@”テキストフィールドの内容を記憶しますか?”
 delegate:self
 cancelButtonTitle:@”いいえ”
 otherButtonTitles:@”はい”,nil
];
——————————————————

 
 

NSIntegerとint

——————————————————
if(buttonIndex == 1){
 myTextField.text = @”内容を記憶しました”;
}
——————————————————
アラートウインドウの仕組みを作成する際、上記のような処理を書いたところ
条件式の「buttonIndex == 1」で警告が表示された。
警告は「ポインタを整数と比べるな!」というもの…。
解決方法は以下のサイトを参考にしました(NSIntegerをintに変換して対応)。
→参考:深夜帯さま「NSNumberクラスとプリミティブ型との変換
 
 

ラッパークラスって?

上記の件を調べている途中に「ラッパークラス」というものを知ったのでメモ
→参考:OKWaveさま「ラッパークラスの存在意義が分かりません
 
上記サイトにある「リフレクション」は以下のサイトでjavaScriptのコードを
確認すると理解しやすいかも。要は文字列でメソッドなどにアクセスできるということ?
→参考:wikipedia様「リフレクション

OKWaveでの回答によれば、引数buttonIndexの型がintではなくNSIntegerなのも
リフレクションが関係してそうです。
 
 
 

情報の記憶

で、肝心の情報の記憶は簡単にできました(殆ど定型みたいです)。
→参考:A Day In The Life様「NSUserDefaults を使ったデータの保存方法
※保存メソッドと取得メソッドが1対1でないのが不思議。保存する時は大抵
 setObjectと大雑把に「オブジェクト」なのに、取得する時は
 stringForKeyと「文字列」としていするなんて。
 
利用するのはNSUserDefaultsクラスで、これにキーを設定して情報を記憶
させます。キーとはobjectオブジェクトのプロパティみたいなもので
名前を付けて情報を保存する仕組みです。
 
まずはデータの記憶です。今回のサンプルでは以下の様に記述しました。
——————————————————-
NSUserDefaults *userObj = [NSUserDefaults standardUserDefaults];
[userObj setObject:myTextField.text forKey:@”myData”];
[userObj synchronize];
——————————————————-
1行目でNSUserDefaultsクラスを作成し、2行目でmyDataというキー
にテキストフィールドの内容を代入しています。そして3行目で
実際に書き込みます。
  
値を取得するのは以下の様に記述しました。
——————————————————-
NSUserDefaults *userObj = [NSUserDefaults standardUserDefaults];
myTextField.text = [userObj stringForKey:@”myData”];
——————————————————-
1行目は書き込みの際の処理と同じです。2行目でstringForKeyメソッドを利用
して、myDataのキーから得られた情報を文字列としてテキストフィールドに
表示します。この処理はviewDidLoadイベントに記述したので
viewが表示されたら保存データをテキストフィールドに表示することになります。
 
参考サイトで紹介したページには、保存時や読取り時の成功/失敗についての
処理も書かれているので見ておくと良いでしょう。
 
 
 

iOS:webページの表示(4)-プログラム

ローカルのhtmlをUIWebViewで表示するソースはgoogleにたくさんありますが
ここでメモしておくのは以下のサイト。
→参考:dTblog様「ローカルの html を UIWebView で表示する
 
上記サイトのソース2〜6行目はInterfaceBuilderを利用せずプログラムでUIWebViewを
画面上に表示する部分(だと思います)。今回は、この部分のテクニックは利用しませんが
利用する機会もありそうなので…。
 
 

動画で確認

独学xcode: 独学xcode: ローカルのhtmlを表示する

 
 

NSBundleを利用する

interfaceBuilderを利用した場合は、リンクで紹介したソースよりシンプルになり、
以下の様になります。
ローカルにあるファイルを利用する時はNSBundleを利用します(以下ソースの1行目)。
後の手順はinternet上にあるhtmlの表示と同じです。
——————————————————————-
NSString *myPath = [[NSBundle mainBundle] pathForResource:@”index” ofType:@”html”];
NSURL *myURL = [NSURL fileURLWithPath:myPath];
NSURLRequest *myURLReq = [NSURLRequest requestWithURL:myURL];
[myWebView loadRequest:myURLReq];
——————————————————————-
1行目で特徴的なのは、指定するファイルをpathForResourceで「ファイル名」と「拡張子」に
分けて記載する点です。これだとパスを記述できないのですが、今回はindex.htmlは
Resourcesフォルダ直下にあるので問題ありません。
 
 

メモ:Resources内のサブフォルダにアクセスする場合

もしindex.htmlがResources内のサブフォルダにあるばあいは以下のサイトが
参考になると思うのでメモ。
→参考:Bugle Diary様「UIWebViewでローカルファイルを表示
 
 
 

iOS:webページの表示(3)-javaScript等

表示するコンテンツ

今回iOS上で表示するコンテンツは以下のサンプルにしようと思います。
これは1年ほど前に練習として作成したモバイル向けのjQueryコンテンツで
条件に合ったスマートフォンを検索します(1年前のサンプルなのでデータは古いです)。
ネット上にもアップしました(PCでも確認できます)。
→参考:スマートフォン用サンプル
chart
 
 

javaScriptやcssなどもResourseフォルダに

前回のhtmlファイルと同様に、jsやcss,csvデータも以下の様にResourcesフォルダでOKです。

 
 

javaScriptがコンパイルされないように

javaScriptはデフォルトでコンパイルされるそうで、上記の設定だけでは機能しないそうです。
→参考:24/7様「UIWebView を使ってリソースバンドル内の HTML ファイルで、外部 JavaScript や CSS を読み込む
 
ということで私も以下の様にターゲットの項目でjavaScriptファイルを移動しました。

 
 
 

バグ?

Resourcesフォルダ内に登録したファイルを削除したり、名前を変更していたりしたら
新たにファイルをドラッグ&ドロップする事ができなくなりました…。
具体的には前回まで利用していたjQuery1.9.2をResourcesフォルダから削除し、
別のjQuery1.7.2をドラッグ&ドロップしようとしたのですが、できなかったのです..。
で、とりあえずドラッグできた「other sources」に登録したら、機能したのですが
なんだか気味が悪かったので、プロジェクトを作り直して対応しました。
 
どの操作がバグ(ドラッグできない)の切っ掛けになったかよく分からないのですが
きっとxcode4であれば問題なくなっているのですよね!
次回は実際にプログラムを書いていきます。
 
 
 
 
 
 

iOS:webページの表示(2)-local

ローカルのhtmlファイルを利用する

更新を殆どしない部分に関してはローカルにデータをおいた方が良いのかな?
通信費定額コースが普及しているので気にしなくても良いかもしれませんが勉強なので
ローカルのhtmlを読み込む方法についてもメモ。
 
今回と次回(javaScript)のyoutubeは無しです。 
次々回に、まとめて動画で紹介する予定です。
 
 
 

ローカルデータをどこに置くか?

xcodeではプロジェクトを作成すると、新規にプロジェクト名のフォルダが作成されます。
なので、そこにhtmlファイルを入れておけば良いと思ったのですがダメでした…。
 
ネットで調べると「Resources」フォルダに入れるとのことですが、プロジェクト名フォルダ内に
そのようなフォルダは見当たりません…。ですが、xcodeの左カラムにResourcesがあったので
そこにhtmlファイルをドラッグ&ドロップしたら登録することができました。
※下図では、Resources内にindex.htmlとimagesフォルダを登録しました。

 
調べている時にフォルダの階層についての注意が見つかったのでメモ。
Resourcesフォルダ内にサブフォルダを作成しても、ビルド(アプリを作成)する際に
サブフォルダが解消(つまり同じ階層に)されてしまうため、htmlのにパスが
通らなくなってしまう。
 
しかし、これに関しては以下のページで説明されているように、ドラッグ&ドロップの際の設定で
サブフォルダを解消しないようにできました。このテクニックを利用しているため、上図では
imagesフォルダの色が青くなっているのです。
→参考:永遠ログ様「リソースファイルをフォルダ階層を維持しながらコピーさせる
 
前述のとおり、サブフォルダは解消されないので、index.htmlのソースは
以下の様にパスにimagesを含んでいます。
もしサブフォルダを解消する設定であれば、imagesのパスは必要なくなります。
——————————————————
<body>
iOS test<br>
<img src="images/tethering.gif" width="80" height="32" alt=""><br>
<img src="images/water.gif" width="80" height="32" alt="">
</body>
——————————————————
ビルド後のことは気にしなくても良いので、この設定は重要と感じないかもしれませんが
実際のフォルダ階層と、Resourcesフォルダの階層を同じようにしておいた方が
間違いが少ないと思うので、この設定を利用していこうと思います。
 
プログラムのソースについては次回説明しようと思います。
 
 

xcode4についての注意

私は時代遅れのxcode3を利用しているわけですが、xcode4ではResourcesフォルダが
無くなっているそうです。私もいずれバージョンアップするのでxcode4についての
Resourcesフォルダ作成について以下のサイトをブックマークしておきました。
→参考:極上の人生さま「XcodeのプロジェクトにResourcesディレクトリを追加する
 
 

iOS:webページの表示(1)-http

動画で確認

独学xcode: 外部htmlの表示

 
 

ソースの説明

インターフェイスビルダーの設定

internetにアップされているwebページを表示するのは簡単にできました。
webViewオブジェクト(下図左)を利用します。このときScaleToFit(下図右)に
チェックを入れると、ページが画面に納まるようにリサイズされます。

 

ヘッダファイルの記述

viewContoroller.hファイルにweb Viewオブジェクト(UIWebView)
を登録。今回は「myWebView」という名前にしました。この1つだけです。
—————————————-
IBOutlet UIWebView *myWebView;
—————————————-
 

実装ファイルの記述

続いてviewContoroller.mファイルにhtmlを表示する処理を記述します。
iOS:タッチしている間だけ移動する」で利用したviewDidLoadイベントを利用して
viewの表示が完了したら実行するようにします。
 
1行目でURLオブジェクト(myURL)を作成し、2行目でURLオブジェクトを利用して
NSURLRequestオブジェクト(myURLReq)を作成します。
そして3行目で実際にmyWebViewに表示するように依頼します。
—————————————-
//—外部htmlの表示
NSURL *myURL = [NSURL URLWithString:@”http://www.apple.com/jp/”];
NSURLRequest *myURLReq = [NSURLRequest requestWithURL:myURL];
[myWebView loadRequest:myURLReq];
—————————————-
結果として、以下の様にアップルのページが表示されました。
「scales page to fit」にチェックを入れたので、ページ全体が納まるように表示されています。

 
internet上に作成されたページを利用することで、頻繁な更新に対応できると思うのですが
個人的には、頻繁にネットにアクセスするのは嫌いなので、ローカルのhtmlを表示する
方法も学んでおこうと思います(次回に紹介予定)。
 
 

iOS:スワイプによる移動、そして…

スマートフォンならではの操作

折角のスマートフォンなので、スマートフォンならではの操作で移動させようと思います。
イメージとしてはプレステのアナログスティックのイメージです。
動画の最後の方で動作確認していますが、プレスした地点からのドラッグ位置で
速度を変更しています。こういう操作もスワイプに入るのかな?
※動画中ではプレスしている間カーソルのまわりが黄色く表示されます。
独学xcode: スワイプによる移動

 

実装ファイルの説明

前回のサンプルと共通な部分も多いので、ポイントだけをメモ。
まずtouchesBeganメソッド内の以下の処理。
————————————————
CGPoint point = [touch locationInView:self.view];
————————————————
locationInViewメソッドでself.viewを指定することで現在のビューでの
タッチポイントを取得できます。
→参考:逆引きObjective-Cさま「タッチイベントを取得する」のページ中程
 
続いてtouchesMovedメソッド。これは文字通り、タッチ中に移動した場合に
実行されます。
————————————————
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
————————————————
そして、このメソッド内の以下の処理。
————————————————
CGPoint point = [touch locationInView:self.view];
speed = (point.x – initX)/20;
————————————————
locationInViewによって取得できる値の型は「point」なので、
X座標だけを利用したい場合は2行目のようにxプロパティを利用して取得します。
これでタッチしたところから、どれ位X座標が移動したかを調べ、それを基に
速度を変更しています。
 
 

jQuery版も作成して忌みました

objective-cの「touchesMoved」とjQueryの「mousemove」イベントの違いに
すこし戸惑いました。詳細はjQueryのソースにコメントとして書いています。
jQueryのサンプル
※濃いグレーの部分をドラッグしてみてください。
 
 
  

今後の展開

このままゲームを作ろうと思い色々調べていたら、cocos2dというフレームワークを
利用すると良さそうなことが分かりました(3DゲームならUnityが良いらしいです)。

 
とりあえず参考になりそうなサイトをメモ。
→参考:iOS開発者@日本さま
→参考:リンゴにかじられたブログさま
 
 
またcocos2dではないのですが、以下のサイトも良さそうなのでメモ。
ですが私の利用しているxcode3では、フレームワークGLKitが無いので保留。
→参考:objective-cが最強の言語である様「簡単なiPhoneゲーム制作の解説」
 
ネットは自分の興味のあることを調べて勉強していくのにはよいけれど
系統的な理解ができないのが難点。なので書籍も購入しようと思う。
とりあえずAmazonで評価の高い(★4.7)をメモ。

 
 
そういえば、今はFlashで作成する事もできるので、それも選択肢に入れておきましょう。
とりあえず以下のサイトをメモ。下記サイトで Adobe Gaming SDK
ANE(ActionScript Native Extensions)の説明が役に立ちそうです。
→参考:DX.univ様「過去のFlashコンテンツを再利用
 
 

次回からはwebページの表示について

ここまでゲームについて調べて来ましたが、調査の過程でxcodeでは簡単にwebページを
組み込むことができることが分かりました(interFaceBuilderにある「web view」を
利用します)。
 

 
そして、これはjQueryも有効なので、これを利用すればjQueryベースのiOSアプリも
作成できるかもしれません。ということでゲームは少しお休みして、
次回からは「web view」について学ぼうと思います。
 
 
 

iOS:タッチしている間だけ移動する

何か動かしてみたい

interFaceBuilderを利用すると、色々簡単にできそうなことが分かりましたが
やっぱりゲームっぽいアプリも作成してみたいです。ということで、とりあえず
タッチしている間だけ移動するようなサンプルを作成しました。
 
手始めにjQueryで作成しました。濃いグレーの部分をプレスしている間だけ
上部の■が右に移動します。jQueryの説明はソースに書いたので確認して下さい。
これをObjective-Cに書き換えてみます。
→参考:jQueryでの移動サンプル
 
 

youtube

実際に作成したサンプルをyoutubeにアップしました。次項でソースについて説明します。
独学xcode: タッチしている間だけ移動する

 
 
 

ソースの説明

ヘッダファイルの記述

interfaceBuilderに登録したのは以下、2つラベルだけです。
jQueryのサンプルではdivを利用しましたが、objective-cでは何を利用して良いか
分からなかったので「とりあえず」ラベルにしました。
——————————————————
IBOutlet UILabel *moveArea;
IBOutlet UILabel *debugArea;
——————————————————
ラベルを使うことを決めた後で知ったのですが、ラベルにはボタンのようなイベントを
設定できません!。しかしネットで調べたら、不可能ではないのでラベルで続行する
ことにしました。というわけでヘッダファイルにはイベントの登録をしていないのです。
→参考:UILabelやUIImageViewのタッチイベントを取得する
 
 

実装ファイルの記述

ほとんど上記リンクを参考にしているため、細かい部分の文法が分かりません..。
しかし勢いが大切。とりあえず分かった部分だけメモ。
※全てのソースをここに書くと長くなるので、ソースはyoutubeで確認して下さい。
 画質を720pにしてフルスクリーンで見れば文字も読めると思います。

新規プロジェクトで選択した「view-based Application」の実装ファイルには
あらかじめ、色々なメソッド?が記述されているが、コメントアウトされている。
以下のviewDidLoadも、その1つで、このコメントを外して処理を追加。
 
メソッド名から察するに、画面の準備が完了されたら実行されるメソッドで
jQueryでいうreadyイベントみたいなものだと思う。
——————————————————
– (void)viewDidLoad {
 [super viewDidLoad];
 moveArea.userInteractionEnabled = YES;
 moveArea.tag = 100;
}
——————————————————
moveAreaはラベルなので、デフォルトではタップを受け付けないらしい。なので
userInteractionEnabledプロパティをYESにしてタップを受け付けるようにする。
このときにtagを数値で設定しなくてはいけないそうです(サンプルでは100)。
 
また、jQueryではsetInterval用に変数moveTimerを作成しましたが
objecteb-cでは以下の様にtimerクラスを作成するそうです。
——————————————————
NSTimer *moveTimer;
——————————————————
 
そしてメソッド(javaScriptのfunction?)の作成部分の構文がよく分かりません。
参考サイトとしては以下のサイトをメモ。
→参考:逆引きObjective-C「メソッドの定義
 
上記サイトからサンプルを解読すると、例えば以下の部分は、インスタンスメソッドで
返値は無く、引数は(NSTimer *)timerということになる。
——————————————————
-(void) moveFunc:(NSTimer *)timer
——————————————————
※(NSTimer *)timerというのは型指定の部分が(NSTimer *)で、変数名が
 timerということなのかな?

でも、今回moveFuncで引数なんて利用してないから、引数の表記を消したらエラーになった。
timerで実行するメソッドには必須なのでしょう。
 
 
touchesBeganやtouchesEndedの構文はさらに複雑。 
——————————————————
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
——————————————————
でもtouchesが引き数名なのは理解しました。withEvent以降はよく分かりませんが、
多分定型なのかな?
→参考:引数touchesを利用した例があるサイト。
 
で、引数のtouchesからタッチの情報を以下の1行目で取得し、それを2行目のif文で
判断しているのだと思う。
——————————————————
UITouch *touch = [touches anyObject];
if ( touch.view.tag == moveArea.tag ){
——————————————————
条件式のtouch.view.tagは、タッチ情報からタグを取得して、それをmoveAreaのtag
と比較しているのだね。だからこのテクニックは、ラベルにイベントを設定しているのではなく
画面全体のタップを検知して、タップされた場所がラベルかどうかを判断して処理をするってこと
ですよね。
 
jQueryのsetIntervalの代わりに利用した、NSTimerはほぼ定型なので省略。
→参考:google検索「NSTimer」
 
オブジェクトの位置はCGPointクラスで指定しなければならないようです。
そしてCGPointクラスを作成するのがCGPointMakeメソッド。
→参考:CGRect、CGPoint、CGSizeの真ん中あたり
 
で、実際にオブジェクトの位置を管理しているのがcenterプロパティ
類似したプロパティとしてframeやboundsがあるそうです。
→参考:UIViewのframeとboundsとcenter
→参考:iPhoneアプリ開発の虎の巻
 
実際に移動させている部分は以下の通り。
——————————————————
-(void) moveFunc:(NSTimer *)timer
{
 float myX = debugArea.center.x;
 float myY = debugArea.center.y;
 myX++;
 if(myX > 320) myX = 0.0;
 debugArea.center = CGPointMake(myX, myY);
}
——————————————————
jQueryのサンプルと異なり、右端にきたら左端に移動するようにしました。
細かい構文は、まだよく分かりませんが。今回はこんな感じです。
 
 
 

メモ

jQueryでの移動サンプルでは以下の様な修正をしました。
——————————————————
修正前→ $(“#moveArea”).mouseup(touchesEnded);
修正後→ $(document).mouseup(touchesEnded);
——————————————————
修正前のサンプルはmoveAreaの外でマウスアップしてしまうと、touchesEndedが実行されず
移動し続けてしまうため、ブラウザ上のどこでマウスアップしてもtouchesEndedしたのです。
 
このことを鑑みてxcodeの以下の部分を確認するとif文でmoveAreaかどうかを
判定しています。
——————————————————
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
 UITouch *touch = [touches anyObject];
 if ( touch.view.tag == moveArea.tag ){
  [moveTimer invalidate];//—timerの停止
 }
}
——————————————————
だから同じようにmoveAreaの外でtouchesEndedすると、移動し続けてしまうのでは?
と思ったのですが、そうはなりませんでした。
 
私の理解としては、PCのclickイベントが最初にmousedownした要素を覚えており、
その要素上でmouseupしないとイベントが発生しないのに近い気がします。
つまり、上記の処理の意味は「moveAreaで発生したtouchesBeganが終わった時に」
という感じだと思います。
 
もし、このif文を外してしまうとmoveArea以外でで発生した場合も処理を実行してしまい
そのため作成していないmoveTimerを停止することになりプログラム上良くないのでしょう。
たぶん。
※moveTimerはmoveAreaがタップされた時にしか作成されない