Hatena::Groupiphone-dev

noborunrunのiPhoneアプリ開発

公開中アプリ mStacks FilmTrackr PicTrackr
|

2010-12-13

MacMiniでgitサーバを構築する

03:15

subversionから移行したい、githubも良いけどプライベートなソース管理は自分でしたい。など考えている方も多いと思い、あえて今、MacMiniMacOSXgitのリモートサーバの構築方法をまとめておきたいと思います。

※最近ではgitosisなど便利なツールもありますが、ここでは「あえて」MacOSXのみでのサーバ構築の手法を説明します。

1.準備

Gitインストールする。

MacPortsでいれても、GoogleCodeにアップされているMacOSX用のインストーラを入れても大丈夫です。。

サーバOSX、ローカルどちらにもインストールをしてください。

ちなみにGoogleCodeのアドレスはこちらです。

http://code.google.com/p/git-osx-installer/

2.サーバでの作業

基本的にはMacOSXの管理機能で完結します。

MacOSXGUI最高!

では手順を見て行きます。

2-1グループ登録

Gitのグループをシステム環境設定のアカウントで登録します。

左下の「+」ボタンをクリックし、アカウントを追加する要領で名前などをいれます。

選択ボックスから種類をグループに変更します。

2-2ユーザー登録

 Gitを使うユーザーをシステム環境設定のアカウントから登録します。

ユーザーを登録したら、先ほど作ったグループにユーザーをいれてあげましょう。

これもグループを選んで右側のユーザーのチェックボックスにチェックを入れるだけです。

必要に応じて(うちの環境ではこの問題が起こりました)ログインシェルのrcファイルにgitのパスを設定してください。rc以外に書いてもエラーが出ます。必ずrcファイルへの記載をしてください。

一つ作れば今後ユーザーの追加をした時もコピペで構いません。

2-3SSH設定

SSHを設定してgitのユーザーをsshの管理下に置きましょう。

システム環境設定を開いて、共有を選択します。その中の項目であるリモートログインを選択して、ログインを許可するユーザーを追加します。

ルータ設定(ポートフォワーディング)やファイヤーウォールの設定なども必要でしたら行ってください。

2-4リポジトリを作る

ターミナルを開き、リポジトリを作成するディレクトリ

git init --bare --shared

コマンドを入力します。

すると、そのディレクトリGitレポジトリができます。

このリポジトリを共有して使い続けることとなります。

(--sharedを付けた場合、このコマンドを実行したユーザーのグループでの書き込みが可能となります。2-1で作成したグループに入っているユーザーで実行をしましょう。)

3.ローカルでの準備

Gitで管理したいフォルダにTerminalで移動して下記のコマンドを打ってください。

git init

git remote add origin <サーバGitリポジトリのアドレス>

これで設定終了です。

4.運用

外部からインターネットで接続して使用したい場合はグローバルIPを用意するか、ダイナミックDNSをの設定をして、IP変更スクリプトを定期的に実行するなどの手段で常にサーバを参照できる様にしてください。

うちではダイナミックDNSを用意して、Macのcronでスクリプトを実行しています。

ローカルでコミットをある程度ためたり、ソース管理をしておき、あるタイミングでサーバにコミットするという使い方ができます。

また、複数人で開発をする場合などもサーバとして使用しているMacOSXのユーザーを追加してSSHの接続許可をするだけで、すぐに環境を作ることができます。

SSH接続許可を行うので、ターミナルからもログインできてしまいますので、権限には注意が必要です。

サーバにコミットするには

git push origin master

サーバから最新のソースを取得するなら

git pull origin master

をすればOKです。

2010-08-24

celebrity flash リリース

14:58

iPhone4でカメラにフラッシュがついたのでストロボを焚くだけのアプリをリリースしました。

flash512

内容はカメラを撮るとかではなく、ストロボを焚くだけのアプリになります。

2010-08-12

OS3とOS4でのCoreDataとTableViewの挙動の違い

03:39

ちょっとはまったのでメモ

CoreData使ってUITableViewのデータを表示していて、一括削除をしようとしたときに、

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

で落ちてしまっていたのでいろいろ調べて見たところ、

OS3の場合は

2010-08-13 03:08:44.863 CompatibilityTests[34809:207] OK

2010-08-13 03:08:44.874 CompatibilityTests[34809:207] 0

2010-08-13 03:08:44.882 CompatibilityTests[34809:207] 1

2010-08-13 03:08:44.913 CompatibilityTests[34809:207] CoreData: sql: BEGIN EXCLUSIVE

2010-08-13 03:08:44.932 CompatibilityTests[34809:207] CoreData: sql: DELETE FROM ZPARTNER WHERE Z_PK = ? AND Z_OPT = ?

2010-08-13 03:08:44.944 CompatibilityTests[34809:207] CoreData: sql: DELETE FROM ZPARTNER WHERE Z_PK = ? AND Z_OPT = ?

2010-08-13 03:08:44.956 CompatibilityTests[34809:207] CoreData: sql: COMMIT

2010-08-13 03:08:44.984 CompatibilityTests[34809:207] CoreData: sql: pragma page_count     <−ここ

2010-08-13 03:08:44.993 CompatibilityTests[34809:207] CoreData: annotation: sql execution time: 0.0095s

2010-08-13 03:08:45.004 CompatibilityTests[34809:207] CoreData: sql: pragma freelist_count

2010-08-13 03:08:45.019 CompatibilityTests[34809:207] CoreData: annotation: sql execution time: 0.0145s

OS4だと

2010-08-13 03:09:36.351 CompatibilityTests[378:307] OK

2010-08-13 03:09:36.356 CompatibilityTests[378:307] 0

2010-08-13 03:09:36.359 CompatibilityTests[378:307] 1

2010-08-13 03:09:36.363 CompatibilityTests[378:307] CoreData: sql: BEGIN EXCLUSIVE

2010-08-13 03:09:36.372 CompatibilityTests[378:307] CoreData: sql: DELETE FROM ZPARTNER WHERE Z_PK = ? AND Z_OPT = ?

2010-08-13 03:09:36.376 CompatibilityTests[378:307] CoreData: sql: DELETE FROM ZPARTNER WHERE Z_PK = ? AND Z_OPT = ?

2010-08-13 03:09:36.380 CompatibilityTests[378:307] CoreData: sql: COMMIT

2010-08-13 03:09:36.432 CompatibilityTests[378:307] TableView:MakeCell <−ここ

2010-08-13 03:09:36.441 CompatibilityTests[378:307] CoreData: sql: SELECT 0, t0.Z_PK FROM ZPARTNER t0 ORDER BY t0.ZSEND_DATE DESC

2010-08-13 03:09:36.447 CompatibilityTests[378:307] CoreData: annotation: sql connection fetch time: 0.0064s

2010-08-13 03:09:36.451 CompatibilityTests[378:307] CoreData: annotation: total fetch execution time: 0.0108s for 0 rows.

2010-08-13 03:09:36.460 CompatibilityTests[378:307] 0

となって、COMMIT後の挙動が違っていた。


落ちてた理由はOS3で動作してたので、これでいいと思ってやってたのだけど、

まず、FetchedResultControllerをinitでロードして、それを

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

return fetchedResultsController fetchedObjects] count];

してたんだけど、

OS4の場合、Cellを作る前にTableViewはnumberOfRowInSection:で行数をとっている。

このときに古いままメモリ上にロードされてた(initでロード)数を返してしまっていたので

整合性がとれず落ちていた。

解決策はDelete時のsave:の後に再度fetchedResultControllerを新しいのに変えてあげればOK。

つまり、initでやってたロードをもう一回やってあげれば良かった。

それにしても、コンソールログをよく見ると、CoreDataのSELECTよりも早くTableViewのCell作りに行く方が早いってどういうことだろう。

と思った。

2010-01-08

CoreDataの使い方

15:56

#2010/09/21追記訂正

 NSFetchedResultControllerはUITableViewに特化したクラスでした。

 そして、普段はNSFetchRequestでNSManagedObjectContextを参照して、そのresultを参照すると、Dataはとれます。

 後ほど、改めてCoreDataについて記したいと思います。

      • 本文---

そろそろ本腰入れて某Meets.app手をつけたいなと思っていて、そこで使用予定のCoreDataについていろいろ調べていたら

何となくわかった気がしたので、書いてみる。

基本的にはCoreDataのリファレンスとサンプルコードを見ながらなんだこれは。といった感じで調べてみた。

調べていて思ったのは、したの2点。

・どこからどこまでやってくれて、どこからどこまで自分でやるのかがわからない。(どの時点で更新されたデータが保存されるのかとか)

・fechedResultsControllerとmanagedObjectのつながり。

CoreDataBooksでは、インサートとデリートしかやってなくて、どこで更新とかしてるんだろと思ったり、

CoreRecipesでは、どこでアップデートかけてるんだろ。とおもったり。

動きがわからないため、何度かTwitterでつぶやいたところ、下記の方々に助けてもらったので、感謝の意を込めて、IDを記しておく。

Thanks to

@hitoriblog,@basuke

では、本題。

・AppDelegateでManageObjectContextを定義して、インスタンス化。

 これをCoreDataを使うクラスでも共有する。

 

 ManagedObjectContextの中でcoordinatorに入れるpersistentStoreCoordinatorメソッドでdatamodelファイル(*.xcdatamodel)を指定する。

 

NSManageObjectContextが同じならそれを使って更新・参照・削除・挿入ができる。

その後、NSManageObjectContextのsaveメソッドを使うと、データがDBに保存される。

・データ参照

 CoreData使用クラス内で

  fetchedResultsControllerを定義してインスタンス化。

  entityにentity名

  sortするならsotrDiscriptorにキー名を指定する。

 このfetchedResultsControllerのRowをobjectAtIndexPathで指定してNSManageObjectをインスタンス化して代入後、

 そのNSManageObjectのValueForKeyでキーを指定すると値参照できる

  

・データ追加

 CoreData使用クラス内で

  NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];

NSEntityDescription *entity = fetchedResultsController fetchRequest] entity];

NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];

[newManagedObject setValue:[NSDate date] forKey:@"(キー)"];

 この状態で

[context save:&error]

すると新しいデータが保存される。

・データ削除

 追加とほぼ同じ。

  NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];

[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath;

 この状態で

[context save:&error]

すると選択したデータが削除される。

・データ更新

NSManagedObjectクラスを継承したentityのプロパティと同じ内容の@propertyがあるクラスを作成する。

更新したいRowのデータをこのクラスにキャストしてインスタンス化する。

(NSManagedObject継承クラス) *impMO = (NSManagedObject継承クラス *)[fetchedResultsController objectAtIndexPath:indexPath];

こんな感じ。

でこのクラスの内容を変更した後、継承したクラスが保持しているmanagedObjectContextでNSManagedContextをインスタンス化する。

それをsaveすれば完了する。

NSManagedObjectContext *context = impMO.managedObjectContext;

[context save:&error]

更新されたかどうかは、NSManagedObjectContextのhasChangesメソッドで確認できる。

されたかどうかにかかわらず更新してしまいたいならそのままsaveメソッドを使う。

DB更新時デリゲート呼び出し

 データが変更されるとcontrollerDidChangeContentメソッドが呼ばれる。

 この中でテーブルビューの更新とかすればいい。

 managedObjectContextが永続化されている間は挿入・更新・削除情報はすべてメモリ上に保存され、

 saveメソッドを使った時点でそれらの内容がDBへ保存される。

・まとめ 

 SQLで言うところのTransaction管理とすべてのデータのSELECTをNSFetchedResultsControllerが行ってくれていて、更新・削除・挿入をしたときには

 保持しているTransactionデータを変更しているだけ。で、要所要所でsaveメソッド使うことでcommitしましょう。と。

 戻したければroolbackメソッドもあるので、直前のsaveまで戻してもらえるんだろうと。

 ちなみにresetなんてメソッドもあります。All the receiver's managed objects are “forgotten.”ですって。

2009-11-02

Objective-Cで四捨五入

00:15

ただのCという噂も。

  • (float)roundWithValue:(float)value Precision:(int)precision {

float roundedValue;

int i = 0;

int calcDigit = 1;

float plus = 1.00;

while (i <= precision) {

plus = plus / 10.00f;

if (i == precision) { //最後だったら

plus = plus * 5.00f;

}else if (i < precision) {

calcDigit = calcDigit * 10;

}

i += 1;

NSLog(@"NDCalcRound:Plus:%f",plus);

NSLog(@"NDCalcRound:calcDigit:%d",calcDigit);

}

roundedValue = (float)floor((value + plus) * calcDigit) / (float)calcDigit;

//NSLog(@"NDCalcRound:roundedValue:%f",roundedValue);

return roundedValue;

}

Objective-Cでtsvファイルの処理

00:12

tsvファイルを二次元配列にする。

用はテキストファイルをもらって配列にして返すだけ。

  • (NSArray *)parseToArrayFromTSV:(NSString *)tsv {

int i = 0;

long from = 0;

long to = 0;

NSMutableArray *rowArray = NSMutableArray alloc] init];

NSMutableArray *columnArray = NSMutableArray alloc] init];

long rowCount = 0;

long columnCount = 0;

NSRange stringRange;

for (i = 0;i < [tsv length];i++) {

NSRange range = NSMakeRange(i,1);

if (tsv substringWithRange:range] isEqualToString:@"\t"] == YES) {

stringRange = NSMakeRange(from, to - 1);

//columnArrayのcolumnCount番に項目を入れる

[columnArray insertObject:[tsv substringWithRange:stringRange] atIndex:columnCount];

//columnCountをカウントアップ

columnCount += 1;

from = i + 1;

to = 0;

}else if (tsv substringWithRange:range] isEqualToString:@"\n"] == YES) {

stringRange = NSMakeRange(from, to - 2 );

//columnArrayのcolumnCount番に項目を入れる

[columnArray insertObject:[tsv substringWithRange:stringRange] atIndex:columnCount];

NSArray *array = NSArray alloc] initWithArray:columnArray];

[rowArray insertObject:array atIndex:rowCount];

//[array release];

//rowCountをカウントアップ

rowCount += 1;

//columnCountを初期化

columnCount = 0;

[columnArray removeAllObjects];

from = i + 1;

to = 0;

}

to += 1;

}

NSLog(@"NDTsvParser:rowArray:count:%d",[rowArray count]);

return rowArray;

}

Objective-Cで二次元配列を使ったコムソート

00:05

ソートする必要があったので、かいてみた。

コムソートの速度は 平均計算時間:O(n log n) 最悪計算時間:O(n log n) メモリ使用量:O(1)

利点はコードサイズが小さくて済む。

Wikipediaにかいてあった。

安定ソートではないので、Rowの番号をちゃんと保持しとかないと後々大変。

ちなみに僕はtsvからとった二次元配列ソートして、近似値Top10をとりたかった。

//ソート準備

NSMutableArray *sortArray = NSMutableArray alloc] init];

NSMutableArray *inArray = NSMutableArray alloc] init];

for (i=0; i<[bmiArray count]; i++) {

//値

[inArray insertObject:(値(例ではfloatを詰め込んでる))] atIndex:0];

//行番号

[inArray insertObject:[NSNumber numberWithInt:i] atIndex:1];

NSArray *concArray = NSArray alloc] initWithArray:inArray];

[sortArray insertObject:concArray atIndex:i];

[inArray removeAllObjects];

}

  //ソートスタート

NSInteger h = [sortArray count] / 1.3;

BOOL flg = YES;

while (flg == YES) {

int swaps = 0;

for (int i=0; i+h < [sortArray count]; i++) {

if ([sortArray objectAtIndex:i+h] objectAtIndex:0] floatValue] < [sortArray objectAtIndex:i] objectAtIndex:0] floatValue]) {

NSArray *iArray = [NSArray alloc] initWithArray:[sortArray objectAtIndex:i? autorelease];

NSArray *ihArray = [NSArray alloc] initWithArray:[sortArray objectAtIndex:i+h? autorelease];

[sortArray insertObject:iArray atIndex:i+h];

[sortArray insertObject:ihArray atIndex:i];

         //NSArrayのinsertObjectは代入ではなく追加なので、挿入した後は挿入前の配列要素は削除しとく。

[sortArray removeObjectAtIndex:i+1];

[sortArray removeObjectAtIndex:i+h+1];

swaps ++;

}

}

if (h == 1) {

if (swaps == 0) {

flg = NO;

break;

}

}else {

h /= 1.3;

}

}

  //後はソートした順に使う。

for (i=0;i<[sortArray count];i++) {

   ...

}

|