2010/03/25

LeopardにRailsの環境を作る

railsの環境設定 備忘録
MacOSX(10.5) LeopardでRailsの環境を整える。
Leopardには、最初からRailsが入っていますが、アップデートしないと不具合がでることが多い。
HFRailのscaffoldでつまずいたのもここ。
scaffold を実行して、
wrong constant name Name:stringController
とかが出たらアップデートすること。作ったプロジェクトもいったん破棄する。

以下を順に実行。
$ sudo gem update --system
$ sudo gem install rails
$ sudo gem update rake
$ sudo gem update sqlite3-ruby

2010/03/07

Dropboxを使って、複数のPCでのGoogle App Engineのアプリ開発の同期を取る

Google App Engineの開発ディレクトリをDropbox上に置くことで複数のPCで開発が行えるようになる。

例えばSomeAppというアプリを開発しているとして、

user/Dropbox/SomeApp

というようにDropbox上に開発ディレクトリを作ってここで開発を行う。
Dropboxの上にあるので編集後に勝手に同期される。

ただしこのディレクトリを直接App Engine Lancherで指定してもダメで、ここから別のローカルディレクトリにリンクを張って、そこをApp Engine Lancherに指定させる。

以下のディレクトリにリンクをはってApp Engine Lancherに指定させるとちゃんと起動する。
user/develop/gae/SomeApp

$cd develop/gae/
$ln -s ~/Dropbox/SomeApp SomeApp

2010/02/01

iPhoneSDK 実行時に急に落ちる症状

アプリがいきなり落ちるパターンのバグは、メモリリーク系。retainカウントの間違いや、releaseの重複があやしい

2010/01/14

iPhone : CoreDataレシピ カスタムのプロトコルを作成する。

レシピのAddをpresentModalで行うときに、カスタムのプロトコルを作成して呼び出し元をそれに準拠させておく。

呼出し元クラス(カスタムのプロトコルに準拠)
やること:
1.プロトコルの設定
2.プロトコルメソッドの実装

呼出しクラス(カスタムのプロトコルを定義)
やること:
1.プロトコルの宣言
2.delegateの宣言
3.プロトコルメソッドの宣言



カスタムのプロトコルの使い方
呼出しクラス

やること:
1.プロトコルの宣言
2.delegateの宣言
3.プロトコルメソッドの宣言

//プロトコルの宣言
@protocol RecipeAddDelegate;
@class Recipe;

@interface RecipeAddViewController : UIViewController  {
    @private
        Recipe *recipe;
        UITextField *nameTextField;
//delegateを宣言
        id  delegate;
}

@property(nonatomic, retain) Recipe *recipe;
@property(nonatomic, retain) IBOutlet UITextField *nameTextField;
@property(nonatomic, assign) id  delegate;

- (void)save;
- (void)cancel;

@end


//プロトコルのメソッドを定義
@protocol RecipeAddDelegate 
// recipe == nil on cancel
- (void)recipeAddViewController:(RecipeAddViewController *)recipeAddViewController didAddRecipe:(Recipe *)recipe;

@end


実装部は長いのでいるとこだけ。
プロトコルメソッドを呼び出すだけ、実装はしなくてよい。実装はプロトコルに準拠した呼出しもとクラスで行う。
これでプロトコルを経由して呼出し元のメソッドを呼び出す。

- (void)save {
    
    recipe.name = nameTextField.text;

 NSError *error = nil;
 if (![recipe.managedObjectContext save:&error]) {
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  abort();
 }  
    //プロトコルを経由してメソッドを呼び出す。メソッドの実装は呼出し元で
 [self.delegate recipeAddViewController:self didAddRecipe:recipe];
}





呼出し元

やること:
1.プロトコルの設定
2.プロトコルメソッドの実装

インターフェース
#import "RecipeAddViewController.h"

@class Recipe;
@class RecipeTableViewCell;

@interface RecipeListTableViewController : UITableViewController  {
    @private
        NSFetchedResultsController *fetchedResultsController;
        NSManagedObjectContext *managedObjectContext;
}

@property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;

- (void)showRecipe:(Recipe *)recipe animated:(BOOL)animated;
- (void)configureCell:(RecipeTableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath;

@end

実装部
プロトコルのメソッドを実装する。

#pragma mark -
#pragma mark Recipe support

- (void)add:(id)sender {
//ここは呼出しメソッド。ここから呼出しクラスを起動してdelegateする。
    RecipeAddViewController *addController = [[RecipeAddViewController alloc] initWithNibName:@"RecipeAddView" bundle:nil];
    addController.delegate = self;
 
 Recipe *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
 addController.recipe = newRecipe;

    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addController];
    [self presentModalViewController:navigationController animated:YES];
    
    [navigationController release];
    [addController release];
}

//プロトコル実装部 dismissModalViewControllerでモーダルを除去する。
- (void)recipeAddViewController:(RecipeAddViewController *)recipeAddViewController didAddRecipe:(Recipe *)recipe {
    if (recipe) {        
        // Show the recipe in a new view controller
        [self showRecipe:recipe animated:NO];
    }
    
    // Dismiss the modal add recipe view controller
    [self dismissModalViewControllerAnimated:YES];
}


- (void)showRecipe:(Recipe *)recipe animated:(BOOL)animated {
    // Create a detail view controller, set the recipe, then push it.
    RecipeDetailViewController *detailViewController = [[RecipeDetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
    detailViewController.recipe = recipe;
    
    [self.navigationController pushViewController:detailViewController animated:animated];
    [detailViewController release];
}

iPhone : 編集可能なテーブルの作成

CoreData Resipeサンプルより。
iPhone : CoreData レシピサンプルを探る

編集可能なテーブルを作るには、
編集可能なテーブルビューセルを作成して使用する。
実装はほとんどなくて、Interface Bulderメインで作成する。セルの操作のためのIBOutletプロパティを設定するだけ。

IB側はこんな感じ



labelとtextfieldになるセルの部分だけを作成する。

手順
1:クラスの作成


新規ファイル>NSObject>種類はUITableViewCellのサブクラス
ViewControllerクラスで作っちゃだめです。
2:xibの作成


新規ファイル>View XIB

3:xibを編集
デフォルトのViewを削除しTableViewCellに変更。

TableViewCellのクラスをEditingTableViewクラスに変更
TableViewCellを配置して、labelとtextFieldを追加する。


TableViewCellのアウトレットにlabelとtextFieldを接続。


File's OwnerのNew Referencing OutletにtextFieldのdelegateを接続する。

後はテーブルビューコントローラーを作って、File's Ownerのクラスに設定する。
さらにFile's Owner経由でテーブルコントローラーのプロパティにEditingTableViewCellを接続する。
テーブルビューコントローラークラス内にXIBを直接読み込んで使用する。
バンドルからXIBを読み込んで、EditiongTableViewCellクラスのViewへ接続する。

編集可能セルとテーブルビューは1セットということになる。複数箇所で使う場合は複数セット用意することになりそう。


EditingTableViewCellクラス
EditingTableViewCellクラスの中身はこんだけ
//インターフェース部
@interface EditingTableViewCell : UITableViewCell {
 UILabel *label;
 UITextField *textField;
}

@property (nonatomic, retain) IBOutlet UILabel *label;
@property (nonatomic, retain) IBOutlet UITextField *textField;

@end

//実装部
#import "EditingTableViewCell.h"

@implementation EditingTableViewCell

@synthesize label, textField;

- (void)dealloc {
 [label release];
 [textField release];
 [super dealloc];
}

@end

これを使いたいテーブルビューコントローラーのtableView:cellForRowAtIndexPathメソッドで設定してあげればよい。

Table View Controllerクラス
//インターフェース側
#import 

@class EditingTableViewCell;

@interface AnkiEditTableViewController : UITableViewController {
 @private
  //なぜプライベートで宣言するのか?
  EditingTableViewCell *editingTableViewCell;
}
@property (nonatomic, assign) IBOutlet EditingTableViewCell *editingTableViewCell;

@end

//実装部
//全体は省略して必要なところだけ
//エディットに入れたいので、セレクトさせないようにする。
- (void)viewDidLoad {
    [super viewDidLoad];
 self.tableView.allowsSelection = NO;
 self.tableView.allowsSelectionDuringEditing = NO;
}

// セルに設定する
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 static NSString *cellIdentifire = @"EDITOR_TABLEVIEWCELL";
 EditingTableViewCell *cell = (EditingTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifire];
  if (cell == nil) {
   //バンドルからXIBの読み込み
   [[NSBundle mainBundle] loadNibNamed:@"EditingTableViewCell" owner:self options:nil];
   //IB上で接続されている。
   cell = editingTableViewCell;
   self.editingTableViewCell = nil;
  }
 
    return cell;
}

EditingTableViewCellはIBOutletとインターフェースを毎回変更すれば、ほとんどそのままで使い回せる。
単純に編集可能なテーブルを生成するだけなら、毎回変更しなくてもこのままでもいい。ビューコントローラークラスの指定を変更するだけでよい。
これくらい公式で用意しておいてくれると助かるのに。

iPhone : CoreData レシピサンプルを探る


iPhone Dev Center CoreRecipes Sample


以外といろいろな物に使えそうなサンプル。
テーブルレイアウトとCoreDataの基本やTipsがいっぱい詰まっている印象です。
CoreData周りの曖昧に理解していた部分をすっきりさせるのに最適です。

・NSManagedObjectの取り扱い方
NSManagedObjectクラスのサブクラスのResipeクラスを作って使う。

・テーブルのセルの拡張方法
TableViewCellをカスタムで拡張する。

・編集可能なテーブルを作る
編集するセル用にEditingTableViewCellクラスを作って使う。

2010/01/05

編集時のアクセサリ設定。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    
 static NSString *SetCellIdentifier = @"SetCellIdentifier";
 
 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SetCellIdentifier];
 
 if (cell  == nil) {
  cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:SetCellIdentifier];
//ここでアクセサリと編集時のアクセサリを設定する。
  cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton;
  cell.editingAccessoryType = UITableViewCellAccessoryDisclosureIndicator;
 }
 
 cell.textLabel.text =[[setListArray objectAtIndex:indexPath.row] valueForKey: @"set_title"];
 return cell;
}