UITableViewをコードで追加しスクロールバーを点滅させる

InterfaceBuilderを使わずにUITableViewを作成したとき、

UITableView* tableView = [[UITableView alloc] init];
[_controller.view addSubview:tableView];
[tableView flashScrollIndicators];
/* or */
[tableView performSelector:@selector(flashScrollIndicators)];

としてもスクロールバーが点滅しないことがあります。
以下のように、performSelector:withObject:afterDelay: を使うと点滅させることができます。

UITableView* tableView = [[UITableView alloc] init];
...
[tableView performSelector:@selector(flashScrollIndicators) withObject:self afterDelay:0.0];

Xcodeをアップデートするとビルドエラーが発生する

Xcodeをアップデートした後の最初のビルド時に、
以下のようなエラーが発生することがあります。


error: PCH file built from a different branch ((clang-425.0.27)) than the compiler ((clang-425.0.28))

この時は、一旦クリーンしてビルドし直すとエラーが解消されます。
Product → Clean

なお、シミュレータ、実機のそれぞれでクリーンが必要になります。

アプリの画面を横向きに固定する

Xcodeのプロジェクト設定(TARGETS設定)の
iPhone / iPod Deployment Info → Supported Interface Orientations
にて
「Landscape Left」 or 「Landscape Right」
を選択しても横画面にならないときは、
ViewControllerのサブクラスにて下記のメソッドを追加します。

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    BOOL ret = NO;
    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight) ret = YES;
    return ret;
}

このtoInterfaceOrientation には、向きが入ってきますので、許可する向きの値のときに
YESを返すようにします。

UITableViewのセクションのタイトル行を非表示にする

セクションのタイトル行(バー)そのものを非表示にするには、tableView:titleForHeaderInSection: で空文字列(@””)を返します。

- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    return @"";
}

セクションが複数あったとしても、非表示になります。

UITableViewの編集モードで移動マークを表示させる

UITableViewDelegateを実装したUIViewControllerのサブクラスで、
以下のメソッドを定義すると、移動マークが表示されてドラッグにより移動可能になります。

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath
{    
    // 移動後のデータ並び替えのコードを記述
}

UITableViewで横スワイプ時に削除ボタンを表示させる

UITableViewDelegateを実装するUIViewControllerのサブクラスにて
tableView:commitEditingStyle:forRowAtIndexPath:
のメソッドを定義すると、
横スワイプで削除ボタンが表示されるようになります。

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        // 削除するコードを挿入します
    }
}

バウンス後の音量は「ノーマライズ」オプションで変わる

Logic ProでMP3としてバウンスしFinderで聴いたところ、全体的に音量が大きかったため、
マスターボリュームで音量を下げて再度バウンス。
しかしなぜか大きいまま。

原因は、バウンス時のダイアログで「ノーマライズ」オプションがオンになっていたため。
オフにしたら、マスターでの調整通り音量が下がりました。
Logic Pro/Express 8 and 9:「バウンス」ダイアログのノーマライズ機能に関するディスカッション

こんなことも知らないなんて、ちょっと恥ずかしい。。
でも、一歩ずつ慣れていきます。

actionは都度新規生成する必要がある

CCShow, CCHideなどの CCAction系クラスのインスタンスは、再利用すると動作がおかしくなります。
[CCShow action]などと、利用する都度新規生成しなくてはなりません。
(これに気付かず数時間を費やしてしまいました)

参考

以下がそのNGコードです。

id acShow = [CCShow action];
id acDelay = [CCDelayTime actionWithDuration:1.0];
id acHide = [CCHide action];
[sprite1 runAction:[CCSequence actions:adShow,acDelay,acHide,nil]];
[sprite2 runAction:[CCSequence actions:adShow,acDelay,acHide,nil]];

正しくは、actions内で都度生成する必要があります。

removeChildByTag で EXC_BAD_ACCESS が発生する

cocos2dにて、CCMenu を何度か追加・消去するプログラムを作成していたところ、
EXC_BAD_ACCESS が発生しました。

具体的には、CCMenuItem が3つ入った CCMenu を構築したあと、
メニューアイテム・メニュー全てを removeChildByTag できれいに削除しようとしました。

CCNode* menuanswers = [self getChildByTag:kTagAnswers];
[menuanswers removeChildByTag:kTagAnswer1 cleanup:YES];
[menuanswers removeChildByTag:kTagAnswer2 cleanup:YES];
[menuanswers removeChildByTag:kTagAnswer3 cleanup:YES];
[self removeChildByTag:kTagAnswers cleanup:YES];

最後の行で EXC_BAD_ACCESS が発生。
発生したのは、CCMenu -onExit にて以下の[selectedItem_ unselected]の部分。

- (void) onExit
{
	if(state_ == kCCMenuStateTrackingTouch)
	{
		[selectedItem_ unselected];
		state_ = kCCMenuStateWaiting;
		selectedItem_ = nil;
	}
	[super onExit];
}

CCMenu は、CCMenuItem が最後まで生きていることを前提にしているようなので、
CCMenu のみを削除することで対応しました。

NSKeyedArchiverでデータをファイルへ保存する

iOSでデータを永続化しファイルへ保存するには、いくつか方法があるようです。ここではNSKeyedArchiverを使った方法をご紹介します。

以下のメソッドは、3つの変数を受け取り、ファイル保存までを行います。

- (void)saveToFileWithVar1:(id)var1 var2:(id)var2 var3:(id)var3
{
    NSMutableDictionary* dicToSave = [[NSMutableDictionary alloc] init];

    NSMutableArray* arrayVals = [[NSMutableArray alloc] init];
    [arrayVals addObject:[[NSDictionary alloc] initWithObjectsAndKeys:
                  var1,@"var1",var2,@"var2",var3,@"var3", nil]];
    // add to dictionary
    [dicToSave setValue:arrayVars forKey:@"vars"];

    NSNumber* value;
    // add numbers
    value = [NSNumber numberWithDouble:1.0f];
    [dicToSave setValue:value forKey:@"value1"];
    value = [NSNumber numberWithDouble:3.5f];
    [dicToSave setValue:value forKey:@"value2"];

    // save to file
    [NSKeyedArchiver archiveRootObject:dicToSave toFile:@"/path/to/file"];
    [dicToSave release];
}

ファイルに保存するのは1オブジェクトです。従って、ここでは辞書オブジェクト dicToSave の内容をファイルに保存します(N行目)。

つまり、dicToSave辞書に、保存したいデータを放り込んで行けばよいわけです。この例では、配列1つ(キーはvars)と数値2つ(キーはvalue1、value2)を放り込んでいます。

NSMutableArrayなどの配列へ、プリミティブ型を格納できないことには注意しましょう。