証明書が切れた

iPhone OS 3.0の発表と同時に開発用の証明書の有効期限が切れた。

切れるとどうなるか。特に環境を変えたりしなければそのまま使えるっぽい。
キーチェインを見るとバツが付いてて、有効期限切れであることが書いてある。
そんでもってビルドに失敗する。
でも2.2.1環境でビルドするとちゃんと通る。
なんだかややこしいな。

つい最近プロビジョニングプロファイルを作り直したような気もするけど、
もう一回証明書から作り直すとちゃんとビルドできた。

新しいSDKをインストールしたせいかと思って慌ててしまったのにこんなオチとは。。。
やれやれ。

UISliderのトラッキング

iPhone OS 2.2から挙動の変わってしまったUISliderだけれど、デバッガーで適当な所で止めてUISliderのインスタンスの中身を覗くと色々見えてくる。

UISlider.hを見ると、以下のフラグが並んでいる。

struct {
	unsigned int continuous:1;
	unsigned int animating:1;
	unsigned int showValue:1;
	unsigned int trackEnabled:1;
	unsigned int creatingSnapshot:1;
} _sliderFlags;

で、デバッガーで_sliderFlagsを開いてtrackEnabledの値を1に変更してみる。実行するとiPhone OS 2.1の頃のようにサムだけでなく、バーの部分も反応することが確認できる。

調子に乗ってshowValueも値を1にしてみる。するとスライダーの右側に現在値が表示されるようになる。スライダーの左右にイメージを乗せることができるけれど、その場合、現在値を表示していると色々崩れてしまう。この辺り、showValueが潰されている理由が見える。

実際にコードで上記の値をセットするにはどうしたらいいのかと思ってErica女史のハックを参考にしたら、プライベートメソッドがある事が判った。以下のような定義をソースに加えると、コード側から値をセットできるようになる。

@interface UISlider (extend)
- (void)setShowValue:(BOOL)value;
- (void)_setTrackEnabled:(BOOL)value;
@end

一応ドキュメントには載っていない方法なので、実行は自己責任でお願いします、と。

テーブルの編集モードを細かく設定する

テーブルビューを編集可能なモードにするには、

- (void)setEditing:(BOOL)editing 
	animated:(BOOL)animated;

で編集モードにすればいいのだけれど、例えばセクションが二つあって、一方は編集可、もう一方は編集不可な状態を作りたい場合には、UITableViewDataSourceの、

- (BOOL)tableView:(UITableView *)tableView 
	canEditRowAtIndexPath:(NSIndexPath *)indexPath;

で編集可能にするrowをコントロールすることができる。もちろんrowだけじゃなくて、NSIndexPathでsectionを取得してセクション毎に編集可/不可を切り分けちゃうのも可。例えば最初のセクションは編集不可、二つ目のセクションは編集可にするにはこんなコードでOK。テーブルを編集状態にしても最初のセクションは影響を受けない。

1
2
3
4
5
6
7
8
- (BOOL)tableView:(UITableView *)tableView 
	canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
	if ([indexPath section] == 0) {
		return NO;
	}
	return YES;
}

それにしてもCocoaのメソッド名って長いな。

新しい開発機を追加する

iPhone以前に使っていた初代iPod touch 16GBを奥さんにあげたつもりが、彼女が普段嬉々として使っているのは初代iPod nanoだったりする訳で、このままiPod touchをガジェット箱に収めておくのももったいないので開発機として使ってあげる事にしました。

OSが1.1.4だったので2.2.1までアップデートしたんですが、そこは省略。

接続した状態でXcodeを起動すると、開発機として使うかどうか聞かれるので素直に「使う」と答えておく。さて、適当なプロジェクトをビルドして転送。エラー。

以下のような手順が必要。手抜きは認めんっていうことらしい。

  1. 新しいデバイスIDを登録
  2. Provisioning Profileの編集
  3. Xcodeのプロジェクトの設定更新

新しいデバイスIDはオーガナイザやiTunes上で実機のIdentifierとして表示されている長いIDをコピー。プログラムポータル上でIDを追加する。

続いてProvisioning Profileの編集を開くと、先ほど登録したIdentifierのデバイスがチェックが外れた状態になってるのでチェックして保存。ダウンロードしたProvisioningをダブルクリックすればXcodeを通して実機にも転送される。

さぁ、適当な既存のプロジェクトをビルドして…。以下のようなエラーが出てビルドすらできません。
CodeSign error: a valid provisioning profile is required for product type 'Application' in SDK 'Device - iPhone OS 2.2.1'

最後にXcodeのターゲットのコード署名IDのIDが古いもののままなので新しいものと置き換えてあげる必要がある。

  1. プロジェクトのサイドバーのターゲットの情報を見る
  2. コード署名IDのポップアップで選択されているIDを確認
  3. リストの上の方にある正しいProvisioning Profileを選択し直す

これは手動でやらないと変更されないので注意。これで新しい開発機を追加する事ができる。ちなみに別のプロジェクトファイルを開いたら問題なく実行できるものもあった。比較的最近のSDKだとiPhone Developer: Hoge Hogeって追記する必要がなかったりするので、扱いが変わったのかなー。

追記@2009/03/02
一つ手順を飛ばしてたのだけれど、プロジェクトの情報側のコード署名IDも古いままです。ターゲットの情報と同様の更新をする必要があります。

ViewのRotate

常時横向きなアプリで、スピーカーの位置を考慮して上下の回転をサポートしようと思ったのだけれど、最初は動いていたのがいつの間にか回転しなくなってたのでちょっと調べました。

基本は以下のコードで上下の回転はサポートできた。UIInterfaceOrientationの値で必要な向きだけ処理できる。

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
- (void)viewDidLoad {
    UIInterfaceOrientation orientation =
    [[UIApplication sharedApplication]
    statusBarOrientation];
    [super viewDidLoad];
    if (orientation ==
    UIInterfaceOrientationLandscapeRight ||
        orientation ==
    UIInterfaceOrientationLandscapeLeft) {
        CGAffineTransform transform =
    self.view.transform;
        CGRect statusBarFrame =
    [[UIApplication sharedApplication] statusBarFrame];
        CGRect bounds =
    CGRectMake(0, 0,
    statusBarFrame.size.height,
    statusBarFrame.origin.x);
        CGPoint center = CGPointMake(
    bounds.size.height / 2.0,
    bounds.size.width / 2.0);
        self.view.center = center;
        transform = CGAffineTransformRotate(
    transform, (M_PI / 2.0));
        self.view.transform = transform;
    }
}
1
2
3
4
5
6
7
- (BOOL)shouldAutorotateToInterfaceOrientation:
    (UIInterfaceOrientation)interfaceOrientation {
    return ((interfaceOrientation ==
    UIInterfaceOrientationLandscapeRight) ||
    (interfaceOrientation ==
    UIInterfaceOrientationLandscapeLeft));
}

実はUIViewAnimationTransitionで二つのビューをトグルするようにしたので、RootViewControllerを用意して、二つのViewControllerをぶら下げて、それぞれのViewControllerに上記のコードを書いた。そうしたら回転しなくなっちゃった。まあ回転する部分のコードは実績のあるものなので、問題はなかろうと。

RootViewController側で処理するべきだろうと上記のコードを加えたら、回転はするもののViewが描画されなくなった。ここでようやく理解した。RootViewControllerで回転処理されてさらに子のViewも回転処理されたらのであらぬ方向へ行ってしまったのかなと。子のViewControllerで回転処理をコメントアウトしたら問題なく描画されて回転もできた。

結局shouldAutorotateToInterfaceOrientationも子のViewControllerでは必要ないみたい。