動的に作りだされるデータを保存する

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
TEAS TEA

動的に作りだされるデータを保存する

#1

投稿記事 by TEAS TEA » 10年前

iPhone objective-c

NSUserDefaultsの挙動を調べる為にテスト用アプリを開発しております。

動的に作りだされるデータを保存したいです。
現在のソースでは静的な情報を保存することが出来ますが2つ目以降の物を保存することが出来ません。
保存したいデータは各セルごとのItem.hで定義されているデータです。

又、ホームボタンをダブタッチクをしてアプリを強制的に落としてしまうと次回起動時に必ず落ちてしまいます。
データ等は保存されているのですが原因がお分かりになる方はいらっしゃりませんでしょうか?

http://www1.axfc.net/uploader/Sc/so/195804
pass:abc

画像

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#2

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:現在のソースでは静的な情報を保存することが出来ますが2つ目以降の物を保存することが出来ません。
 それぞれの銀行名項目を区別して保存していないからじゃないですか?
 今は毎回必ず @"BANK_NAME"の名前で保存していますが、銀行毎に別の名前(Key)で
保存すれば個別に保存できるはずです。
 あー、あと書き出したときはsynchronizeを忘れないようにして下さい。


 でもざっくりとソースを見た感じ EditMenuに入る度に読み出すのではなくコレクションを使って
起動時に全てのデータを読み取ったり、書き込みもアプリが終了するとき・バックグラウンドに
回ったときなどに限定して一括で行った方がよくないですか?

TEAS TEA さんが書きました:ホームボタンをダブタッチクをしてアプリを強制的に落としてしまうと次回起動時に必ず落ちてしまいます。
 プロジェクトのバックアップをとった上で、Admobを外して試してみてはどうでしょうか。
 後はログの確認とか。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#3

投稿記事 by TEAS TEA » 10年前

ご回答ありがとうございます。

>>今は毎回必ず @"BANK_NAME"の名前で保存していますが、銀行毎に別の名前(Key)で
>>保存すれば個別に保存できるはずです。

静的なものでしたら@"BANK_NAME_01"@"BANK_NAME_02"等と増やしていけばいいのですが
何個あるかもわからないので組み方にてこずっております。

>>落ちる時のログを見るのですが特にコードが発行されずに
シグナルを受信しました。killと書いてあるだけなんで原因がわからないんです。
Admobが原因の可能性がありそうなので帰り次第試してみます。

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#4

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:何個あるかもわからない
 何個あるのかの情報も入れておけばいいかと。

 設計を変えて良いのならこんな感じなんてのはどうでしょうか。
 NSUserDefaultsは NSMutableArrayや NSMutableDictionary のデータを扱うことができます。
http://iphone-dev.g.hatena.ne.jp/tokoro ... 1242789479

 そこで、NSMutableArrayに銀行を区別するID(番号や文字列)を配列で NSUserDefaultsにセットしておき、
その銀行毎に 1つの NSMutableDictionaryにデータを入れ、セットします。

 纏めるとこんな感じです。

[tabs][tabs: ]"banklist" : [NSMutableArray] "Bank001", "Bank002", "Bank004"
"Bank001" : [NSMutableDictionary]
"bankName" : "A銀行", "bankNumber" : "12345678", ...
"Bank002" : [NSMutableDictionary]
"bankName" : "B銀行", "bankNumber" : "31415926", ...
"Bank004" : [NSMutableDictionary]
"bankName" : "D銀行", "bankNumber" : "48151623", ...[/tabs]
※ "Bank003"は削除された状態だと思って下さい。

 この構造なら banklistの IDが被らないようにさえ注意すれば(どう被らないようにするかは考えてみて下さい)
数は banklistの配列を調べればすぐ判りますし、即各銀行のデータを取り出すことも容易ではないかと思います。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#5

投稿記事 by TEAS TEA » 10年前

ご回答ありがとう御座います。
いつも説明が丁寧なので今回も理解?できそうです。
いつもJyust様のお陰で出来ないことが少しだけ出来る様になり非常に感謝しております。
本当にありがとう御座います。

長々とすみません。
Item.hを削除し下記の様に変更してみたのですが問題点と分からないことが出て来てしまいました。

・保存が上手く行かない。
 要素が1個の時は上手く行く様なのですが他の時は全て空欄で保存されてしまっております。

・TopMenuでの読み込みがよくわからない。
 TopMenuでテーブルに銀行名を表示したいのですがどのように取得すれば良いのかが分からないです・・・。
 また現段階でTopMenuで削除を行ってしまうとデータの不整合?が起こってしまう様な気がします。

何度も質問すみません・・・。

コード:



//
//    TopMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "TopMenuController.h"
#import "EditMenuController.h"

@implementation TopMenuController

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

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStylePlain]) ) {
        self.title = @"口座情報";
		/*
        // 表示するデータを作成
		testData = [Item alloc];
		testData.bankName = @"三井住友銀行";
		testData.bankNumber = @"009";
		testData.branchName = @"○○支店";
		testData.branchNumber = @"001";
		testData.accountNumber = @"1234567890";
		testData.accountName = @"アプリ 太郎";
		testData.note = @"aaaa";
		*/
		/*
        Menu = [[NSMutableArray alloc] initWithObjects:
				testData.bankName,
				nil ];
		 */
    }
    return self;
}

- (void)viewDidLoad {
	// 編集ボタンの追加
	self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//	self.navigationController.navigationBarHidden = YES;
	Menu = [[NSMutableArray alloc] initWithObjects:
			nil ];
}

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	self.tableView.editing = NO;
}
// セルの追加/削除要求
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
	if ( UITableViewCellEditingStyleDelete == editingStyle ) {
		[Menu removeObjectAtIndex:indexPath.row];// データソースから実データを削除
		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];// テーブルからセルを削除
	}else if( UITableViewCellEditingStyleInsert == editingStyle ){
		// データの挿入
		[Menu insertObject:@"新規追加" atIndex:(Menu.count-1)];
		[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
	}
}

// 編集モードの最後の行のみ挿入モードにする
- (UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath{
	// 編集モードの場合の最後のRowだけ挿入モードにする
	if ( tableView.editing && Menu.count <= indexPath.row + 1 ) {
		return UITableViewCellEditingStyleInsert;
	} else {
		return UITableViewCellEditingStyleDelete;
	}
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
	if( editing ){
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count inSection:0];
		[Menu addObject:@"新規追加"];
		[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}else{
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count-1 inSection:0];
		[Menu removeLastObject];
		[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}
	[super setEditing:editing animated:YES];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {

    // 既にセルの型が登録済みかどうかをチェック
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"simple-cell"];
    if ( !cell ) {
        // セルの型が登録済みでないなら新しく登録する
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"simple-cell"] autorelease];
    } 
    // セルのラベルに表示するテキストを設定
    cell.textLabel.text = [Menu objectAtIndex:indexPath.row];
    return cell;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {

	EditMenuController* viewEdit;
	viewEdit = [[EditMenuController alloc] init];
	viewEdit.keyIndex = [[NSString alloc] initWithFormat:@"BANK_%03d",indexPath.row];
	[self.navigationController pushViewController:viewEdit animated:YES];
	[viewEdit release];
}

@end

//
//    EditMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "EditMenuController.h"
#import "MyTableViewCell.h"

@implementation EditMenuController
@synthesize keyIndex;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
	if( indexPath.row == 6 ) return 96;
	return 42;
}

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

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStyleGrouped]) ) {
        self.title = @"口座情報";
        // 表示するデータを作成
        Menu = [[NSMutableArray alloc] initWithObjects:
				@"銀行名",
				@"銀行番号",
				@"支店名",
				@"支店番号",
				@"口座番号",
				@"口座名義",
				@"メモ",
				nil ];
    }
    return self;
}

- (void)viewDidLoad {
//	self.navigationController.navigationBarHidden = YES;
	// 編集ボタンの追加
	//self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//keyIndex = [[NSString alloc] initWithString:@"BANK_001"];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
	
	static NSString *CellIdentifier = @"Cell";
	MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
	if (cell == nil) {
		cell = [[[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
	}
	
	//	UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	UITextField *textField;
	if( indexPath.row != 6 ) textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	else textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 85)] autorelease];
	
	textField.returnKeyType = UIReturnKeyDone;
	textField.delegate = self;
	textField.tag = indexPath.row;
	
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	NSDictionary* dictionary = [defaults dictionaryForKey:keyIndex];
	
	if( indexPath.row == 0 ) textField.text = [dictionary objectForKey:@"BANK_NAME"];
	if( indexPath.row == 1 ) textField.text = [dictionary objectForKey:@"BANK_NUMBER"];
	if( indexPath.row == 2 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 3 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 4 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NUMBER"];
	if( indexPath.row == 5 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NAME"];
	if( indexPath.row == 6 ) textField.text = [dictionary objectForKey:@"NOTE"];
	
	NSString *setText = [[NSString alloc] init];
	
	[cell setLabelText:[Menu objectAtIndex:indexPath.row] :setText];
	[cell.contentView addSubview:textField];
	[setText release];

	return cell;

}

// 保存する
- (void)textFieldDidEndEditing:(UITextField *)textField{
	
	NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
	
	if( textField.tag == 0 ) [dictionary setObject:textField.text forKey:@"BANK_NAME"];
	if( textField.tag == 1 ) [dictionary setObject:textField.text forKey:@"BANK_NUMBER"];
	if( textField.tag == 2 ) [dictionary setObject:textField.text forKey:@"BRANCH_NAME"];
	if( textField.tag == 3 ) [dictionary setObject:textField.text forKey:@"BRANCH_NUBER"];
	if( textField.tag == 4 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NUMBER"];
	if( textField.tag == 5 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NAME"];
	if( textField.tag == 6 ) [dictionary setObject:textField.text forKey:@"NOTE"];
	
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setObject:dictionary forKey:keyIndex];
	[defaults synchronize];
	
}

// キーボードを隠す
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
	[textField resignFirstResponder];
	return YES;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
}

@end


アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#6

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:Item.hを削除
 いや、削除する必要はないですよ。
 書き出しなら必要な時だけ Itemクラスが持つ情報を NSUserDefaultsに書き出す為の
NSMutableArrayや NSMutableDictionaryに入れて書き出したり、
読み出しなら NSUserDefaultsから読み出す為の NSMutableArrayや NSMutableDictionaryを
用意して、NSUserDefaultsから読み出した後 Itemに情報をセットしていくような形で
従来通り通常は Itemクラスで管理していくのが望ましいかと思います。

TEAS TEA さんが書きました:要素が1個の時は上手く行く様なのですが
 つまり、銀行名を BANK_NUMBERを設定すると BANK_NAMEを忘れる、とかそういう意味ですか?
 textFieldDidEndEditingでどんな dictionaryに情報をセットして NSUserDefaultsに
入れているのか考えてみれば、自ずと判るはずです。

 そもそもの話をすると Itemクラスが削除されていないのであれば、各詳細項目を入力する度に
NSUserDefaultsに保存しなさなくてもいいでしょう。
 せいぜい TOPに戻った時とか銀行数が変化したとき、或いは No.1で書いたタイミングくらいで
十分なわけですし。

TEAS TEA さんが書きました:TopMenuでの読み込みがよくわからない
 No4で示した通り、銀行の IDリストを記録しておいて、そのリストを元に
各銀行の情報を復元すれば銀行名は取得できるはずです。

 が、現状の選択した行数から IDを生成する方法はだめでしょう。
 別の手段を考えて下さい。
 他にもいくらでもあるはずです。生成する度にインクリメントされる内部カウンタを
用意するとか(この場合、このカウンタも NSUserDefaultsに保存)、日時を元にした文字列にするとか。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#7

投稿記事 by TEAS TEA » 10年前

ご回答ありがとう御座います。
Item.hを復元してみました。
データの管理はインクリメントで4桁で表す様にしたいと思っております。

>>書き出しなら必要な時だけ Itemクラスが持つ情報を NSUserDefaultsに書き出す為の
>>NSMutableArrayや NSMutableDictionaryに入れて書き出したり、
頂きましたURLでどのように値を取得しているのかが理解は出来たのですが
実際に使うとなるとやはり良く使い方がわかりません。
どのようにソースを記載すれば良いのでしょうか。

またナビゲーションバーがタッチされて戻る時に書き込みをしようとしているのですがメソッドが上手く拾ってくれません。
下記のメソッドではないのでしょうか?
- (void)navigationBar:(UINavigationBar*)navigationBar buttonClicked:(int)button{
NSLog( @"%d", button );
}

本当に質問ばかりで申し訳ないです。
長々と申し訳ございませんが現在のソースです。

コード:


//
//    TopMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "TopMenuController.h"
#import "EditMenuController.h"

@implementation TopMenuController

- (void)dealloc{
	[Menu release];
	[increment release];
	[super dealloc];
}

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStylePlain]) ) {
        self.title = @"口座情報";
		/*
        // 表示するデータを作成
		testData = [Item alloc];
		testData.bankName = @"三井住友銀行";
		testData.bankNumber = @"009";
		testData.branchName = @"○○支店";
		testData.branchNumber = @"001";
		testData.accountNumber = @"1234567890";
		testData.accountName = @"アプリ 太郎";
		testData.note = @"aaaa";
		*/
		/*
        Menu = [[NSMutableArray alloc] initWithObjects:
				testData.bankName,
				nil ];
		 */
    }
    return self;
}

- (void)viewDidLoad {
	// 編集ボタンの追加
	self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//	self.navigationController.navigationBarHidden = YES;
	Menu = [[NSMutableArray alloc] initWithObjects:
			nil ];
	
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	[defaults setInteger:1 forKey:@"INCREMENT"]; // 削除する(テスト用)
	[defaults synchronize]; // 削除する(テスト用)
	increment = [defaults integerForKey:@"INCREMENT"];
	NSLog( @"BANK_%04d",increment );
}

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	self.tableView.editing = NO;
}
// セルの追加/削除要求
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
	if ( UITableViewCellEditingStyleDelete == editingStyle ) {
		[Menu removeObjectAtIndex:indexPath.row];// データソースから実データを削除
		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];// テーブルからセルを削除
	}else if( UITableViewCellEditingStyleInsert == editingStyle ){
		// データの挿入
		[Menu insertObject:@"新規追加" atIndex:(Menu.count-1)];
		[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
	}
}

// 編集モードの最後の行のみ挿入モードにする
- (UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath{
	// 編集モードの場合の最後のRowだけ挿入モードにする
	if ( tableView.editing && Menu.count <= indexPath.row + 1 ) {
		return UITableViewCellEditingStyleInsert;
	} else {
		return UITableViewCellEditingStyleDelete;
	}
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
	if( editing ){
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count inSection:0];
		[Menu addObject:@"新規追加"];
		[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}else{
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count-1 inSection:0];
		[Menu removeLastObject];
		[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}
	[super setEditing:editing animated:YES];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {

    // 既にセルの型が登録済みかどうかをチェック
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"simple-cell"];
    if ( !cell ) {
        // セルの型が登録済みでないなら新しく登録する
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"simple-cell"] autorelease];
    } 
    // セルのラベルに表示するテキストを設定
    cell.textLabel.text = [Menu objectAtIndex:indexPath.row];
    return cell;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {

	Item* data = [Item alloc];
	data.list = @"";
	data.bankName = @"三井住友銀行";
	data.bankNumber = @"009";
	data.branchName = @"○○支店";
	data.branchNumber = @"001";
	data.accountNumber = @"1234567890";
	data.accountName = @"アプリ 太郎";
	data.note = @"aaaa";
	
	EditMenuController* viewEdit;
	viewEdit = [[EditMenuController alloc] init];
	viewEdit.keyIndex = [[NSString alloc] initWithFormat:@"BANK_%04d",increment];
	viewEdit.itemData = data;
	[self.navigationController pushViewController:viewEdit animated:YES];
	[viewEdit release];
	[data release];
	
}

@end
//
//    EditMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "EditMenuController.h"
#import "MyTableViewCell.h"

@implementation EditMenuController
@synthesize keyIndex;
@synthesize itemData;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
	if( indexPath.row == 6 ) return 96;
	return 42;
}

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

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStyleGrouped]) ) {
        self.title = @"口座情報";
        // 表示するデータを作成
        Menu = [[NSMutableArray alloc] initWithObjects:
				@"銀行名",
				@"銀行番号",
				@"支店名",
				@"支店番号",
				@"口座番号",
				@"口座名義",
				@"メモ",
				nil ];
    }
    return self;
}

- (void)viewDidLoad {
//	self.navigationController.navigationBarHidden = YES;
	// 編集ボタンの追加
	//self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//keyIndex = [[NSString alloc] initWithString:@"BANK_001"];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
	
	static NSString *CellIdentifier = @"Cell";
	MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
	if (cell == nil) {
		cell = [[[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
	}
	
	//	UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	UITextField *textField;
	if( indexPath.row != 6 ) textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	else textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 85)] autorelease];
	
	textField.returnKeyType = UIReturnKeyDone;
	textField.delegate = self;
	textField.tag = indexPath.row;
	
	if( indexPath.row == 0 ) textField.text = itemData.bankName;
	if( indexPath.row == 1 ) textField.text = itemData.bankNumber;
	if( indexPath.row == 2 ) textField.text = itemData.branchName;
	if( indexPath.row == 3 ) textField.text = itemData.branchNumber;
	if( indexPath.row == 4 ) textField.text = itemData.accountNumber;
	if( indexPath.row == 5 ) textField.text = itemData.accountName;
	if( indexPath.row == 6 ) textField.text = itemData.note;
	
	/*
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	NSDictionary* dictionary = [defaults dictionaryForKey:keyIndex];
	
	if( indexPath.row == 0 ) textField.text = [dictionary objectForKey:@"BANK_NAME"];
	if( indexPath.row == 1 ) textField.text = [dictionary objectForKey:@"BANK_NUMBER"];
	if( indexPath.row == 2 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 3 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 4 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NUMBER"];
	if( indexPath.row == 5 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NAME"];
	if( indexPath.row == 6 ) textField.text = [dictionary objectForKey:@"NOTE"];
	*/
	
	NSString *setText = [[NSString alloc] init];
	
	[cell setLabelText:[Menu objectAtIndex:indexPath.row] :setText];
	[cell.contentView addSubview:textField];
	[setText release];

	return cell;

}

// 保存する
- (void)textFieldDidEndEditing:(UITextField *)textField{
	
	NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
	
	if( textField.tag == 0 ) [dictionary setObject:textField.text forKey:@"BANK_NAME"];
	if( textField.tag == 1 ) [dictionary setObject:textField.text forKey:@"BANK_NUMBER"];
	if( textField.tag == 2 ) [dictionary setObject:textField.text forKey:@"BRANCH_NAME"];
	if( textField.tag == 3 ) [dictionary setObject:textField.text forKey:@"BRANCH_NUBER"];
	if( textField.tag == 4 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NUMBER"];
	if( textField.tag == 5 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NAME"];
	if( textField.tag == 6 ) [dictionary setObject:textField.text forKey:@"NOTE"];
	
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setObject:dictionary forKey:keyIndex];
	[defaults synchronize];
	
}

// キーボードを隠す
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
	[textField resignFirstResponder];
	return YES;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
}
/*
- (void)navigationBar:(UINavigationBar*)navigationBar buttonClicked:(int)button{
	NSLog( @"%d", button );
}
*/
@end

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#8

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:メソッドが上手く拾ってくれません。
 delegateを接続していないとか?
 でも、戻る時に処理するなら viewWillDisappearの方が適切ではないですか?

TEAS TEA さんが書きました:実際に使うとなるとやはり良く使い方がわかりません
 つまり、文法は判ったけど、設計としてどこにどのデータを持たせて、どの段階でどうすればいい、
というのが判らない、ということでしょうか?

TEAS TEA

Re: 動的に作りだされるデータを保存する

#9

投稿記事 by TEAS TEA » 10年前

viewWillDisappearですか(汗)
ちょっとメソッドを調べてみますね。

>>つまり、文法は判ったけど、設計としてどこにどのデータを持たせて、どの段階でどうすればいい、
>>というのが判らない、ということでしょうか?
その通りです。お恥ずかしながら本などを見ないと作れなくて・・・
原理はわかったのですが設計が出来ないんです。

PGとしては失格かとは思うのですが設計の仕方がよくわからないので
いつも作りたいものがあったらコーディングをしながら考えてしまいます。
勿論、不味いとは思っております。

いつも頼ってばかりで本当に申し訳ないと思っております。
何とかサンプルを頂けないでしょうか?

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#10

投稿記事 by Justy » 10年前

[quote="TEAS TEA"メソッドが上手く拾ってくれません。[/quote]
 delegateを接続していないとか?
 でも、戻る時に処理するなら viewWillDisappearの方が適切ではないですか?

TEAS TEA さんが書きました:原理はわかったのですが設計が出来ないんです
 では、とりあえずソースから NSUserDefaultsを使った処理を全部削除した上で
アプリを終了したらデータを忘れてしまっても構わないので、それ以外の部分は
正常に動作する(各銀行のデータ管理も含めて)アプリを作って下さい。

 そうですね、TopMenuControllerに複数の Itemクラスを入れる配列(NSMutableArray)でも
作って纏めて管理しましょうか。
 銀行が新規追加されたり削除されたらこの配列を変更していきます。
 UITableViewの表示もこの配列の銀行名を表示するようにします。
 EditMenuControllerで詳細を表示するときはその中の対象の Itemクラスを EditMenuControllerに
引き渡して、Item内の情報を編集する処理をするようにしてみて下さい。


 それが出来たら NSUserDefaultsの処理を入れて次回起動時にデータを復元する
処理を入れていきましょう。

 当面は細かいことは考えないでデータ構造も含めてシンプルに、
起動時に読み取り、終了時・バックグラウンドになった時に書き込みを
処理するようにしましょう。

 まずは書き込みから。
 これは UIApplicationDelegateの OS4.0以降なら applicationDidEnterBackground、
未満なら applicationWillTerminateに記述します。

 肝心な記述内容ですが
[NSUserDefaults resetStandardUserDefaults];
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
と前回の情報をリセットしてから NSUserDefaultsオブジェクトを取得します。

 書き込むデータは、まず銀行の数を整数値(キーは "BankNum"とでもしておきましょう)で
NSUserDefaultsに入れた後、以下のような処理を for文で銀行の数分だけ行います。

・ 空の NSMutableDictionaryを用意して、詳細な各銀行の情報を Itemクラスから
NSMutableDictionaryに設定していきます。
・ その NSMutableDictionaryを何番目の銀行なのかの番号(forループの回数でOK)を文字列にしたものを
キーにして NSUserDefaultsに入れます。

 全ての銀行のデータを入れ追えたら、最後に synchronizeを呼び出して書き出しは終了です。


 次は読み出しです。
 TopMenuControllerの initに書くとしましょうか。
 
 キー "BankNum"で数値を取り出します。この数値が 0以下なら初回起動時か1つも情報を
入力していないことになるので、ここで処理は終了です。
 1以上入っているのであればその数の分だけ forで回し以下のように処理します。

・ 空の NSMutableDictionaryに forの回数をキーとして NSUserDefaultsから情報を
取り出します(nilでないことを確認)。
・ 空の Itemクラスを用意し、NSMutableDictionaryから情報を写していきます。
・ 設定した Itemを TopMenuControllerが持つ Itemの配列に追加します。


 これで終わりです。
 まぁ実際に組んで試しているわけではなく、机上で書いているので細かいところは
うまくいかないかもしれませんが、概ねこんなところです。

 まずははやれるところまでやってみて下さい。


TEAS TEA さんが書きました:何とかサンプルを頂けないでしょうか?
 NSUserDefaultsのサンプルなら検索すればいろいろ出てくると思いますけど、

AppPrefs
http://developer.apple.com/library/ios/ ... Intro.html

DrillDownSave
http://developer.apple.com/library/ios/ ... Intro.html

MoviePlayer
http://developer.apple.com/library/ios/ ... Intro.html

とかでしょうか。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#11

投稿記事 by TEAS TEA » 10年前

何度もありがとうございます。
しかもいつもわかりやすく・・・。
本当に助かります。

自分なりに実装してみたのですが保存が出来ないのと警告が出てしまいます。
多分、実装の仕方がまずいんですよね・・・。
又、iPhoneのOSVerによって使う関数を変えるということでしょうか?
applicationWillTerminateの所がよく分かりません。
どのように使い分けるのでしょうか。

警告文
WARNING! Creating precompiled collator because collator is out of date. This is expensive!

長々と申し訳ないですがソースを記載させて頂きます。

コード:

//
//  TopMenuController.h
//
//  Created by ToKoRo on 2009-08-16.
//

#import <UIKit/UIKit.h>
#import "Item.h"

@interface TopMenuController : UITableViewController<UIApplicationDelegate>{
@private
	NSMutableArray* Menu;
}

@end

//
//    TopMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "TopMenuController.h"
#import "EditMenuController.h"

@implementation TopMenuController

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

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStylePlain]) ) {
        self.title = @"口座情報";
		/*
        // 表示するデータを作成
		testData = [Item alloc];
		testData.bankName = @"三井住友銀行";
		testData.bankNumber = @"009";
		testData.branchName = @"○○支店";
		testData.branchNumber = @"001";
		testData.accountNumber = @"1234567890";
		testData.accountName = @"アプリ 太郎";
		testData.note = @"aaaa";
		*/
		
        Menu = [[NSMutableArray alloc] init];
		
		// 読み込み
		NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
		int num = [defaults integerForKey:@"BankNum"];
		if( num <= 0){
			return self;
		}else{
			for(int i=0; i<num; i++){
				NSString* keyIndex = [[NSString alloc] initWithFormat:@"BANK_%04d",i];
				NSDictionary* dictionary = [defaults dictionaryForKey:keyIndex];
				if( dictionary != nil ){
					Item* item = [Item alloc];
					item.bankName = [dictionary objectForKey:@"BANK_NAME"];
					item.bankNumber = [dictionary objectForKey:@"BANK_NUMBER"];
					item.branchName = [dictionary objectForKey:@"BRANCH_NAME"];
					item.branchNumber = [dictionary objectForKey:@"BRANCH_NUBER"];
					item.accountNumber = [dictionary objectForKey:@"ACCOUNT_NUMBER"];
					item.accountName = [dictionary objectForKey:@"ACCOUNT_NAME"];
					item.note = [dictionary objectForKey:@"NOTE"];
					[Menu addObject:item];
				}
				
				NSLog( @"%@",[dictionary objectForKey:@"BANK_NAME"] );

			}
		}
    }
    return self;
}

- (void)viewDidLoad {
	// 編集ボタンの追加
	self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//	self.navigationController.navigationBarHidden = YES;
	
	Menu = [[NSMutableArray alloc] initWithObjects:
			nil ];
	
	// test用 削除予定
	Item* initData = [Item alloc];
	initData.bankName = @"新規追加";
	[Menu addObject:initData];
	
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	[defaults setInteger:1 forKey:@"INCREMENT"]; // 削除する(テスト用)
	[defaults synchronize]; // 削除する(テスト用)
}

- (void)viewDidAppear:(BOOL)animated {
	[super viewDidAppear:animated];
	self.tableView.editing = NO;
}
// セルの追加/削除要求
- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath{
	if ( UITableViewCellEditingStyleDelete == editingStyle ) {
		[Menu removeObjectAtIndex:indexPath.row];// データソースから実データを削除
		[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationLeft];// テーブルからセルを削除
	}else if( UITableViewCellEditingStyleInsert == editingStyle ){
		// データの挿入
		Item* insertData = [Item alloc];
		insertData.bankName = @"新規追加";
		[Menu insertObject:insertData atIndex:(Menu.count-1)];
		[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
	}
}

// 編集モードの最後の行のみ挿入モードにする
- (UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath{
	// 編集モードの場合の最後のRowだけ挿入モードにする
	if ( tableView.editing && Menu.count <= indexPath.row + 1 ) {
		return UITableViewCellEditingStyleInsert;
	} else {
		return UITableViewCellEditingStyleDelete;
	}
}

- (void)setEditing:(BOOL)editing animated:(BOOL)animated{
	if( editing ){
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count inSection:0];
		Item* insertData = [Item alloc];
		insertData.bankName = @"新規追加";
		[Menu addObject:insertData];
		[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}else{
		NSIndexPath *path = [NSIndexPath indexPathForRow:Menu.count-1 inSection:0];
		[Menu removeLastObject];
		[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
	}
	[super setEditing:editing animated:YES];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {

    // 既にセルの型が登録済みかどうかをチェック
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"simple-cell"];
    if ( !cell ) {
        // セルの型が登録済みでないなら新しく登録する
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"simple-cell"] autorelease];
    } 
    // セルのラベルに表示するテキストを設定
	Item* item = [Item alloc];
	item = [Menu objectAtIndex:indexPath.row];
    cell.textLabel.text = item.bankName;
    return cell;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {

	/*
	Item* data = [Item alloc];
	data.list = @"";
	data.bankName = @"三井住友銀行";
	data.bankNumber = @"009";
	data.branchName = @"○○支店";
	data.branchNumber = @"001";
	data.accountNumber = @"1234567890";
	data.accountName = @"アプリ 太郎";
	data.note = @"aaaa";
	*/
	
	EditMenuController* viewEdit;
	viewEdit = [[EditMenuController alloc] init];
	viewEdit.itemData = [Menu objectAtIndex:indexPath.row];
	[self.navigationController pushViewController:viewEdit animated:YES];
	[viewEdit release];
	
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
	
	[NSUserDefaults resetStandardUserDefaults];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	// 銀行の数を入れる
	[defaults setInteger:[Menu count] forKey:@"BankNum"];
	
	// それぞれのデータを挿入
	for(int i=0; i<[Menu count]; i++){
		
		Item* item = [Item alloc];
		item = [Menu objectAtIndex:i];
		NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
		[dictionary setObject:item.bankName forKey:@"BANK_NAME"];
		[dictionary setObject:item.bankNumber forKey:@"BANK_NUMBER"];
		[dictionary setObject:item.branchName forKey:@"BRANCH_NAME"];
		[dictionary setObject:item.branchNumber forKey:@"BRANCH_NUBER"];
		[dictionary setObject:item.accountNumber forKey:@"ACCOUNT_NUMBER"];
		[dictionary setObject:item.accountName forKey:@"ACCOUNT_NAME"];
		[dictionary setObject:item.note forKey:@"NOTE"];
		
		NSString* keyIndex = [[NSString alloc] initWithFormat:@"BANK_%04d",i];
		[defaults setObject:dictionary forKey:keyIndex];
	}
	[defaults synchronize];

}
@end
//
//    EditMenuController.m
//
//    Created by ToKoRo on 2009-08-16.
//

#import "EditMenuController.h"
#import "MyTableViewCell.h"

@implementation EditMenuController
@synthesize keyIndex;
@synthesize itemData;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
	if( indexPath.row == 6 ) return 96;
	return 42;
}

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

- (id)init {
    if ( (self = [super initWithStyle:UITableViewStyleGrouped]) ) {
        self.title = @"口座情報";
        // 表示するデータを作成
        Menu = [[NSMutableArray alloc] initWithObjects:
				@"銀行名",
				@"銀行番号",
				@"支店名",
				@"支店番号",
				@"口座番号",
				@"口座名義",
				@"メモ",
				nil ];
    }
    return self;
}

- (void)viewDidLoad {
//	self.navigationController.navigationBarHidden = YES;
	// 編集ボタンの追加
	//self.navigationItem.rightBarButtonItem = [self editButtonItem];
	//keyIndex = [[NSString alloc] initWithString:@"BANK_001"];
}

#pragma mark ----- UITableViewDataSource Methods -----

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section {
    return [Menu count];
}

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath {
	
	static NSString *CellIdentifier = @"Cell";
	MyTableViewCell *cell = (MyTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
	if (cell == nil) {
		cell = [[[MyTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
	}
	
	//	UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	UITextField *textField;
	if( indexPath.row != 6 ) textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 30)] autorelease];
	else textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 150, 85)] autorelease];
	
	textField.returnKeyType = UIReturnKeyDone;
	textField.delegate = self;
	textField.tag = indexPath.row;
	
	if( indexPath.row == 0 ) textField.text = itemData.bankName;
	if( indexPath.row == 1 ) textField.text = itemData.bankNumber;
	if( indexPath.row == 2 ) textField.text = itemData.branchName;
	if( indexPath.row == 3 ) textField.text = itemData.branchNumber;
	if( indexPath.row == 4 ) textField.text = itemData.accountNumber;
	if( indexPath.row == 5 ) textField.text = itemData.accountName;
	if( indexPath.row == 6 ) textField.text = itemData.note;
	
	/*
	NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
	NSDictionary* dictionary = [defaults dictionaryForKey:keyIndex];
	
	if( indexPath.row == 0 ) textField.text = [dictionary objectForKey:@"BANK_NAME"];
	if( indexPath.row == 1 ) textField.text = [dictionary objectForKey:@"BANK_NUMBER"];
	if( indexPath.row == 2 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 3 ) textField.text = [dictionary objectForKey:@"BRANCH_NAME"];
	if( indexPath.row == 4 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NUMBER"];
	if( indexPath.row == 5 ) textField.text = [dictionary objectForKey:@"ACCOUNT_NAME"];
	if( indexPath.row == 6 ) textField.text = [dictionary objectForKey:@"NOTE"];
	*/
	
	NSString *setText = [[NSString alloc] init];
	
	[cell setLabelText:[Menu objectAtIndex:indexPath.row] :setText];
	[cell.contentView addSubview:textField];
	[setText release];

	return cell;

}

// 保存する
- (void)textFieldDidEndEditing:(UITextField *)textField{
	/*
	NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
	
	if( textField.tag == 0 ) [dictionary setObject:textField.text forKey:@"BANK_NAME"];
	if( textField.tag == 1 ) [dictionary setObject:textField.text forKey:@"BANK_NUMBER"];
	if( textField.tag == 2 ) [dictionary setObject:textField.text forKey:@"BRANCH_NAME"];
	if( textField.tag == 3 ) [dictionary setObject:textField.text forKey:@"BRANCH_NUBER"];
	if( textField.tag == 4 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NUMBER"];
	if( textField.tag == 5 ) [dictionary setObject:textField.text forKey:@"ACCOUNT_NAME"];
	if( textField.tag == 6 ) [dictionary setObject:textField.text forKey:@"NOTE"];
	
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	[defaults setObject:dictionary forKey:keyIndex];
	[defaults synchronize];
	*/
}

// キーボードを隠す
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
	[textField resignFirstResponder];
	return YES;
}

#pragma mark ----- UITableViewDelegate Methods -----

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
}

@end

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#12

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:自分なりに実装してみたのですが保存が出来ない
 もうひと踏ん張りですね。
 textFieldDidEndEditingで textFieldから対象の Itemのプロパティの情報を更新して下さい。

 あと、applicationDidEnterBackgroundを TopMenuControllerの中に入れていますが、
delegateが繋がっていません。
 TopMenuControllerと繋げてもいいのですが、既に HelloWorldAppDelegateの方で繋がっているので
こちらを利用した方が良さそうです。
 まずは HelloWorldAppDelegate側にapplicationDidEnterBackgroundを書いて、
そこから TopMenuクラスの applicationDidEnterBackgroundを呼び出すといいでしょう。

 それから、viewDidLoadで Menuを初期化してしまっているのも問題ですね。

TEAS TEA さんが書きました:iPhoneのOSVerによって使う関数を変えるということでしょうか?
 そうです。
 というか、OSのバージョンによって呼ばれる関数が変わります。
TEAS TEA さんが書きました:WARNING! Creating precompiled collator because collator is out of date. This is expensive!
 ちょっとこちらはわかりませんが、検索してみてはどうでしょうか?

TEAS TEA

Re: 動的に作りだされるデータを保存する

#13

投稿記事 by TEAS TEA » 10年前

ご回答ありがとう御座いました。
あ・・・Editを修正していなかったので駄目だったのですね・・・。
当たり前ですね。すみませんでした。
ご指摘いただいた通り修正しましたらデータが表示されました。

>>それから、viewDidLoadで Menuを初期化してしまっているのも問題ですね。
なるほど・・・修正し削除しました。
細かい所まで見て頂いて本当に助かります。

>>iPhoneのOSVerによって使う関数を変えるということでしょうか?
これは同じ処理を2個書けばよいということでしょうか?
私がOSの情報を何かの関数で取得して分岐させるということはないのですね。
ありがとうございます。

>>警告の件
調べてみたのですがOS側のバグらしい等のblogしか出てきませんでした。
ただそんな筈がないと思いPGにお詳しいJusty様にお尋ねさせて頂きました。
Justy様で分からないのでしたらバグな気がしてきました・・・。

>>まずは HelloWorldAppDelegate側にapplicationDidEnterBackgroundを書いて、
>>そこから TopMenuクラスの applicationDidEnterBackgroundを呼び出すといいでしょう。
ここがよくわからないのですが下記のソースの様な感じでいいのでしょうか?
又、[topMenu applicationDidEnterBackground:self];の引数は何にすれば良いのでしょうか?
UIApplicationなる変数は私では用意していない気がするので・・・。

コード:

//TopMenu.m

- (void)applicationDidEnterBackground:(UIApplication *)application {
	
	[NSUserDefaults resetStandardUserDefaults];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	// 銀行の数を入れる
	[defaults setInteger:[Menu count] forKey:@"BankNum"];
	
	// それぞれのデータを挿入
	for(int i=0; i<[Menu count]; i++){
		
		Item* item = [Item alloc];
		item = [Menu objectAtIndex:i];
		NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
		[dictionary setObject:item.bankName forKey:@"BANK_NAME"];
		[dictionary setObject:item.bankNumber forKey:@"BANK_NUMBER"];
		[dictionary setObject:item.branchName forKey:@"BRANCH_NAME"];
		[dictionary setObject:item.branchNumber forKey:@"BRANCH_NUBER"];
		[dictionary setObject:item.accountNumber forKey:@"ACCOUNT_NUMBER"];
		[dictionary setObject:item.accountName forKey:@"ACCOUNT_NAME"];
		[dictionary setObject:item.note forKey:@"NOTE"];
		
		NSString* keyIndex = [[NSString alloc] initWithFormat:@"BANK_%04d",i];
		[defaults setObject:dictionary forKey:keyIndex];
	}
	[defaults synchronize];
	
}
//
//  HelloWorldAppDelegate.h
//
//  Created by ToKoRo on 2009-08-15.
//

#import <UIKit/UIKit.h>
#import "AdMobDelegateProtocol.h"

@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate, AdMobDelegate> {
	UIWindow* window_;
	UIViewController* rootController_;
	AdMobView* adMobAd;
}

@property (nonatomic, retain) UIWindow* window;

@end

// AppDegate.m
- (void)applicationDidEnterBackground:(UIApplication *)application {
	
	TopMenuController* topMenu = [[[TopMenuController alloc] init] autorelease];
//	[topMenu applicationDidEnterBackground:self];
	
}

// EditMenu.m
// 保存する
- (void)textFieldDidEndEditing:(UITextField *)textField{
	
	if( textField.tag == 0 ) itemData.bankName = textField.text;
	if( textField.tag == 1 ) itemData.bankNumber = textField.text;
	if( textField.tag == 2 ) itemData.branchName = textField.text;
	if( textField.tag == 3 ) itemData.branchNumber = textField.text;
	if( textField.tag == 4 ) itemData.accountNumber = textField.text;
	if( textField.tag == 5 ) itemData.accountName = textField.text;
	if( textField.tag == 6 ) itemData.note = textField.text;

}

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#14

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:これは同じ処理を2個書けばよいということでしょうか?
 そういうことになりますね。
 処理を別の関数に纏めておいて、2カ所で呼び出すだけにしておけばいいでしょう。
(OSやデバイスの違いで呼び出される関数が違うので、2通りのテストが必要です)

TEAS TEA さんが書きました:私がOSの情報を何かの関数で取得して分岐させるということはないのですね
 はい。

TEAS TEA さんが書きました:ここがよくわからないのですが下記のソースの様な感じでいいのでしょうか?
 applicationDidEnterBackgroundの中で新規に TopMenuControllerを生成してはいけません。
 保存したい情報を持った Itemリストを持っているのは applicationDidFinishLaunchingの中で
生成した TopMenuControllerの方です。
 
 従って、applicationDidFinishLaunchingの中で生成した TopMenuControllerを覚えておき、
そのオブジェクトを使って TopMenuController側の applicationDidEnterBackgroundを
呼び出してください。

TEAS TEA さんが書きました:[topMenu applicationDidEnterBackground:self];の引数は何にすれば良いのでしょうか
 あー、実際のところ TopMenuController側の applicationDidEnterBackgroundは
delegateというわけではないので関数名や引数は何であっても構わなんですけど、
とりあえず HelloWorldAppDelegateの applicationDidEnterBackgroundの引数 applicationを
そのまま指定しておけばいいんじゃないでしょうか
 勿論 TopMenuControllerの方を修正して引数なしにしてしまってもいいですね。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#15

投稿記事 by TEAS TEA » 10年前

ご指導ありがとうございます。
何とかそれらしい動きになってきました。
本当にありがとうございます。

ただ一度、保存した後にアプリケーションを落として起動し直すと落ちてしまいます。
タスクに残した状態ですと問題ないみたいです。
タスクから消すと駄目です。

更にもう一度起動し直すと起動はするのですがデータが全て飛んでしまっております。
※保存された形跡はあります。もともと2個のデータがあったら空欄のセルが2つできています。

デバッガがシグナルkillとしか出ていないので原因がわかりません・・・。
多分、Justyさんが仰っていましたnilのチェックが悪いと思うのですが見渡した限り見つかりませんでした。

お手数おかけして申し訳ないのですが今一度ソースを見ては頂けないでしょうか。
Justy様の気が向かなければ放置で構いませんので・・・。

イマイチAppDelegate周りを理解していないのでこれから勉強します。

長いのでURLを貼らせて頂きます。
URL:http://www1.axfc.net/uploader/Sc/so/197308
PASS:123

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#16

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:アプリケーションを落として起動し直すと落ちてしまいます。
 ランチャーから起動したのに、アプリが落ちて再度ランチャーに戻る、という意味ですか?
 であれば、実機なのかシミュレータなのか等、もう少し手順など状況を詳しく補足してもらえますか?
 エラーログもあれば。

TEAS TEA さんが書きました:保存された形跡はあります。もともと2個のデータがあったら空欄のセルが2つできています。
 TopMenuControllerの WriteDataの forの中で各項目毎に ifで nilチェックしていますが、
これが原因です。
 空の dictionaryなんですから中には何も入っていないわけで、中に何か入っていたらデータをセットする、
という処理では何もセットされないままですよね?

 キーが BRANCH_NUMBERと BRANCH_NUBERが混在しているのも問題ですね。

TEAS TEA さんが書きました:イマイチAppDelegate周りを理解していないのでこれから勉強します
 TopMenuControllerの applicationDidEnterBackgroundは大丈夫ですが、
applicationWillTerminateが呼ばれることがない状況なので、そのあたりも何とかしてみてください。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#17

投稿記事 by TEAS TEA » 10年前

ぬけておりました・・・。
人の話を聞けと怒られてしまいますよね・・・。
ご指摘ありがとう御座います。

HelloWorldAppDelegate.m
- (void)applicationWillTerminate:(UIApplication *)application{
[topMenu applicationDidEnterBackground:application];
}

nilについて
ご指摘ありがとうございます。
読み込みでnilチェックをしてなくて落ちてしまっていたので
何も考えずに書き込みにも追加しておりました。
見てみると確かにnilなのが当たり前ですもんね(汗)
小さなミスが多すぎて申し訳ないです。

又、全てNUMBERに修正しました。
開発環境に頼り過ぎで英単語が書けなくなってしまいお恥ずかしい限りです。

落ちるのは下記の手順の時です。

起動する。
ホームに戻る
ホームボタンをダブルクリックしてアプリケーションを落とす。
起動する。 ココで落ちます。
落ちた後に自分で再起動する。(もう一度アプリを選ぶ)と問題なく動きます。
又、データも正常に保存されております。

デバイスで試してみた所下記のコードが吐き出されました。
ただメモリの番地が書いてあってよくわかりませんでした。

[Session started at 2011-01-23 17:53:04 +0900.]
GNU gdb 6.3.50-20050815 (Apple version gdb-1510) (Fri Oct 22 04:12:10 UTC 2010)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "--host=i386-apple-darwin --target=arm-apple-darwin".tty /dev/ttys001
プログラムをデバッガに読み込み中...
sharedlibrary apply-load-rules all
プログラムは読み込まれました。
target remote-mobile /tmp/.XcodeGDBRemote-114-51
Switching to remote-macosx protocol
mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
run
実行中...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
Ignoring packet error, continuing...
gdb stack trace around reply contains invalid hex digit:
0 gdb-arm-apple-darwin 0x0019026b remote_backtrace_self + 54

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#18

投稿記事 by Justy » 10年前

 今一つ判らないので、以下のテストをしてみてください。

・ 実機上でデバッガを接続しないでテストして再現するかどうか
 これで落ちたのなら、オーガナイザにあるコンソールログやデバイスログを見せてください。

・ デバッガから実行し、ホームに戻る。アプリを殺す、再度デバッガから実行する。
 これで落ちたのなら落ちたときにデバッガのスタックトレースの状況や各種ログで怪しそうなのを
見せてください。

・ Admobを外して(requestAdWithDelegateしない)テスト。

TEAS TEA さんが書きました:デバイスで試してみた所下記のコードが吐き出されました
 ちなみにこれを実行したときのプロビジョニングプロファイルは開発用ですか? 配布用ですか?

TEAS TEA

Re: 動的に作りだされるデータを保存する

#19

投稿記事 by TEAS TEA » 10年前

ご回答ありがとう御座います。
返信が遅れてしまい申し訳ありませんでした。

すぐにでも試したいのですが立て込んでおりまして・・・。
水曜位まで待って頂けますと助かります。

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#20

投稿記事 by Justy » 10年前

 了解です。
 まったりといきましょう。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#21

投稿記事 by TEAS TEA » 10年前

Justy様

お待たせしました。
頂いた3つのことを試しましたがどれも落ちませんでした。
デバッガを接続して落としてそれを起動するという手順が悪かったみたいです。
本来ならクリーニングしなければならないゴミが溜まっていたのでしょうか・・・。

ご指示をありがとうございました。
Justy様のお陰で保存の仕方だけではなくデータの管理の仕方が
少しだけですか理解できる様になりました。

又、現在トップページで下記の様に書いて表示しております。
Item* item = [Item alloc];
item = [Menu objectAtIndex:indexPath.row];
cell.textLabel.text = item.bankName;

編集の画面からトップページに戻っても古いbankNameが表示されてしまうのですがこれを修正できない物でしょうか。

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#22

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:Jデバッガを接続して落としてそれを起動するという手順が悪かったみたいです。
本来ならクリーニングしなければならないゴミが溜まっていたのでしょうか・・・。[/quote]
 多分デバッガが繋がったままプロセス が終了したということで、「プロセス kill」状態になり、
そのまま同じアプリを手動で起動したのので何かあったのではないかと思います。

TEAS TEA さんが書きました:編集の画面からトップページに戻っても古いbankNameが表示されてしまう
 トップページの表示開始時(viewDidAppear)にテーブルをリロードしてください。

TEAS TEA さんが書きました:又、現在トップページで下記の様に書いて表示しております。
Item* item = [Item alloc];
 ところで、この allocは必要ですか?
 これ以外にも keyIndexとか解放されていないような気がしますけど。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#23

投稿記事 by TEAS TEA » 10年前

ご回答ありがとう御座います。

リロードする専用の関数があるのですね・・・。ありがとうございます。
添付した物には実装しておりませんが

コード:

- (void)viewDidAppear:(BOOL)animated {
	[self.tableView reloadData];
	[super viewDidAppear:animated];
	self.tableView.editing = NO;
}
と記載したら出来ました。

またご指摘ありがとう御座います。
keyIndexは使っていないので削除してしまいました。
allocはメモリの確保に必要だと思っていたのですがその部分で書かないで直接代入しても出来ました。
なぜなんでしょうか・・・。代入元のオブジェクトがallocされているからかと考えたのですが・・・。

また、データの保存が出来なくなってしまいました。
修正前の物が見当たらないです。

http://www1.axfc.net/uploader/He/so/310551
PASS:123

Justy様に何度もソースをお見せし意見を頂くのは大変申し訳ないと思うのですが今一度確認頂けないでしょうか・・・?
お暇の時で結構です。頼れるのはJusty様しかいないので数日かかっても構いません。
本当に申し訳ないのですがどうかよろしくお願い致します。

アバター
Justy
副管理人
記事: 122
登録日時: 10年前
住所: 神奈川県

Re: 動的に作りだされるデータを保存する

#24

投稿記事 by Justy » 10年前

TEAS TEA さんが書きました:代入元のオブジェクトがallocされているからかと考えたのですが・・・。
 そうです。
 まぁ何にせよ、全般的に alloc周りは見直してください。
TEAS TEA さんが書きました:データの保存が出来なくなってしまいました。
 コードを見た感じ、保存も復帰もできています。
 ダメなのは、NSUserDefaultsからデータを復元したのにも関わらず、再初期化しなおしているからです。

TEAS TEA

Re: 動的に作りだされるデータを保存する

#25

投稿記事 by TEAS TEA » 10年前

遅くなってしまいすみませんでした。
出来ました・・・。
こんな簡単なことを聞いてしまい申し訳ありませんでした。
Justy様には今回も非常にお世話になりました。
長い間、本当にありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る