Browsing all articles in iPhone Dev
2月
5

Xcode4.6でアプリの新バージョンをアップロードする手順

Author msota    Category 作業記録     Tags

拙作Swim Noteの新バージョンをアップロードしたので、その手順のメモ。前のバージョンと何も変わっていなかった。

0. 事前準備

  • スクリーンショットを取り終えておく
  • Xcodeでアプリのバージョン番号を設定しておく
  • (当たり前だけど)不要なログ出力等の余計な処理をしないようにする
  • (これも当たり前だけど)使わなくなったファイル等は消しておく

1. iTunes Connectでの作業(目的:新バージョン情報の登録)

  • SafariでiTunes Connectにログイン
  • 右側にあるManage Your Applicationをクリック
  • アップデートしたいアプリをクリック
  • 右下にある青いボタン「Add Version」をクリック
  • 表示された画面で、バージョン番号(このバージョン番号は、Xcodeで設定した番号と同じであること)と、アプリの更新内容を入力する。複数言語をサポートしている場合は全て記入する
  • 入力が完了したら、右下の「Save」をクリック→アプリ情報の画面になる
  • アプリ情報に表示されているメタデータやスクリーンショットを修正する場合は、画面中段の「Metadata and Uploads」のところにある「edit」をクリックする
  • スクリーンショットを入れ替える場合は、表示された画面の削除したいスクリーンショットのところで×ボタンを押して、一旦削除した後に「Choose File」をクリックしてアップロードする。表示する順番はドラッグ&ドロップで入れ替える
  • 修正が完了したら、画面右上の「Ready to Upload Binary」をクリック
  • Export Complianceという画面になり、ラジオボタンが2つ並ぶ。ここに書いてあるようなことをしていなければ「No」を選択し、右下の「Continue」を押す
  • Version Release Controlという画面になる。承認されたら自動リリースするか(上)、自分でリリースするか(下)を選択し、右下の「Save」を押す
  • アプリ情報の画面に戻る。Statusが「Waiting For Upload」になっていることを確認する

2. アプリのアップロード(Xcodeでの作業)

  • iOSデバイスをMacに接続し、Xcodeが正しく認識している状態にする
  • Productメニューから Archive を実行
  • Archiveが終了すると、自動的にOrganizer画面が開き、Archivesリストが表示される
  • リストにて作成したバージョンを選択した状態で右側の「Validate…」ボタンをクリック
  • iTunes Connectのユーザ名、パスワードを聞かれるので入力し「Next」ボタンをクリック
  • 表示されたApplication, Code Signing Identityが正しいことを確認して「Next」ボタンをクリック(検証処理をするため時間がかかる)
  • 検証で問題なければ「No issues were found in “アプリ名”」と表示されるので「Finish」ボタンをクリック→Organizerに戻る
  • そのまま「Distribute…」ボタンをクリック
  • Submit to the iOS App Storeを選択して「Next」ボタンをクリック
  • iTunes Connectのユーザ名、パスワードを聞かれるので入力し「Next」ボタンをクリック
  • 表示されたApplication, Code Signing Identityが正しいことを確認して「Next」ボタンをクリック(アップロードをするため時間がかかる)
  • アップロードで問題なければ「No issues were found in “アプリ名”」と表示されるので「Finish」ボタンをクリック→Organizerに戻る

3. 確認

Appleから「Your app status is Waiting For Review」というメールが来ているはず。iPhoneにiTC Mobileを入れていたらそちらにも。

7月
13

TapkuLibraryをXCode4に組み込む

Author msota    Category 逆引き備忘録     Tags

CoverFlowやカレンダーが使えるライブラリTapkuLibraryをXCode4で組み込んだ。

まず、ライブラリをgithubから取得する。

  • どこか適当にライブラリの置き場を決める(とりあえず~/Documents/dev/tapku にした)
  • ターミナルを開き、cdで置き場に移動
  • git clone git://github.com/devinross/tapkulibrary.git
  • ~/Documents/dev/tapku/tapkuLibrary ができる

続いて、プロジェクトに導入する。

  • XCodeで、TapkuLibraryを導入するプロジェクトを開く
  • 左側のツリーからFrameworksを選び、マウス右ボタンメニュー「Add files to project」を実行
  • 画面から ~/Documents/dev/tapku/tapkuLibrary/src/TapkuLibrary.xcodeproj を追加
  • 同様に ~/Documents/dev/tapku/tapkuLibrary/src/TapkuLibrary.bundle を追加

続いてBuild Phasesの設定をする。

  • PROJECTのTARGETSを選び、Build PhasesタブからTarget Dependenciesを選ぶ
  • +ボタンから、TapkuLibraryを追加する
  • 同じタブにある Link Binary With Libraries を選ぶ
  • +ボタンから、libTapkuLibrary.aを追加する
  • 同様に、MapKit、QuartzCoreを追加する

最後にBuild Settingsに追加する。

  • Build Settingsタブを選択する
  • タブの下にあるツールバーからAllを選択する
  • Header Search Pathsに、~/Documents/dev/tapku/tapkuLibrary/src/ を追加する
  • Other Linker Flagsに、-all_load -ObjC を追加する

アプリケーションへの組み込みは、当然ながらXCode3の時と同じ。

7月
12

カスタムキーボードを作成する

Author msota    Category 逆引き備忘録     Tags

iPhoneで文字入力する際のキーボードを、カスタムキーボードに変更した。目的としては、定型文しか入力しないフィールドに対して選択肢を用意し、入力を簡単にすることである。

それだけを目的とするならピッカーでも同じことはできるのだが、現在作っているアプリケーションでは、ピッカーをグルグル回して選択するよりも並んでいるボタン状のものから選ぶ方が好ましいと思われたので、カスタムキーボードにした。

さらに言うと、単に選ぶだけならUIAccessoryViewを使っても同じようなことが出来そうだが、本来のキーボードも併用して切り替えられるようにしたかったので、カスタムキーボードにしてみた次第である。

大雑把な手順は以下の通り。

  1. UITextFieldクラスを継承して、カスタムテキストフィールドクラスを作る(CustomTextFieldとする)
  2. Interface BuilderでCustomTextFieldをビューに配置する
  3. カスタムキーボードに相当する新しいxibファイルを、UIViewベースで作成する(CustomKeyboardInputViewとする)
  4. xibファイルをInterface Builderで起動し、入力選択肢(キーボードのキー)に相当するボタン(UIButon)を配置する
  5. 3. で作成したカスタムキーボードに対するビューコントローラクラスを作成する(CustomKeyboardInputViewControllerとする)
  6. 5. で作成したビューコントローラを、4. で作成したxibでFile’s Ownerに対するビューコントローラに設定する
  7. 1. で作成したCustomTextField.mを編集し、inputViewメソッドをオーバーライドする。このメソッドで、3.で作成したxibを使ってビューコントローラ(4.で作成したCustomKeyboardInputViewController)を生成し、そのビューコントローラに対するビューを戻す
  8. CustomKeyboardInputViewController.mを編集し、ビュー上のボタンが押された際のメソッドを記述し、呼び出し元となったカスタムテキストフィールド(CustomTextField)に適切な値をセットする

当然ながら、Interface Builderではなくプログラムでガリガリ書いても同じ(はず)。

この手法の考え方としては、UITextFieldやUITextView(を継承したサブクラス)のinputViewメソッドをオーバーライドして、新たに定義したキーボード(のUIView)を返すようにすれば、カスタムキーボードを表示できる、というものである。

一旦キーボードを表示してしまえば、あとは通常のビュー間でのデータのやりとりと同じ手法で、カスタムキーボードの呼び出し元になったテキストフィールドに、カスタムキーボードで選択したボタンに相当する値をセットしてやればよい。

サンプルソースは以下の通り。
本筋とは関係ない処理は全て削ってある。
本来は、本来のキーボードと切り替えるためのAccessoryViewを作ったり、その切り替え処理を組み込んだり、キーボードで選択したボタンに対する処理など、色々とやることはあるのだが、それらは除外した。

CustomTextField.h

#import 

@interface CustomTextField : UITextField {

}

@end

CustomTextField.m

#import "CustomTextField.h"
#import "CustomKeyboardInputViewController.h"

@implementation CustomTextField

- (UIView *)inputView {
	CustomKeyboardInputViewController *vc = [[CustomKeyboardInputViewController alloc] initWithNibName:@"CustomKeyboardInputView" bundle:nil];

	return vc.view;
}

- (void)dealloc {
    [super dealloc];
}

@end

カスタムキーボード呼び出し元になるxibの設定

カスタムキーボード表示対象のテキストフィールド(上で作成したCustomTextField)をビューに配置する。

カスタムキーボード自体のxib

実行結果

ビュー上のテキストフィールドを選択すると、カスタムキーボードが表示される。

キーボード選択値をテキストフィールドに設定

キーボードでのボタン選択で、テキストフィールドに値をセットするためには、カスタムキーボードのビューコントローラでボタンの処理を実装する。例えばこのようになる(テキストフィールドのプロパティをキーボードのビューコントローラ側に持たせるのはあまり良いやり方ではない気がするが、とりあえずそこは無視)。

まず、CustomKeyboardInputViewController.h で、対象テキストフィールドとボタンの処理を宣言。

#import 

@interface CustomKeyboardInputViewController : UIViewController {
	UITextField *tf;
}

@property (nonatomic, retain) UITextField *tf;

-(IBAction) btPressed:(id) sender;

@end

CustomKeyboardInputViewController.m で、ボタンの文字列をテキストフィールドにセットする。

#import "CustomKeyboardInputViewController.h"
#import "CustomKeyboardTestViewController.h"

@implementation CustomKeyboardInputViewController

@synthesize tf;

-(IBAction) btPressed:(id)sender {
	// キーボード上のボタン選択値をテキストフィールドにセット
	UIButton *bt = (UIButton *) sender;
	[self.tf setText:bt.titleLabel.text];
	
	// キーボードを隠す
	[self.tf resignFirstResponder];
}

@end

カスタムテキストフィールドのメソッドを少し変えておく。

#import "CustomTextField.h"
#import "CustomKeyboardInputViewController.h"

@implementation CustomTextField

- (UIView *)inputView {
	CustomKeyboardInputViewController *vc = [[CustomKeyboardInputViewController alloc] initWithNibName:@"CustomKeyboardInputView" bundle:nil];
	
	vc.tf = self; // これを追加
	
	return vc.view;
}

- (void)dealloc {
    [super dealloc];
}

@end

キーボードのxibを編集して、各ボタンからの処理を呼出すようにする。

7月
6

iOS4以降でのビュー切り替えとアニメーション

Author msota    Category 逆引き備忘録     Tags

ビューを切り替える場合(に限らないが)のアニメーション記述方法がiOS4から変更になった。ネットで探してみても、iOS4以降の記述方法があまり見つからなかったのでメモしておく。

結果的にはかなりシンプルになっている。
長いので改行しているが、ビューの切り替えも含めて、1文で終わってしまう。

ちなみに以下のoldVC、newVCは、変更前後のビューに対するビューコントローラ。

iOS4以降の場合

	[UIView transitionFromView: oldVC.view
		toView: newVC.view
		duration:0.5 
		options:UIViewAnimationOptionTransitionCurlDown
			completion:^(BOOL finished){
				/* do something on animation completion */
	} ];

(参考)iOS3.xまでの場合

	// アニメーション
	[UIView beginAnimations:@"flipping view" context:nil];
	[UIView setAnimationDuration:1];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
	[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown 
							   forView:self.view cache:YES];

	// Change View
	[oldVC.view removeFromSuperview];
	[self.view addSubview:newVC.view];
	
	[UIView commitAnimations];
7月
4

SQLite+FMDBで日付型を扱う場合の注意点

Author msota    Category 逆引き備忘録     Tags

忘れないように整理しておく。

SQLiteとFMDBで日付型を扱う際の前提

まず、整理の前提となる事実。

  • SQLiteでは日付型そのものの型はないので、日付を格納する列はtextやrealで代替定義している
  • FMDBは日付型を扱うためのメソッドを提供しているが、列定義がrealであることを想定している
  • FMDBは、real値を日付型として返すために NSDate クラスの dateWithTimeIntervalSince1970 を利用している
  • FMDBは、real値を日付型としてSQLiteに登録するために NSDate クラスの timeIntervalSince1970 を利用している
  • 日付情報はUNIX時間(1970年1月1日を起源とした差分値)で管理している。NSDateクラスには、その前提で倍精度数値データを扱うためのメソッドがある(dateWithTimeIntervalSince1970 / timeIntervalSince1970)

対応方針

上記の前提を踏まえると、SQLite, FMDBの組合せでアプリケーションを組む場合は、以下のような方針にすれば良さそうだ。

  • SQLiteのテーブル定義時は、日付を扱う列はreal型で定義する
  • FMDBで日付型データを参照する場合は dateForColumn / dateForColumnIndex を使う(NSData型の値が戻される)
  • FMDBで日付情報を登録/更新する場合は、NSDate型にしておけば、あとはFMDBが勝手にやってくれる

実際にはNSDateFormatterで書式を整えたりする必要があるが、FMDBやSQLiteとは直接関係ないのでとりあえず考えないでおく。

問題点

テストデータを事前に手操作なり何なりでDBに登録しておきたい場合、timeIntervalSince1970 なり何なりで変換したreal値を登録しなければならない。ごく普通に「2011/06/20」のような値を登録できない。