2008年12月25日木曜日
CS193P Cocoa Programming - AssignmentPresence3まで完了
最近ご無沙汰気味でしたが、
なんとかPresenceアプリ作成の宿題3まで完了させることができました。
リロードボタンと投稿ボタンがつきました。
詳細画面を見るとこんな感じです。ちょっと寂しい。
投稿ボタンを押すとこうなります。
UITextFieldではなくてUITextViewを使った方がよかった気がします。まぁいいや。
ソースコードなどは以下に公開しております。
http://github.com/akisute/akisute_cs193p/tree/master
残るはPresence4だけなのですが、Presence4の内容は正直それほど難しくない(TabBarを使うぐらい)ので、
ここらですっ飛ばして今興味があるroute-meという地図ライブラリの解析でもやってみようと思います。
2008年12月17日水曜日
CS193P 11日目 非同期処理をやってみる
- 非同期処理を行う方法はいくつかある
- URLフェッチ処理ならば、NSURLConnectionクラスをつかっておけば一発
- さらに簡単にURLフェッチ処理を行いたいのであればこのライブラリをおすすめ
- URLフェッチ以外の処理を行うならば、NSThreadを使うか、NSOperationとNSOperationQueueを併用する
- NSThreadは従来どおり、本当にスレッド処理を記述する必要があるため非常に大変
- 対するNSOperationはインスタンスをつくってキューにぶち込んだら後は勝手にやってくれる、楽
- UIViewやUIViewControllerに対する処理(要するに画面に対する処理)は、必ずメインスレッドから呼び出す必要がある
- スレッドセーフではないため
- 要するに[object performSelectorOnMainThread:withObject:waitUntilDone:modes:]を使えば解決する
いきなり日付が飛んで11日目です。
このあたりからは課題1つにつき3日分ぐらいのの講義内容が含まれていて、難易度がどんどん高くなってきました。
母さん、おいらスタンフォード大学の学生にはなれそうもないよ。
さて、今回の内容は非同期処理です。
現在の課題ではTwitterのタイムラインをJSON形式で取得して表示を行っているのですが、
メインスレッド(プログラムのメインループが走っているスレッド)の上から直接URLに対してHTTPアクセスを行っているため、
処理が返ってくるまでメインスレッドがブロックされ、結果フリーズしたように見えるという問題がありました。
これを非同期処理にしてブロックしないようにしましょうね、と言うのが今回の課題の内容。
NSURLConnectionと言うクラスを使えばURLのフェッチを自動的に非同期で行ってくれるのですが、
ご丁寧に「NSThreadかNSOperationで処理してね」とご忠告が。
Threadはどうにも使いこなせる気がしないので、ここはより簡単なNSOperationを使おうと思います。
(ゲームなどではおそらくNSThreadを使うことになるんだと思いますが)
NSOperationというクラスを継承して、
mainメソッドをオーバーライドして処理を記述し、
NSOperationQueueに追加すると自動的にThreadを裏で立ち上げて並列処理を行ってくれます。
処理が完了したらKVOという機能を使ってNSOperationから通知を受け取るらしいです。
しかしこのKVOと言う概念がイマイチ理解できないので後回しにして、
より簡単なNSInvocationOperationというクラスを使うことにしました。
使い方はこんな感じです。
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(reloadPerson:) object:person]; [self.operationQueue addOperation:op]; [op release];
これだけで自動的に並列処理をしてくれるんだから凄いと思います。
ということで、今回の課題では以下のように並列構成をしてみました。
スレッド1:メインスレッド
スレッド2:TwitterからTimelineを取得するためのスレッド(NSInvocationOperation + NSOperationQueue)
スレッド3:画像を取得するための並列処理(ImageStoreを利用、内部的にはNSURLConnection)
ところがこれがうまくいきません。
1と2だけを並列処理させたときはうまくいき、1と3だけのときもうまくいくのですが、
1と2と3と並列で動かすとエラーになります。
ああもう!だから並列処理なんて嫌いだ!
デバッガで調査してみるとSocketの取得のあたり?でとまっている感じがしたので、
スレッド2かスレッド3がソケットを捕まえてロックしているのではないかと考え、
使ったらすぐreleaseするようにソースを変えてみたのですが、効果なし。
Google先生にご相談したところ、それらしい回答が。
【iPhone】スレッド中で[UITableView reloadData]を使ってはいけない
なるほど!自分のソースを見直すと、確かにスレッド2の処理の中でUITableViewに対してreloadDataを呼び出しています。
さっそくご指摘のあったとおりにソースを書き直してみました。
if ([delegate respondsToSelector:@selector(mPersonDataSourceDidFinishLoadOfPerson:)]) { [delegate performSelectorOnMainThread:@selector(mPersonDataSourceDidFinishLoadOfPerson:) withObject:person waitUntilDone:YES]; }
今度は一発で成功!
2008年12月6日土曜日
CS193P Cocoa Programming - ソースコードをgithubに公開いたしました
gitの練習もかねてここまでの成果ソースコードを公開してみました。
http://github.com/akisute/akisute_cs193p/tree/master
特に見所はありませんが、一応自分の勉強用として。
http://github.com/akisute/akisute_cs193p/tree/master
特に見所はありませんが、一応自分の勉強用として。
2008年11月30日日曜日
CS193P Cocoa Programming - 7日目 UINavigationViewControllerを使う
- UIViewControllerのawakeFromNibは動作しないときがある。UIViewControllerの初期化には 必ずviewDidLoadを使うこと
- UINavigationViewControllerはxibファイルに含めずに、ソースコード中で初期化したり管理する方がうまくいく
- UINavigationViewControllerの上に表示されるバーを編集したいとき(ボタンを追加したりするとき)は、UINavigationViewControllerにpushされるUIViewControllerのnavigationItemプロパティを編集する。Interface Builderから操作できるかどうかはわからない
- UIAlertViewがポップアップ表示、UIActionSheetが下からにょきっと出てくるボタンのリストを表示
- ボタンにソースコード中からアクションを追加することが可能(UIButton, UIBarButtonなどのドキュメントを参照のこと)
さて、ナビゲーションがついてようやくiPhoneアプリらしくなってきました。
画面はナビゲーション時にUIViewControllerのインスタンスがどのように管理されているかをログに吐いてみたところです。viewDidDisappearの後にdeallocが毎回流されているのがわかります。
要するに、一つのviewを毎回毎回alloc->initしないでインスタンスを再利用してやろうと思うときはUINavigtionViewControllerにpushするだけではなくて、どこか別のところでUIViewControllerのインスタンスを保持しておく必要があるようです。2tchの作者さん曰くalloc->initは相当重い動作らしいので、できるかぎり使い回しができるようにしたいです。
ポップアップも出るようになりました。
※いい加減開発ペースと学習ペースをあげようと思っているので、しばらくの間はブログの更新がこんな感じで適当になりそうです。
2008年11月26日水曜日
CS193P Cocoa Programming - 6日目おまけ、多角形をくるくる回せるようにしてみた
- CS193P(http://www.stanford.edu/class/cs193p/cgi-bin/index.php)のチュートリアルで作っているHelloPolyプロジェクトを自分なりにアレンジしてみた
自分なりにアレンジしてみた=ニコニコ動画だと駄作フラグ- UIViewはhiddenプロパティをYESにした瞬間に消えてしまうので、アニメーションでフェードアウトさせたいときは、まずアニメーションだけ実行>アニメーション終了時のデリゲータ(- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag)で実際にUIViewをhiddenにする
- タッチ動作を取得するには、UIView(正確にはUIResponder)のtouchBeganメソッドやtouchMovedメソッドをオーバーライドする
- デフォルトではマルチタッチ不可能(最初の1タッチのみ感知する)、マルチタッチしたければ設定を変えること
- UITouch.tapCountでタップした数を取得できる。これを使ってダブルタップを検出できるが、連打すると3とか4とか2より大きい数が取得されてしまうので注意
- CGPointはクラスではなくて構造体、頭にCGがつくCore Graphics系はすべて純粋C言語であるところに注意!
- CGPointなどを作成するときはCGPointMake()関数を使う
- CGPointやCGRectなどをObjective-Cのクラスとして扱いたいときはNSValueクラスを使う、たとえば[NSValue valueWithCGPoint:(CGPoint)point]など
- CGRectGetMidX()関数とか地味に超便利
- C言語の変数の有効範囲について:http://www.cis1.c.dendai.ac.jp/c_master/C_14.htm
CGPointMake()で作ったCGPointなどは自動変数なので、別のメソッドに渡すときはポインタ渡しではなくてそのまま値で渡す
ただ単にカリキュラムにそって進めていくだけでは面白くないので、この辺りでちょっとチャレンジングなことをしてみることにしました
まずは新しくサブビューを追加。
ON OFFスイッチでビューを出したり消したり。出したり消したりするときはアニメーションします。
UISliderを使って、線の太さを変えてみましたよ。
UISliderのvalueプロパティはdouble型なので注意です。ずっとNSString型だと思ってました。
それから、タップした向きに多角形を回転できるようにしました。赤線は中心からタップした点への線分です。
タップしてドラッグするとスムー(?)ズに回転しますよ。
破線への切り替えもできるようにしました。
UISegmentedControlを使っています。このUISegmentedControl、取得できる値が選択されているセグメントのインデックス番号(selectedSegmentIndex)だけなのでちょっと厄介です。HTMLのラジオボタンみたいに好きな値をセグメントごとに持たせられればいいのに。
今回作成したアプリのプロジェクトファイルを公開してみました。
面白いことをやっている点は何一つないのですが、まぁ一応。
http://sites.google.com/site/akisutesama/files/HelloPoly-06b.zip?attredirects=0
今後はgithubとかで公開できるようにします。
2008年11月22日土曜日
CS193P - ここまでの進捗をアップしてみた
ここまでのCS193Pの進捗をアップしてみました。
http://sites.google.com/site/akisutesama/files/HelloPoly-06.zip?attredirects=0
Xcode3.1用のプロジェクトファイルと、ソース一式が入っています。
Max OS Xで解凍してXcodeで読み込んでコンパイルできると思います。たいした内容ではありませんが一応。
http://sites.google.com/site/akisutesama/files/HelloPoly-06.zip?attredirects=0
Xcode3.1用のプロジェクトファイルと、ソース一式が入っています。
Max OS Xで解凍してXcodeで読み込んでコンパイルできると思います。たいした内容ではありませんが一応。
CS193P Cocoa Programming - 6日目、NSUserDefaultsの使い方
- アプリケーションが終了した後もデータを保持したい(例:現在開いているページなど)
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- あとはNSDictionaryとほとんど同じ(格納の仕方も取得の仕方も)
- BOOLとかintをそのまま格納できるメソッドもあります
- 格納するタイミングは、値がかわった瞬間かまたはアプリが終了する瞬間
- 取得するタイミングは、アプリが立ち上がった瞬間かまたはawakeFromNibメソッド
NSUserDefaultsとはアプリケーションが終了した後もデータを保持することができる仕組みのようです。
本格的にデータを保存したいならSQLiteやファイルを使うんでしょうが、ちょっとしたデータ(例えば現在開いているページ)を保持したいときなどにSQLを書くのは煩雑です。そういうときに便利に使える仕組みらしいです。
○値を格納する
タイミングは二つ。値がかわった瞬間か・・・
//ボタン押し下げ時に値を減らすまたはアプリケーションが終了するタイミングか。
- (IBAction)decrease {
int currentNum = polygonShape.numberOfSides;
currentNum--;
polygonShape.numberOfSides = currentNum;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:currentNum forKey:@"numberOfSides"];
[self updateInterface];
}
//@implementation HelloPolyAppDelegate(アプリケーションのデリゲートの中で)パフォーマンスに応じてどちらか好きな方を選んでくださいとのことです。
- (void)applicationWillTerminate:(UIApplication *)application {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setInteger:controller.model.intValue forKey:@"numberOfSides"];
}
○値を取得する
こちらもタイミングは二つ。アプリケーションが立ち上がったタイミングか・・・
//@implementation HelloPolyAppDelegate(アプリケーションのデリゲートの中で)
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int storedNumberOfSides = [defaults integerForKey:@"numberOfSides"];
controller.model.intValue = storedNumberOfSides;
[window makeKeyAndVisible];
}
または対象のクラスのawakeFromNibメソッドの中か。
//ここではコントローラクラスの中で・・・
- (void)awakeFromNib {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
int storedNumberOfSides = [defaults integerForKey:@"numberOfSides"];
self.model.intValue = storedNumberOfSides;
[self updateInterface];
}
この二つの違いは正直わかってません。複数のNibファイルを利用するときはawakeFromNibでないと駄目らしいですが・・・
CS193P Cocoa Programming - 5日目、いよいよView自作
- Interface Builderを使ったらとにかくWrite Class Files...を押すのを忘れないように
- 描画はJavaのSwingなどとほぼ同じ
- drawRectメソッドをオーバーライドして描画する
だんだんと難易度も上がってきました。
まずは自作Viewを作成。
Interface BuilderからUIViewを引っ張ってきて画面上に配置。
クラス名を適当に(ここではPolygonView)に変更。
ControllerクラスやらModelクラスなど、必要に応じてOutletを追加します。
最後に(一番忘れやすいんだけれども)メニューからFile > Write Class Files... この書き出しを行わないとXcode上に実際のソースが出てきません。
書き出しを行ったらXcodeを開いて、以下の2つの仕事を行います。
・先ほど追加したPolygonViewのスーパークラスを定義する
・ControllerにIBOutlet PolygonView *polygonViewを追加する
新しいオブジェクトはWrite Class Filesで一発だと思うけれども、既存のクラス(例えば前回実装したController)なんかは、書き出ししちゃうと上書きしてしまいそう。怖いので今回はXcodeから書くことにしました。でもこれ非常に非効率的。hファイルだけ上書きしてほしいんですけど・・・
勇気を振り絞って上書きWrite Class Files...にチャレンジしたら、なんだかこんなFileMergeとかいうアプリが立ち上がって、きれいにマージすることができましたとさ。よかったよかった。
では早速Viewに描画処理を追加します。
描画を行うのはUIViewの-(void)drawRect:(CGRect)rectメソッドですので、こいつをオーバーライド。
あとは再描画したいタイミングでUIViewのsetNeedsDisplayをコールすれば適切なタイミングでシステムが再描画してくれるというしくみ。Swingに似てますね。
実際に描画してみました。簡単簡単!!
描画のやり方さえわかってしまえばこっちのものです。
ポリゴンの点の位置を計算するメソッドは例題の中で用意されていたので、それを丸コピーして点の位置に線を引くだけ。線の太さを調節する関数はCGContextSetLineWidthというのが見つかったのでそれを使うだけ。リファレンスが使いやすい!すてき!
カスタムビューの中にUILabelを追加して、ラベルにポリゴンの名称を表示できるようにしてみました。UILabel.textプロパティを書き換えるタイミングはカスタムビューのdrawRectの中で。ほかに良いタイミングが見当たらず。
ひとまずこんなところですかね。次は・・・
- スライダーで線の太さを変える
- 線の種類を何らかのスイッチで変える
- ビューの上でフリックしたらポリゴンがくるくる回るようにする(アニメーション処理の勉強が必要)
2008年11月17日月曜日
CS193P Cocoa Programming - 現在4日目
- メモリの管理についてお勉強
- allocで領域確保(オーバーライドしない)
- initで初期化(オーバーライドして使う)
- 同一オブジェクトを参照するときはretain(オーバーライドしない)
- コピーするときはcopy(オーバーライドしない、copyWithZoneをオーバーライドするべき)
- 解放するときはrelease(オーバーライドしない)
- 実際にメモリから削除されるのはdealloc(オーバーライドして使う)
- NSAutoReleasePoolとautoreleaseメソッド・・・事前にautoreleaseしておいたオブジェクトは[NSAutoReleasePool releaseまたはdrain]呼び出し時に一斉に解放される
1日に二日分前進。iPhone発売から既に4ヶ月経過、既に無数の超優良アプリがわんさかと出回っています。果たして私は遅れを取り戻せるでしょうか。
これはNSURLから文字列を取得する方法を模索していたときです。
結局、absoluteStringかrelativeStringが正解ということがわかりました。
クラスの作成とメモリ管理。ようやくCらしくなってきたかな?
Objective-Cではガベージコレクションもできるらしいのですが、iPhone開発ではガベージコレクタをぶん回せるだけのリソースはないため昔ながらのメモリ管理でやる必要があります。
いろんなイニシャライザをためしてみました。
リストにオブジェクトを突っ込んだときは、突っ込んでいるNSArray自身もリリースしないと、個々のオブジェクトがリリースされません。おそらく内部でretainされてるんでしょうね。
introspection(Javaでいうところのrefrection)にチャレンジ。instanceof演算子みたいなのはなくて、すべてNSObjectのメソッドとして提供されています。java.lang.refrectionパッケージみたいな面倒さはないです。あとセレクタはSEL型とかいう専用の型があって便利。いわゆる関数へのポインタとして使えます。Javaの何が不満ってこの関数ポインタがないところですよ。
続けてもう一つの宿題のほう(Assignment2B)に突入。いよいよ実際に動作するiPhoneアプリを作ることになるのですが、その前に一つ宿題にバグ?があったのでご報告。
上の画像のカーソルで選択している部分(PolygonShape.h)、Assignment2Aで作成したときにはCocoa/Cocoa.hをインポートしていますが、2BではCocoaが使えない(iPhoneアプリになるため)ので、Foundation/Foundation.hに書き換える必要がありました。
で、これが完成品です。
SwingやWin32API開発並みの苦行を覚悟していたのですが、あまりに簡単で逆に拍子抜け。はまりそうな点といえば、プロジェクトに新しくクラスをインポートしたり作成した後はInterface Builderからアプリケーションに登録しなければならないというところぐらいでしょうか。あと、awakeFromNibはコントローラに実装しないとだめ(間違えてPolygonShapeに一生懸命実装して、ビルド直前にこの過ちに気づきました)。
今のところは楽勝。問題はOpen GL ESに手を出すあたりからでしょうかね。
2008年11月9日日曜日
CS193P Cocoa Programming - 1日目の宿題Bをやってみた
- Objective-Cは、見た目とは裏腹に非常に簡単
- Xcodeのリファレンスはきわめて優秀
- Xcodeのコード補完はControl + , またはOption + Escだが使いづらいのでCommand + Spaceに変更する
- Xcodeのコンソール表示(NSLogの内容を確認)はShift + Command + R
それにしてもこの宿題、問題の出し方がうまいです。全く調べないで解けるほど優しくないですが、何処を調べればよいかはきちんと示されています。リファレンスの引き方と自分で調べる力が養えるのがうれしいです(あたりまえなんですけど・・・自分の大学では調べてもさっぱりわからないか、調べ方がそもそもわからないか、調べる必要がまったくないか、というような宿題が多かったので)。
閑話休題。Objective-Cは何一つわかりませんが、とにかく見よう見まねでコードを書いてみます。
おおー動いた!最初このコンソールの出し方がわからず困りました。Shift + Control + Rでした。
調子に乗ってさらに数行記述。リファレンスを引いてNSString同士の結合およびフォーマットのやり方を調べてみました。+で結合できないのが少々面倒(確かC++だとできたはず)。
なれてきたらもう簡単。
それにしてもメソッド名がいい感じに長いです。私はこういうやたら説明的で長いメソッド名が大好きです。
NSArrayのループもこの通り。Javaっぽい。
あとNSDictionaryも調べてみましたけど、Javaと同レベル・・・これはいまいち・・・
JavaScriptやPythonみたいなスクリプト言語らしい使い勝手のいいDictと比べる方が悪いですけどね。
Xcodeの設定。これでコード補完をCommand + Spaceに割り振ることができます。
同じ項目がもう一カ所ありましたが、こちらは変えなくても特に問題ないらしいです。メニューから呼び出しているかそれともテキストエディタの中で直接呼び出しているかの違いのようです。
それでは引き続き残りの宿題をやってしまいますか!
CS193P Cocoa Programming - 1日目の宿題Aをやってみた
- http://www.stanford.edu/class/cs193p/cgi-bin/index.php
- これはわかりやすい
- 宿題があるのが実にうれしい
- Interface Builderで配置したクラスの属性(位置とか表示するイメージとか)を操作するときは、Command + Shift + I またはCommand + 1から4
- Labelの文字の大きさとフォントは変えられたが色とか太字はなぜかうまくいかず
- vertical centerな配置やholizonal centerな配置を行うには、メニューのLayout > Align
手始めに1日目の宿題から。・・・こんなに宿題を嬉々としながらこなす私の姿を学生時代の自分に見せてやりたいものだ。
一つ目の宿題は、コーディングはいっさいなく、interface builderからCocoa Touchが用意しているviewやclassを配置して画面をデザインしてビルドして走らせるだけというもの。
こんな感じでinterface builderにパーツを配置して・・・
できた!初日の宿題だけあって実に簡単。
こういったグラフィカルなGUI作成機能は別に目新しいものではない(Microsoft Visual Studio 2005などでもできる)が、これまで使ったことがあるツールよりは使いやすかった気がする。まぁVS2005はマイクロソフト語で書かれているので読めない=論外だし、Eclipse GEFはそもそもSwing自体があまりよいフレームワークでなかったため使いづらかった。
なによりiPhoneの場合はデバイスの画面サイズが決まっているから絶対座標指定がしやすい。
2008年11月8日土曜日
iPhone開発をこれから始めるときに参考にする資料
- スタンフォード大学の授業が一番わかりやすい
- iPhone Dev Centerのビデオは全体像をつかむために使える
- 良い書籍がないか探索中
- Core Animation, Core Audio, Quartz(Core Graphics), OpenGL ESあたりの使い方に詳しい資料が欲しい
ところが私自身、Mac OS Xでの開発もやったことがないし、XCodeも使ったことがないので、そういう人向けの初めてのiPhoneアプリ開発用資料を集めてみました。
CS193P - Cocoa Programming | Announcements
スタンフォード大学のCocoa Programmingの授業。英語が読めるなら断然これがオススメですね。タダだし。本当にタダでいいんですかこれ?
iPhone Dev Center
Appleの総本山。ここのビデオをiPhoneに突っ込んで通勤中に見るのがオススメです。詳しいところは全く分かりませんが、全体像をつかむには適しています。
それから書籍。正直iPhone開発向けの本はこれ!と言うものがまだ見つかっておらず、Objective-Cの本のみを調査中。
詳解 Objective-C 2.0 荻原 剛志 by G-Tools |
4000円以上しますが、一番評価が高かったのがこれ。
あとはiPhoneのメディア系(アニメーション、画像描画、オーディオなど)の使い方の詳しい解説資料が欲しいのです。こちらは目下捜索中。使うのはHello Worldレベルから脱却してから。
登録:
投稿 (Atom)