2010年11月24日

SubVersionでブランチを作成して作業コピーを切り替える

ブランチの作成は基本的にリポジトリ内でコピーするだけです。


$ svn copy file:///Users/ishi-ken/Documents/svn/SubVersionSample/trunk file:///Users/ishi-ken/Documents/svn/SubVersionSample/branches/new-branch -m "Branching"
$ cd ~/Documents/SubVersionSample/
$ svn switch file:///Users/ishi-ken/Documents/svn/SubVersionSample/branches/new-branch
At revision 17.
$ svn info


最後の svn info でどのリポジトリがチェックアウトされている状態なのかを確認できます。
posted by iphone-dev at 22:20| 日記

2010年11月22日

iPhone開発でSubVersionを使ってバージョン管理をする

やはり開発にはバージョン管理(ソースコード管理)は必須です。小規模で開発していると必要ないと思ってしまいがちですが、次期バージョンを開発中にリリース済みのバージョンにバグが見つかった場合などはどうでしょうか。バージョン管理をしていないと、修正だけ行なおうにも、すでにいろいろな新機能の実装が進んでいて、バグ修正版を出すことが難しくなります。

能書きはこのあたりにしておいて、バージョン管理ソフトはいろいろありますが、Mac環境には最初から含まれているSubVersionを使うのが面倒が少なくていいと思います。

この記事では、すでに開発中のXCodeプロジェクトをSubVersionでローカル管理する方法を取り上げます。自分への備忘録的に書いていますので、間違っていたら指摘してください。

リポジトリのパスを環境変数に登録しておくと便利みたいですが、ここではしていません。

1. SubVersionのリポジトリを作成する



個人的にはプロジェクトごとのリポジトリを作成した方がいいような気がするので、そうします。今回は "SubVersionExample" というプロジェクトをバージョン管理することにします。



$ cd ~/Documents/
$ mkdir svn
$ cd svn/
$ mkdir SubVersionExample
$ svnadmin create SubVersionExample/


2. trunk, tags, branchesを作る



SubVersionはtrunk, tags, branchesで管理するように推奨されています。


  • trunk: メインの開発ソース

  • tags: スナップショットを保存

  • branches: メインの開発とは別の更新をするために使用



イメージとしては、リリースを行なった時点で tags にディレクトリを作成して("ver1.0" など)、リリースバージョンのスナップショットを取っておきます。リリースバージョンにバグが見つかった場合などに、スナップショットを元に branches の中にブランチを作成して、バグ修正ブランチを作成する、という感じです。

ここでは、この構成を持ったディレクトリをコミットします。



$ mkdir tmp
$ cd tmp/
$ mkdir trunk tags branches
$ svn import ./ file:///Users/ishi-ken/Documents/svn/SubVersionExample/ -m "Initial import."
Adding trunk
Adding branches
Adding tags

Committed revision 1.
$ cd ..
$ rm -rf tmp


ここらへんがちょっと分かりにくいのですが,リポジトリの内部は特段何かの決まりとか分類とかがあるわけではなくて、自分で勝手に決めていいわけです。それでリポジトリ内部にその三つのディレクトリを作成し、trunk内をメイン開発ディレクトリとして定めます。

3. 既存のプロジェクトをリポジトリに登録する



まず、リポジトリのtrunkを既存のプロジェクトディレクトリにチェックアウトします。上書きされることはありませんが、心配なら別のところにコピーして取っておくこともできます。



$ cd ~/Documents/SubVersionExample/
$ svn checkout file:///Users/ishi-ken/Documents/svn/SubVersionExample/trunk .
Checked out revision 1.


次に、プロジェクトファイルをリポジトリに追加します。



$ svn add --force .
A build

A Classes
A Classes/SubVersionExampleAppDelegate.h
A Classes/SubVersionExampleAppDelegate.m
A Classes/SubVersionExampleViewController.h
A Classes/SubVersionExampleViewController.m
A main.m
A MainWindow.xib
A SubVersionExample-Info.plist
A SubVersionExample.xcodeproj
A SubVersionExample.xcodeproj/ishi-ken.mode1v3
A SubVersionExample.xcodeproj/ishi-ken.pbxuser
A SubVersionExample.xcodeproj/project.pbxproj
A SubVersionExample_Prefix.pch
A SubVersionExampleViewController.xib


いろいろなファイルが登録されます。しかし、build以下はバージョン管理をしなくてもよいファイルです。なので、buildの登録を解除し、build以下を無視する設定にします。



$ svn revert build --recursive
Reverted 'build'
$ svn propset svn:ignore "build" .
property 'svn:ignore' set on '.'


.xcodeproj以下にはユーザー独自のファイルがあるので、それもはずしてもいいかもしれません。



$ svn revert SubVersionExample.xcodeproj/ishi-ken.*
Reverted 'SubVersionExample.xcodeproj/ishi-ken.mode1v3'
Reverted 'SubVersionExample.xcodeproj/ishi-ken.pbxuser'


最後にコミットしてプロジェクトファイルの登録が終了です。



$ svn commit -m "New XCode project."
Sending .
Adding Classes
Adding Classes/SubVersionExampleAppDelegate.h
Adding Classes/SubVersionExampleAppDelegate.m
Adding Classes/SubVersionExampleViewController.h
Adding Classes/SubVersionExampleViewController.m
Adding MainWindow.xib
Adding SubVersionExample-Info.plist
Adding SubVersionExample.xcodeproj
Adding SubVersionExample.xcodeproj/project.pbxproj
Adding SubVersionExampleViewController.xib
Adding SubVersionExample_Prefix.pch
Adding main.m
Transmitting file data ..........
Committed revision 2.


4. XcodeのSCMと連携させる



SubVersionExampleのリポジトリを消してしまったので、ToToDoのリポジトリになっていますが、手順は以下の通りです。




  1. SCMメニューから「SCMリポジトリを構成...」を選択スクリーンショット(2010-11-30-7.40.41).png

  2. 表示されるウィンドウの左下の「+」ボタンをクリックスクリーンショット(2010-11-30-7.44.52) (1).png

  3. リポジトリの名前を入力。SCMシステムは「Subversion」を選択して、OKをクリックスクリーンショット(2010-11-30-7.45.13).png

  4. リポジトリが追加されるので、URLにSubversionリポジトリのURLを入力。「認証されました」というのが下に出るのを確認したら、OKをクリックして閉じるスクリーンショット(2010-11-30-7.44.52).png

  5. Subversionリポジトリに対応するXcodeプロジェクトを開き(あらかじめ開いておいてもOK)、プロジェクトメニューの「プロジェクト設定を編集」を選択スクリーンショット(2010-11-30-7.45.44).png

  6. 「一般」タブに切り替えて、「ルートとSCMを構成...」ボタンをクリックスクリーンショット(2010-11-30-7.46.19).png

  7. プロジェクトルートとSCMを関連づけて、OKをクリックスクリーンショット(2010-11-30-7.46.34).png

  8. 以上で終了



5. スナップショットの作成



スナップショットやブランチの作成は、svn copyを使います。単純コピーですね。簡単です。



$ svn copy file:///Users/ishi-ken/Documents/svn/SubVersionExample/trunk file:///Users/ishi-ken/Documents/svn/SubVersionExample/tags/ver1.0

Committed revision 3.


SVN_EDITORが設定されていない、みたいなエラーメッセージが出る場合は、



$ export SVN_EDITOR="vi"


これを実行。
posted by iphone-dev at 19:14| 日記

UIActionSheetのボタンに長い文字列をtruncateしないで表示させる方法

UIActionSheetは便利ですが、長い文字列を表示させようとすると、truncateされてしまいます。日本語は母国語のせいか短めに表現できるのでいいのですが、フランス語とかになると結構長くなってしまって困ることがあります。

この問題を解決するには、ボタンの画像を用意して、UIButtonとしてUIActionSheetにaddSubViewするのが手っ取り早いです。

画像は以下のを使えます。Retina Display対応画像も用意してあります。
[gallery link="file" columns="4"]

コードは以下のような感じです。
ボタン一つにつき53.0fの高さが使われるようなので、必要に応じてoffset値などを変更してください。ボタンが複数あるときでも53.0f間隔で配置されるようにすれば良さそうです。

文字のサイズをループで取得しているのは、ボタンのtitleLabelのサイズを適当な値で設定して、adjustsFontSizeToFitWidth = YES;とすると、文字列が縦方向の真ん中にこないためです。

そして、ボタンのインデックスをtagに設定しておいて、それをイベントハンドラ内で読み取って、dismissWithClickedButtonIndex: でUIActionSheetの通常のdelegateで処理できるようにしています。



- (void)actionButtonDidTouchUpInside:(id)sender {

CGFloat offset = 0.0f;
NSInteger buttonIndex = 0;
NSString *longTitleString = NSLocalizedString(@"longTitle1", nil);

UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:NSLocalizedString(@"cancel", nil) destructiveButtonTitle:nil otherButtonTitles:longTitleString, nil] autorelease];

UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *image = [UIImage imageNamed:@"ActionSheetButton.png"];
[button setBackgroundImage:image forState:UIControlStateNormal];
[button setBackgroundImage:[UIImage imageNamed:@"ActionSheetButtonHighlighted.png"] forState:UIControlStateHighlighted];
[button setFrame:CGRectMake(21.0f, offset + 21.0f, image.size.width, image.size.height)];
[button setTitle:longTitleString forState:UIControlStateNormal];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];

for (CGFloat size = 20.0f; size >= 10.0f; size -= 1.0f) {
CGSize stringSize = [longTitleString sizeWithFont:[UIFont boldSystemFontOfSize:size]];
if (stringSize.width <= image.size.width - 10.0f) {
button.titleLabel.font = [UIFont boldSystemFontOfSize:size];
break;
}
}

button.tag = buttonIndex++;

[button addTarget:self action:@selector(customActionSheetButtonDidTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];
[actionSheet addSubview:button];

[actionSheet showInView:self.view];
}


- (void)customActionSheetButtonDidTouchUpInside:(id)sender {

if ([sender isKindOfClass:[UIButton class]]) {
UIButton *button = (UIButton *)sender;
if ([[button superview] isKindOfClass:[UIActionSheet class]]) {
UIActionSheet *actionSheet = (UIActionSheet *)[button superview];
[actionSheet dismissWithClickedButtonIndex:button.tag animated:YES];
}
}
}

posted by iphone-dev at 16:52| 日記