忍者ブログ
なんでもいいから書くブログ。iPhoneアプリやAndroidアプリといったスマートフォンアプリを開発していこうと考えてはいるが、はたしてどこまでできるか、、とにかく記録していこうと思い書いているブログである。有益な情報はあるかもしれないし、ないかもしれない。
Admin | Write
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

iPhone 開発Tips


NavigationBar で、バーにタイトルを設定しておけば、

pushViewController で新しいビューを表示したとき、

左側に戻るボタンを表示してくれる。

タイトルを設定しているとタイトル名のボタンに、無い場合は「戻る」となる。


で、戻るボタンにタイトル名は表示してほしいが、バーにタイトルを表示してほしくない場合、

(ややこしい)こんなケース。
バーの右側にいろいろボタンを付けるので、
中央のタイトルだと、表示可能な文字数が少なすぎる。
よって、自前でラベルを付けた。だからバーのタイトルはいらない。
でも戻るのタイトル名は欲しい。

5b3e361f.png





次のように、navigationItemのtitleView をダミーにしてやれば解決できる。

    UIView *viewTmp = [[UIView alloc] initWithFrame:CGRectZero];
    viewTmp.backgroundColor = [UIColor clearColor];
    self.navigationItem.titleView = viewTmp;
    [viewTmp release];


titleView が nil だと、デフォルトの動作(バーにタイトルを表示)だが、

こいつにviewが設定されていると、それを表示してくれるのだ。

なので、タイトルの文字部分に画像を貼付けたり、ボタンを貼付けたり、

UIView を付け替えできるので、なんでも有りですね。

バーの色は tintColor で変更できる(この例だと茶色にしてある)が、

文字色は変更できない。

でも、自前で titleView を付け替えれば 文字色変更、文字サイズ変更もできそうだ。






PR
iPhoneアプリの開発は1人で行っているので、
Subversionのようなソース管理はいらん!っと思っていたが、
アプリのバージョンアップ開発も多くなりそうなので、Subversionを使おうかと思う。

バージョンアップ開発と新規開発と複数手掛けると、
何をどこまでしたか思い出すのに一苦労で。
わりこみ仕事で1週間もほったらかすと、もうわからんのです。


といっても、1人なので、サーバー立てるまでもなく
Leopard以降なら、すでにsvnはインストールされているようで!

じゃぁローカルで。でもHDD壊れると大変なので、
USBメモリにレポジトリを作ってしまおうか。
別に持ち歩かないけどね。


XCode のSCMって機能でSubversionと連携できるようだ。
SCM にリポジトリブラウザ的なものはある。
が見るだけなので、SVNクライアント(GUI)があるといいかな。

まぁXCodeで更新、コミット、比較等はできるんだけどね。


* smartSVN
* Versions
* svnX

svnX が無料のようなので、これを使うことにした。(他はシェアウェア)
(svnX  diff は日本語あるファイルはNGでした。まぁXCodeで比較使うからいいけど。)

  Windows のTortoiseSVN のような扱いやすいものは無料ではないようだ。


んじゃ、リポジトリの作成。

コンソールのコマンドラインにて、

svnadmin create /Volumes/USBMEMORY/myRepos

おぉできた。簡単。

じゃぁsvnXでつないでみます。


svnXを起動して、

「Repositories」というウィンドウで「+」をクリックして、
Name てきとー  Path さっき作ったやつ (虫眼鏡から指定もできる)
User, Password は作ってないから指定なしで。

リストに追加されるので、ダブルクリック。

おぉ!できた。

じゃぁおなじみのディレクトリ構成を作って、

ぁあ、、、長いから今回はこの辺で終わり。

簡単に書くと次のような感じだね。(あくまで一例ですよ)

・ディレクトリを作る
root/Proj/trunk,  branches,  tags  ってとこ。プロジェクト単位に分けた。

・インポートする。
svnXにもインポート機能あるし、SCMのリポジトリにも読み込みっていうのがある。
既存プロジェクトでも新規プロジェクトでも、XCodeのプロジェクトディレクトリを
指定すればオッケーだ。

・チェックアウトする。
これも、svnX、SCMのリポジトリのどちらでもいいし。
インポート時とは別のディレクトリがいいかな。

・チェックアウトしたプロジェクトを開く。

・SCMのリポジトリを構成していない場合は、XCodeのメニューから
「SCM」「リポジトリを構成」で、接続をつくりましょう。

・プロジェクトの情報を見る、右上の「ルートとSCMを構成」ボタンを押す。

・さっき作ったリポジトリの接続を選ぶ

これでオッケー!

あとは「SCMの結果」をみると、変更したり追加したファイルがどーと表示されていく。

好きにコミットすればいいさ。

buildディレクトリとか、まぁ管理不要なファイルは除外したほうがいいね。
実はこの辺はよくわからん。。


まぁとりあえず、これで subversionは使えるな。

















iPhoneアプリ開発

私はiPhoneアプリ開発において、Interface Builder(IB) を使っていません。
最初は使っていたのですが、使わない開発を試したところ、
XCodeとIBの切り替えも発生しないし、IBOutletの連携し忘れもなくなるし、
微妙なレイアウトの位置調整でマウス操作と格闘することもなくなるし、
無駄なnibの読み込みがないので処理が早くなった(ような気がする)し、
メリットが多いので使わなくなりました。
IB は単独で、レイアウトのデザインツールとして使用しています。
部品の配置を調整するには最適なツールですので。

今回ハマッたのは、IBを使ったアプリのバージョンアップで、
IBを使わなくした(nib(xib)ファイルを全部削除した)ときに発生した問題です。
2点あります。(1点目はIBとは関係ありませんが。。)
(1) バージョンアップインストール(古いバージョンを上書きする場合)でアプリが起動しなくなる
(2) 起動するが、ラベルなどの表示がおかしく、動作しない箇所が多々発生する


(1) バージョンアップインストール(古いバージョンを上書きする場合)でアプリが起動しなくなる


今回のバージョンアップは大幅な改良なので、ソースを一から見直そうとプロジェクトを新規作成して作りました。

「Bundle identifier」が同じなら、同じアプリと見なされると思い、プロジェクト名やプロダクト名も変えました(前のはアプリ名とプロジェクト名が違っていたので)。

シミュレータでは、これで問題なくバージョンアップできたので、作業を続け、やっと完成。

実機(開発用のBundle identifier)で確認。問題なく動作! よしよし

いよいよ、Distribution の確認作業へ。

はじめは iPod (3.1.3) のOSで確認。新規も更新も問題なし。

次に、iPhone3GS (iOS 4.1) で確認。新規は問題なし。でも更新は。。。

あれ、、起動しない。一瞬、起動画面がでて、終了。

iPhoneを再起動したり、何回かやり直してみたが NG.

アプリを削除して、もう一度インストールしたら OK. でもこれは新規だから

データ消えちゃうのでだめだ。。

エラー内容は、
実行中...
Ignoring packet error, continuing...
gdb stack trace at 'putpkt: write failed':
0   gdb-arm-apple-darwin                0x0018d893 remote_backtrace_self + 54
1   gdb-arm-apple-darwin                0x00190cab putpkt_binary + 401
2   gdb-arm-apple-darwin                0x001913a8 remote_macosx_get_all_image_infos_addr + 45

さっぱりわからん。

こうなると、なぜ?を考えるのです。
違う部分はどこか、、

一つずつ前のバージョンと違う部分を戻していき、結論は

プロダクト名が違うとダメ


となりました。

プロダクト名は、アプリケーションのファイル名(パッケージ名)のことです( xxx.app )。
(通常はプロジェクト名がプロダクト名になります。)

アプリのバージョンアップ版を開発する場合は、

「Bundle identifier」コード署名 と
プロダクト名(アプリケーションのファイル (*.app)名)

を同じにしないとダメってことですね。ふぅ〜


(2) 起動するが、ラベルなどの表示がおかしく、動作しない箇所が多々発生する

この問題も苦労しました。(1日で原因がわかってよかったです。こういうのネットで調べるの大変、、結局ネット上に答えはなかったし。)

原因は、 nibファイルのキャッシュ (と思っています。)

ようは、昔使っていたnibファイルがなぜかロードされているってことです。
(バージョンアップでアプリを更新しても、どこかに残っているのでしょうか??)

IBを使わない開発に切り替えたので、nibファイルは削除し、コード上で

各部品を初期化、配置しているのですが、なぜか昔のnibファイルの内容が表示され、

重なっていたので、これが原因だと思ったわけです。

で、新規インストールは動くんだから、コーディングは問題ないはずと思い、

どうしたら昔のnibを読まなくできるのか試行錯誤していましたが、

結局、、コーディングが悪い(記述が足りない)ということがわかりました;;

UIViewController のロードで IB を使う場合は、
・-initWithNibName で作って
・viewDidLoad で各部品の初期処理を行う

IBを使わない場合
・-initWithNibName nibファイルにnill 指定 または単に init で作る
・loadView でビューをセットする
・viewDidLoad で各部品の初期処理を行う

2番目のloadView を記述していなかったのが原因なようです。

記述しなくても、本来はデフォルトで問題なく動きます。
(問題なく動くのが問題なのかもしれません。)

でも、今回のように、以前nibファイルを使っていた場合はダメみたいですね。
(なぜ?、どこの?キャッシュが使われているのか、はたまたOSのバグなのか
わかりませんが。)

IBを使わない場合は、loadViewの記述を書く で解決です。

こんな感じです。
- (void)loadView {
    UIView *mv = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
    self.view = mv;
    [mv release];
}

で、viewDidLoad で各部品の初期化をすればいいでしょう。


おわり。

















iPhone開発。

UITableViewCellを継承したカスタムセルの場合、編集モードになった際、インデントしてくれない。

通常は左側に禁止マークが表示された分、右へインデントするわけだが、

カスタムセルの場合、自前でコードを書かなければいけないようだ。(あたりまえ?)

何もしない場合はこんな感じ。

ccc.jpg

で、カスタムセルで次のメソッドをオーバーライドし、個々のサブビューの配置を行う。

- (void)layoutSubviews {
    [super layoutSubviews];
   
    if (self.editing == YES) {
        lblAAA.frame    = CGRectMake(40, 18, 210, 28);
        lblCCC.frame    = CGRectMake(40,  1,  75, 20);       
    }
    else {
        lblAAA.frame    = CGRectMake(10, 18, 250, 28);
        lblCCC.frame    = CGRectMake(10,  1, 100, 20);
    }
}

面倒なので、編集モードとそうでない場合をべたっと書いた。

相対的にうまいことやれば、分岐する必要はないだろう。

結果、こんな感じ。

bbb.jpg













iPhone開発。

またEXC_BAD_ACCESSでハマってしまった。

iPhoneアプリを開発していれば、誰しもこれでハマった経験はあるだろう。

EXC_BAD_ACCESSと出力してフリーズだ。。

いつも発生するならまだしも、たまに発生するケースは厄介。場所が特定できないので。

まぁ原因は、メモリ管理。releaseし過ぎか、retain忘れか。。


で、場所を特定しやすくする方法があったので紹介。

左ペインの「実行可能ファイル」にある実行ファイルをダブルクリックし

そこの引数タブの環境変数に「NSZombieEnabled」を追加して値を「YES」にする。

メモリ解放されずにゾンビとして生き残るということか。

これで、がんばって?!EXC_BAD_ACCESSを発生させる。

運が良ければ?!コンソールに何かしら出力される。

*** -[NSIndexPath release]: message sent to deallocated instance 0x5c5b610

やはり既に解放されているアドレスへのアクセスか。

でもこれで、NSIndexPath ということがわかった。

コールスタックも見覚えのある呼び出し(黒で表示されている部分)があったので、クリック。

- (void)dealloc {
      [lastIndexPath release];
      ...

lastIndexPathという変数だ。こいつが原因!

代入している部分を検索したら、

    lastIndexPath = indexPath;

こんな箇所が。。この変数はプロパティにしているので、

    self.lastIndexPath = indexPath;

が正解。(lastIndexPath = [indexPath retain]; これでもいいけど。)

self. にするかしないかで全く違うのです。

というか、プロパティだからセッターが呼ばれて、

その中で、古いのrelease 新しいのretain ってやってくれているだけだ。これ重要。







iPhone開発ネタ。

OpenALを使うと、仮想の3次元空間にいる感覚で音が聞こえるらしい。

これを使ってゲームを作ろうと思い、使ってみることにした。

ようは音源とリスナー(聞く人)を配置すればいいだけだな。(速度のパラメータを使えばドップラー効果も再現できるようだ。)

サンプルは Appleドキュメントの 「oalTouch」、これを見ればよくわかるし、ほぼ流用できる。

サンプルを実行すれば、3次元空間ではなく2次元だが、左右の違いや、距離による音量の変化はよくわかる。

で、複数の音源もできるようなので、サンプルをちょこちょこっと改良した。

実行。。

音はなる。複数の音源でちゃんとなる。

でも

同じ音量だし、距離や左右の違いによる音の変化はない。(もちろん実機でイアフォンして)

あれれ。。。。

ソースを一つずつ見直し、パラメータを変えたり、位置を変えたりしたが、かわらない。原因不明だ。

3時間くらい格闘しただろうか。

サンプルのソースに徐々に戻しつつ、

サンプルの音源ファイルで試してみるかっと音のファイルを変えてみたら、、

うまくいくじゃん!!!!


ほーー、これが原因?!

ということで、自前で用意した音ファイルはダメだったようだ。

何がダメか、、afconvert で CAFのリニアPCMに変換した(つもり)だが。(元は wav)

実際、細かなことはわからんが、次のように CAFのIMA4 にしたらうまくいった。

(この辺のフォーマット、コーデックの違いはよーわからん。)

afconvert -f caff -d ima4 -d LEI16@22050 -c 1 -o [出力ファイル名].caf [入力ファイル名].wav

だめだったやり方はこれ
afconvert -f caff -d LEI16 [入力ファイル名].wav [出力ファイル名].caf



結局、コーディングは最初の状態で問題なかったので、元にもどした。






iAD.framework は iOS4.0 からの機能なので、3.x のOSでは動作しないわけだ。

でもアプリケーションとしてはiOS4.0 と 3.x のどちらでも動作するものにしたい。

そうしないと、OS 3.x でアプリ実行時に落ちてしまう。。

方法は、Framework を Required から Weak に変更すればよい。

左側のツリーから
「ターゲット」ー「実行ファイル名」ー「バイナリをライブラリにリンク」を選択。
右上の「詳細」にフレームワークの一覧が表示されるので、
その「役割」をRequired から Weak に変更。

OSのバージョン毎に処理を分岐したいなら、次のように判別すればよい。

if
([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0) {
}


(当然、Deployment Target は低いバージョンにしておかないとダメだぞ。)






iPhone開発ネタ。

UIImagePickerController を使用して、写真を撮れるようにしたのだが、(実機の動作確認で)メモリ警告が発生して落ちまくった。。

それまで、メモリ警告は特に意識していなかったが、UIImagePickerController はメモリをいっぱい使うのだろう。(あと、iOS4にしてからマルチタスクなのでアプリ残骸が多々あるせいでもある。。きっと。)

まずハマったのが、なぜ落ちるのか。当然、既に存在しないアドレスにアクセスしてるからだろうが、どこだ??

地道にコールスタックでどこまで処理が呼ばれているか確認していき、ようやく発見。
これは単純なミスだった。release し過ぎて、dealloc でコケていただけ。

次に、カメラ起動後、メモリ警告のせいで、ビューが初期化されてしまい、設定していた値が初期値に戻ってしまう問題。

考えた対処方法は、didReceiveMemoryWarning で値をファイルに書き込んでおき、
viewDidLoadでその一時ファイルがあれば、その値を設定するという方法。

で、値を保存しようと思ってdidReceiveMemoryWarning で拾っても、あれ、、すでにnilじゃん。。

LOGを吐いて呼ばれる順番を確認したら、viewDidUnloadのあとにdidReceiveMemoryWarning が呼ばれている。うーん。viewDidUnloadですでに解放しているし。。

この辺がややこしや。実際は、上の階層のViewControllerのdidReceiveMemoryWarning で下の階層のviewDidUnload が呼ばれているようだった。(ナビゲーションコントローラね。)

しょうがないので、上の階層のViewControllerのdidReceiveMemoryWarning でviewControllersをぐるぐる参照しながら、目的のコントローラに設定されている値をファイルに書き込むように修正。

ふー。

新アプリを作り始めた段階だったので、メモリ警告も考慮して作っていこう。

前作は修正無理だな。まだ申請中だけど。まぁテスト時に一回もメモリ警告でていないので、大丈夫なんじゃないかなぁ。。写真撮影使っていないし。


メモリ警告のデバッグポイントは、AppDelegateのapplicationDidReceiveMemoryWarning
から、順に呼ばれるdidReceiveMemoryWarning と viewDidUnload を追っていくこと。

コールスタックでどこで落ちているかつきとめること。

まぁだいたいはあれだ、既に解放されてやんのってやつだ。










ログはNSLog を使って簡単に出力できるが、リリース構成では入れておきたくないもの。

いちいちコメントアウトするのも面倒だし。

そんなときマクロが記述できるCはいいよね。コンパイル時に置き換えてくれるので、無駄な処理も入らないし。

こんな感じ。(適当に共通のヘッダーファイルに書き込んでおけばオッケーだよね。)

#ifdef DEBUG
#define LOG(...) NSLog(__VA_ARGS__)
#else
#define LOG(...)
#endif

で、プロジェクトの情報から「ビルド」のプリプロセッサマクロに "DEBUG"と追加してやれば、
DEBUG とそうでない場合で、置き換えてくれる。

使い方は NSLog が LOG になっただけ。
LOG(@"hogehoge: %d", intValue);
のような感じで。





久々のブログ更新。ようやく1つiPhoneアプリが完成したので、申請中。

勉強含め3ヶ月かかってしまった。

1、2ヶ月でできるかと思ったが、つまずくとピタっと開発が止まってしまう。1人だから。。

申請中にボーとしているわけにもいかないので、次の開発を始めます。

今回は、1つずつ整理しながら進めようかな。要領もわかったことだし。


まず、Interface Builder を使わない開発手法をやってみたいと思います。

1. "Resources" のMainWindow.xib を削除します。
2. XXX-Info.plist の "Main nib file base name" 項目を削除します。(XXXはプロジェクト名)
3. main.mを次のように修正します
int retVal = UIApplicationMain(argc, argv, nil, @"XXXDelegate");
4.XXXDelegate.mで次のようにコードを追加し、自前でwindowを作成します。
また、ルートビューとなるビューを window のサブウィンドウとして追加します。
(この例ではラベルビューとしています。)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {   
   
    CGRect frameWindow = [[UIScreen mainScreen] bounds];
    window = [[UIWindow alloc] initWithFrame:frameWindow];
   
    //
    CGRect rect = [window frame];
    UILabel *label = [[UILabel alloc] initWithFrame:rect];
    label.text = @"Hello, world!";
    [window addSubview:label];
    [label release];

    // Override point for customization after application launch.   
    [window makeKeyAndVisible];
   
    return YES;
}


よし、できた。

今仮にラベルにしているところを必要なViewにしてやればいいわけだ。

YamaTatsuのiPhoneアプリ
iTunes Store でみる
LightOff Light Off Hot New
点いたライトを素早く消そう!
誰でも遊べるシンプルなゲームです

めいろであそぼう めいろであそぼう New
かわいいイラストのめいろ、ぬり絵もできる
子供向けの迷路あそびです。※iPad専用

運試し 運試し NEW
15連続の確率は0.0001%
操作は簡単 好きなパネルを選ぶだけ。どこまで進めるか運試し!

連打 連打! まだまだ人気
16連射に挑戦
10秒間で何回ボタンを押せるか競うゲームです。

うちメモ うちメモ ★大人気★
買い物中に 「まだあったかな?」 と思った経験 ありませんか? 「うちメモ」していれば大丈夫!!

BestBowling Best Bowling
マイボウラーに大人気! ボウリングのスコアを管理するアプリです。

イメージ貯金 イメージ貯金
貯金はモチベーションが重要! 目標を設定して毎日楽しく貯金しよう!

Mine Escape Mine Escape
聴力は優れていますか? 音で機雷の位置を判断する新感覚のアクションゲーム!

Rank Checker Rank Checker
だって気になるじゃないですか、、 アプリ開発者必須! AppStoreのランキングをチェックツールです。


カレンダー
03 2024/04 05
S M T W T F S
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Twitter
プロフィール
HN:
YamaTatsu
HP:
性別:
非公開
自己紹介:
iPhoneアプリを開発してまーす。
最新コメント
[06/04 K.I.T]
[06/03 Cotoba]
[05/19 K.I.T]
[05/18 コタツ猫]
最新トラックバック
ブログ内検索
バーコード
忍者アド
アクセス解析
忍者ブログ [PR]

Designed by