UITableView reloadDataでnumberOfSectionsInTableViewが呼ばれない

ユーザーが別画面で情報編集後、一覧画面のテーブルビューを更新したいことがあります。

テーブルビュー側の viewWillAppear で reloadData を実行すればテーブルが更新されますが、
[super viewWillAppear:animated]との順番によって動作が変わる点に注意しなくてはなりません。

<NGの例>

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.tableView reloadData];
}

一見よさそうですが、以下の2点で問題があります。
・ビューの最初の読み込み時に、numberOfSectionsInTableView が重複して呼ばれてしまう
・他のビューから戻ってきた時に、numberOfSectionsInTableView や numberOfRowsInSection が呼ばれず、cellForRowAtIndexPath だけ呼ばれてしまう可能性がある。セクション数などが変わった場合、Appが落ちる原因となる。

<OKの例>

- (void)viewWillAppear:(BOOL)animated {
    [self.tableView reloadData]; // OK
    [super viewWillAppear:animated];
}

上記2点の問題が解消されます。

値一覧で選択後、数字フィールドに数字ばかり表示される

数字フィールドの選択肢を、値一覧を使って表示させたとき、選択後に値一覧内の文字列が消えてしまい数字が残り、桁数が多いため1.308+15eなどと表示されてしまうことがあります。
クリックすると、ポップアップ内ではきちんと値一覧の文字列が表示されます。

これは、このフィールドをレイアウトモードで書式設定したとき、「一般」になっているのが原因です。
「入力モードそのまま」に変更すると、選択後も文字列がきちんと表示されます。

iTunesのApp Storeでカテゴリページが表示されない

プログラミングとは関係のないタイトルですが、
MelodyMemoのリリースを確認したくて、タイトルの現象に遭遇。

Mac OS X 10.7
iTunes 11.0.5

この環境で、iTunesを起動しApp Storeを眺めようとしたところ、
トップページは表示されますがカテゴリを選ぶと真っ白ページになるじゃありませんか。

実は、日本以外のStoreを見たことがありまして、どうもその時を境に
問題が発生しているのではという気がしたので
画面右下の丸い国旗マークをクリックし、一旦別の国にして
再度日本に戻したところ、無事表示されました。

一瞬焦りましたが、めでたしめでたし。

TitaniumでAndroid実機に変更が反映されない

Titanium Studioをインストール後、色々試すうちにつまづいたことをメモします。

結論:サンプルソースはよく見よう。

新規プロジェクトを、「Tabbed Application」をもとに作成しました。

app.jsを見ると

//considering tablet to have one dimension over 900px - this is imperfect, so you should feel free to decide
//yourself what you consider a tablet form factor for android
var isTablet = osname === 'ipad' || (osname === 'android' && (width > 899 || height > 899));

var Window;
if (isTablet) {
    Window = require('ui/tablet/ApplicationWindow');
}
else {
    Window = require('ui/handheld/ApplicationWindow');
}

こうなってます。

Android実機はスマホ(Arrows X F-10D)なので、「isTabletはfalseになるだろうから、ui/handheld/ApplicationWindow.jsをいじればよかろう」と思い
まずはボタンを追加。エミュレータで実行し、変更(ボタン増加)を確認。
よしよし、ということで実機で実行。
・・・あれ?ボタン増えてないぜ、にいちゃんよぅ(因縁付け)。

何でよーと思いながら、クリーンしたりbuildフォルダ削除したり、Android側でアンインストールしたり
何度ビルドし直しても、結果は変わらず。

んで、ソースをふと見返すと。。「isTabletは、ほんまにfalseか?」と。(気付くの遅い)

これがビンゴで、widthが1280あったため、isTabletはtrueになってました。ちゃんちゃん。
ご丁寧にコメントにも書いてありますし。完全に見落としました。

同じことで悩む人がいませんように〜。

Xcodeで、フォルダ構成を維持したままリソースをコピーする

UIWebViewがローカルのhtmlを読み込む形のアプリケーションを作成する際の話です。

通常のWebサイトと同じように、Javascriptやcss、画像などをそれぞれまとめてフォルダに入れると思います。

Xcodeでは、通常だとリソースの参照をグループ化できますが、htmlではリソースをコピーする際に、実際にフォルダを作ってその中に画像等をコピーさせる必要があります。

それをするには、リソースを追加する際の以下のダイアログで、
Create folder references for any added folders
を選択します。

folder

これで、ビルド時にフォルダが作成され、フォルダ構成を維持したままリソースがコピーされるようになります。

参考:
リソースファイルをフォルダ階層を維持しながらコピーさせる:永遠ログ

adb devicesでofflineと表示される

Android開発時、実機をUSB接続してもEclipseからデバッグ実行できない、
ターミナルでadb devicesを実行すると、offlineと表示される。

こうなったとき、以下の手順で復旧できました。

1.一度USBを抜き、再度実機に挿し込む。
2.実機の「設定→開発者向けオプション→USBデバッグ」のチェックボックスをOffにし、再度Onにする。
3.ターミナルで、次のコマンドを順に実行する。
adb kill-server
adb start-server
4.実機を再起動する。

——–
WiFi経由でデバッグしたくて、adb tcpip やadb connectを実行してから、動作がおかしくなりました。
他にお困りの方のご参考になれば幸いです。

参考:
Why does adb return offline after the device string?

自分で拡張子を定義し、メール添付経由でファイルを受け取る

自分のAppで独自のファイル形式を使っているとき、拡張子も独自のものにしていると思います。

メールの添付ファイルを開くときなど、他のAppから自分のアプリへ「送る」「開く」
をしてもらえるようにする方法です。

まずは、(App名)-Info.plistを開きます。

Infoplist

「Document types」と、「Exported Type UITs」を追加します。
Document Content Type UTIs、Identifier … 独自のファイル形式を指す、システムでユニークな名前を指定する(ドメイン形式を逆にしたものが推奨されるとのこと)
public.filename-extension … 拡張子をシステムに宣言する

fileextension

ここまでできたら、ビルドして実機で実行すると、
インストールとともに、システムに拡張子が登録されます。

メール添付などでこの拡張子のファイルを「送る」と、
自分のAppが選べるようになります。

この後、UIDocumentInteractionControllerの仕組みを通じて
自分のAppで受け取るコードを追加していきますが、
それについては以下のページを参照してみて下さい。

参考ページ:
iOSの中で、アプリケーション同士が連携するためのしくみ
UIDocumentInteractionControllerによる、アプリケーション間のファイル受渡し
iOSでユーザ拡張子を定義する方法

XcodeでiOSデバイスを選択できないかNSInvalidUnarchiveOperationExceptionが発生する

プロジェクトのターゲットOSが最新のときは、旧OSを使用したiOSデバイスを対象にしたビルドや実行はできません。

デバイスで実行したいときは、プロジェクトのターゲットOSを下げる必要があります。
xcode1

また、デバイスで実行すると以下のエラーが発生することがあります。

Terminating app due to uncaught exception ‘NSInvalidUnarchiveOperationException’, reason: ‘Could not instantiate class named NSLayoutConstraint’

これは、Storyboardの設定が旧OSでサポートされていないのが原因です。
xcode2

具体的には、「Use Autolayout」のチェックを外す必要があります。

xcode4

これで実行できるはず。

UIPickerViewのselectRowが動かないとき

例えば、ピッカーを2つ設置したとします。

一方のピッカーの選択によって、他方のピッカーの値をselectRow:inComponentによって変えるとき、
その他方のピッカーが動かないことがありました。

以下のようなコードです。

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    /* ... */

    // 選択させる
    [pickerView selectRow:rowIndex inComponent:0 animated:YES];
    // 選択後の動作をさせる
    [self pickerView:pickerView didSelectRow:rowIndex inComponent:0];
}

ネットで情報がうまく得られなかったため、以下のようにperformSelectorを使ったところ、解決しました。

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    /* ... */
    _index = rowIndex;
    [self performSelector:@selector(selectPicker2:) withObject:self afterDelay:0.01];
}
- (void)selectPicker2:(id)sender
{
    [_picker2 selectRow:_index inComponent:0 animated:YES];
    [self pickerView:_picker2 didSelectRow:_index inComponent:0];
}

iOSシミュレータで音が鳴らない/ファイルが読み込めないことがある

いつも通りビルドしたつもりなのに、突然下記の症状が出ることがあります。

  • 音声が再生されない
  • 画像が表示されない
  • ファイルが読み込めない

特に音については、CocosDenshion(SimpleAudioEngine)の使用方法や
caf/mp3/wav/aifファイルの作成方法、
afconvertコマンドでの引数指定を間違えたのか、と思いがちです。

トリガーとなるのは、直前のクリーンとリソースファイルの登録し直しです。

原因は、
Project Navigator のプロジェクト→TARGETS→Build Phases→Copy Bundle Resources
に該当のリソースファイルが登録されていないからです。
しかしここに追加しても根本的な解決になりません。

.png以外のリソースファイルをXcodeウィンドウにドラッグアンドドロップすると、
直後の「Choose options for adding these files」ダイアログにて
Add to targetsオプションでターゲットのチェックが外れています。
(.pngファイルだと、ターゲットにデフォルトでチェックが付きます)

よって、リソースファイルが更新されてもコピーされずに以前のデータが使われていたが、
クリーンしたことでそのデータも消えてしまった、というわけです。

ドラッグアンドドロップ後のダイアログによく注意し、
ターゲットにチェックを付けるようにしましょう。