質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

Q&A

解決済

1回答

5611閲覧

UITableViewのcellForRowAtIndexPathが2回目から呼ばれない

mm--_--mm

総合スコア113

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

iOS

iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

0グッド

0クリップ

投稿2015/12/09 07:28

編集2015/12/11 06:45

いつもお世話になっております。

表題の件ですが、一回UITableViewをviewdidlaod内で生成し、値を表示した後に別の関数でもう一度cellに表示する値を取得しなおして一回目に生成したUITableViewを削除し、もう一回UITableViewを生成したいのですが、2回目以降からUITableViewを作成しようとしてもcellForRowAtIndexPathが呼ばれず、作成することができません...

調べてみると、numberOfRowsInSectionの値は0になっているとcellForRowAtIndexPathが呼ばれないとネットに書いてありましたが、NSLogで確認してみたところ、0にはなっていませんでした。

この原因がわかる方おりましたら教えていただけると幸いです。
以上です。
よろしくお願いいたします。

*追記

下記がUITableViewを更新しようとしているコードになります。

objective

1 2hoge.hの中 3 4NSMutableDictionary *m_UserListDict; 5@property (retain, nonatomic)NSMutableArray *hoge; 6NSString *UserCnt; 7NSString *str; 8NSMutableArray *val; 9 10hoge.mの中 11 12int iUserCnt; 13CGRect listView_windowsize; 14float listView_height_windowsize; 15float listView_width_windowsize; 16 17- (void)viewDidLoad { //tableviewの生成 18 19 listView_windowsize = [[UIScreen mainScreen] bounds]; 20 listView_height_windowsize = listView_windowsize.size.height; 21 listView_width_windowsize = listView_windowsize.size.width; 22 23 listtable = [[UITableView alloc] initWithFrame:[self.view bounds]]; 24 listtable.frame = CGRectMake(0, 44 , listView_width_windowsize, listView_height_windowsize * 0.8); 25 listtable.delegate = self; 26 listtable.dataSource = self; 27 listtable.allowsMultipleSelection = YES; 28 [self.view addSubview:listtable]; 29 30} 31 32- (void)OnEnterMember:(const char*)strUserId { //サーバーから通知を受け取る関数(ここも都合上、割愛させてもらってます) 33 34 [self performSelectorOnMainThread:@selector(DisplayList) withObject:nil waitUntilDone:YES]; 35 36} 37 38-(void)get_data{ //サーバーからxml形式でデータを取得し、格納する。(サーバと通信してる部分等は省略してます) 39 40 m_UserListDict = [[NSMutableDictionary alloc]init]; 41 [m_UserListDict setDictionary:UserList]; 42 for (id key in m_UserListDict){ 43 NSLog(@"%@,%@", key, m_UserListDict[key]); 44 } 45} 46 47- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView //セクションの数を返す 48{ 49 // Return the number of sections. 50 return 1; 51} 52 53- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section //cellの数を返す 54{ 55 56 return self.hoge.count; 57 58 59} 60 61- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 62 UITableViewCell *cell; 63 64 static NSString *CellIdentifier = @"Cell"; 65 cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 66 67 if (cell == nil) { 68 69 cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier]; 70 cell.selectionStyle = UITableViewCellSelectionStyleNone; 71 72 } 73 cell.textLabel.text = [self.hoge objectAtIndex:indexPath.row]; 74 75 return cell; 76 77} 78 79-(void)DisplayList{ 80 81 [self get_data]; 82 83 NSLog(@"isMainThread=%@", NSThread.currentThread.isMainThread?@"YES":@"NO"); 84 str = [[NSString alloc]init]; 85 val = [[NSMutableArray alloc]init]; 86 self.userlistarray = [[NSMutableArray alloc]init]; 87 UserCnt = [m_UserListDict objectForKey:@"UserCnt"]; 88 iUserCnt = [UserCnt intValue]; 89 90 for ( int i = 0; i < iUserCnt; i++){ 91 92 str = [NSString stringWithFormat:@"%d", i]; 93 val = [[m_UserListDict objectForKey:str] objectForKey:@"name"]; 94 [self.hoge addObject:val]; 95 96 } 97 NSLog(@"reloadDataの直前のlisttable=%@", listtable); 98 99 [listtable reloadData]; 100 101 NSLog(@"reloadDataの直後のlisttable=%@", listtable); 102 userlistcnt = (int)[self.userlistarray count]; 103}

処理の流れとしてはm_UserListDictの中にあるnameというkeyで保存されている値をvalに入れてそれを
self.hogeに入れて最後に[listtable reloadData];を行っている処理になります。
m_UserListDictの中身が空とかいう問題はありませんでした。

よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

まず、UITableViewを削除するのはやめましょう。

値を取得しなおした後、

objectivec

1[tableView reloadData];

とすればテーブルが更新されるはずです。


【追記】

サンプルコードです。
セルをタップするとセルが増えていきます。

objectivec

1#import "ViewController.h" 2 3@interface ViewController () 4{ 5 NSMutableDictionary *m_UserListDict; 6 NSString *UserCnt; 7 NSString *str; 8 NSMutableArray *val; 9 int iUserCnt; 10 UITableView *listtable; 11} 12@property (retain, nonatomic)NSMutableArray *hoge; 13@end 14 15#define _REUSEID @"hoge" 16 17@implementation ViewController 18 19- (void)viewDidLoad 20{ 21 [super viewDidLoad]; 22 23 //テーブル生成 24 listtable = [[UITableView alloc] initWithFrame:self.view.frame]; 25 [self.view addSubview:listtable]; 26 listtable.dataSource = self; 27 listtable.delegate = self; 28 [listtable registerClass:UITableViewCell.class forCellReuseIdentifier:_REUSEID]; 29 30 //m_UserListDict初期化 31 m_UserListDict = 32 @{ 33 @"UserCnt": @"3", 34 @"0": @{@"name": @"zero"}, 35 @"1": @{@"name": @"one"}, 36 @"2": @{@"name": @"two"}, 37 }.mutableCopy; 38 //NSLog(@"%@", m_UserListDict); 39 40 //hoge初期化 41 [self DisplayList]; 42} 43 44//セル数を返す 45- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 46{ 47 return self.hoge.count; 48} 49 50//セル生成 51- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 52{ 53 //セル取得 54 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_REUSEID]; 55 //セル設定 56 cell.textLabel.text = self.hoge[indexPath.row]; 57 58 return cell; 59} 60 61//セルタップ時に呼ばれる 62- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 63{ 64 //m_UserListDictに追加 (この中はあまり気にしないで下さい) 65 { 66 //key生成 67 NSString *key = @(self.hoge.count).stringValue; 68 //obj生成 69 NSNumberFormatter *nf = NSNumberFormatter.new; 70 nf.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"]; 71 nf.numberStyle = NSNumberFormatterSpellOutStyle; 72 NSString *name = [nf stringFromNumber:@(self.hoge.count)]; 73 m_UserListDict[key] = @{@"name": name}; 74 //UserCnt+1 75 m_UserListDict[@"UserCnt"] = @([m_UserListDict[@"UserCnt"] integerValue] + 1).stringValue; 76 } 77 78 //更新 79 [self DisplayList]; 80} 81 82//hoge更新 83// reloadDataをループの外に出した以外は変更無しです 84-(void)DisplayList 85{ 86 str = [[NSString alloc]init]; 87 val = [[NSMutableArray alloc]init]; 88 self.hoge = [[NSMutableArray alloc]init]; 89 90 UserCnt = [m_UserListDict objectForKey:@"UserCnt"]; 91 iUserCnt = [UserCnt intValue]; 92 NSLog(@"UserCnt=%zd", iUserCnt); 93 94 for ( int i = 0; i < iUserCnt; i++){ 95 96 str = [NSString stringWithFormat:@"%d", i]; 97 val = [[m_UserListDict objectForKey:str] objectForKey:@"name"]; 98 [self.hoge addObject:val]; 99 } 100 [listtable reloadData]; 101} 102 103- (void)didReceiveMemoryWarning 104{ 105 [super didReceiveMemoryWarning]; 106} 107 108@end 109

投稿2015/12/09 07:34

編集2015/12/10 05:40
fuzzball

総合スコア16731

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mm--_--mm

2015/12/09 07:42

ご回答いただきありがとうございます。 試してみましたが、更新されませんでした...値を取得し直すというのは, cellForRowAtIndexPath内で, cell.textLabel.text = [self.hoge objectAtIndex:indexPath.row]; というようにhogeの中身を表示しているのですが、hogeの中身を取得し直すタイミングで [tableView reloadData];をすればよろしいのでしょうか??
fuzzball

2015/12/09 07:55 編集

質問に書いてある「値を取得しなおして」というのは「cell.textLabel.text = [self.hoge objectAtIndex:indexPath.row]」のことなのでしょうか?そうであれば、この回答は的外れです。ただし、UITableViewを削除するのはやめましょう。
mm--_--mm

2015/12/09 07:58

値を取得しなおすというのはhogeの中身を変更して、変更したものをもう一度TableViewに表示したいということです...わかりました。削除しないようにします。
fuzzball

2015/12/09 08:01

その「hogeの中身を変更」した直後にreloadDataすればいいです。
fuzzball

2015/12/09 08:03

あ、それをやっても更新されなかったということなのでしょうか?
mm--_--mm

2015/12/09 08:07

やってみたのですが、更新されません... 更新する前は何も表示していない状態ですが、reloaddataをする前は何か一つでも値が入っていなければダメなのでしょうか?
fuzzball

2015/12/09 08:14

「何も表示していない」の意味が分かりません。テーブル(セル)が表示されていないのでしょうか?最初はhogeがカラなのですか?
mm--_--mm

2015/12/09 08:30

わかりにくくて申し訳ありません... はい。cellが表示されてない状態です。hogeの中身が空ということです。
fuzzball

2015/12/09 08:39 編集

hoge は NSMutableArray *hoge; numberOfRowsInSection は { return hoge.count; } だと仮定して、例えば、 [hoge addObject:@"hogehoge"]; [tableView reloadData]; としても何も表示されないでしょうか?
mm--_--mm

2015/12/09 09:24

試してみましたが、だめでした。 自作の関数内で処理を行っているので、[listtable reloaddata];というように記述しているのですがそれがいけないのでしょうか? [tableView reloaddata];だと自作関数内ではエラーが出てしまうので、listtableというUITableVIewを生成した際に自分でつけた名前の方できじゅつしているのですが、それが原因だったりするのでしょうか??
fuzzball

2015/12/09 12:04 編集

名前は問題ありません。が、「生成」ということはStoryboardは使ってないんですね。 なんとなくですが、TableView周りの設定が出来ていないような気がしてきました。 UITableViewDataSourceとかUITableViewDelegateは設定しているでしょうか?
fuzzball

2015/12/09 10:01

すみません、生成に関しては最初に書いてましたね。
fuzzball

2015/12/09 15:30 編集

TableViewが正常に動いているかどうか確かめるために、hogeに初期値を与えてみてはどうでしょうか?TableViewの生成をしているところで、 hoge = [NSMutableArray arrayWithObjects:@"A",@"B",@"C",nil]; などとして初期化し、テーブルが表示されるかどうか、表示されない場合、numberOfRowsInSection や cellForRowAtIndexPath が呼ばれているかどうかを確認してみて下さい。
mm--_--mm

2015/12/10 00:18

返信が遅くなってしまい、大変申し訳ありません... 試してみたところ、TableViewは正常に動いています。 やはり、更新するところがうまくいかないみたいです...
fuzzball

2015/12/10 00:19

その更新しているコードを書いて下さい。
mm--_--mm

2015/12/10 00:31

わかりました。 質問にコードを追記します。
mm--_--mm

2015/12/10 00:42

コードを追記しました。 よろしくお願いいたします。
fuzzball

2015/12/10 01:03

m_UserListDictは正しいフォーマットで値が入っていますか? NSLog(@"%@", m_UserListDict); としたときに、 { 0 = { name = zero; }; 1 = { name = one; }; 2 = { name = two; }; UserCnt = 3; } 正しければ、こんな感じで表示されるはずです。 あと、[listtable reloadData]; はforループの外に出して下さい。(中でも動きますが無駄なので)
mm--_--mm

2015/12/10 01:15

NSLogで確認した結果、記述していただいたような形でlogが出力されました。 わかりました。reloaddataをループの外に出します。 しかしまだ、更新はされません...
fuzzball

2015/12/10 01:48

サンプルコードを追加しました。自分のコードと比べてみてください。分からないことは聞いて下さい。
mm--_--mm

2015/12/10 01:50

ありがとうございます! 確認してみます!!
mm--_--mm

2015/12/10 05:04

試してみた結果、didSelectRowAtIndexPathの中ではrelsoaddataでテーブルの中身を更新することができました。しかし、自作の関数の中では更新することができません...これはUITableViewの仕様なんでしょうか?
fuzzball

2015/12/10 05:43

listtableを使用してDisplayListの中でreloadDataを行うようにしてみましたが、ちゃんとテーブルは更新されました。(回答修正済み) hirahasuさんのソースで、reloadDataの前に NSLog(@"listtable=%@", listtable); を入れてlisttableの値を確認してみて下さい。nilになっていないでしょうか?
mm--_--mm

2015/12/10 06:00

fuzzballのおっしゃる通り、listtableの中身がnullになっていました... reloadの前にlisttableをもう一度生成すれば良いのでしょうか?
fuzzball

2015/12/10 06:14 編集

listtableの、 ・定義部分(私のソースでは UITableView *listtable;) ・生成部分(私のソースでは listtable = [[UITableView alloc] initWithFrame:self.view.frame];) を教えて下さい。(定義部分は、どこで定義しているかも書いて下さい) その他、listtableに何か代入している箇所があればそれも教えて下さい。
mm--_--mm

2015/12/10 06:19

定義部分がヘッダファイル内で UITableView *listtable; 生成部分が listtable = [[UITableView alloc] initWithFrame:[self.view bounds]]; listtable.frame = CGRectMake(0, 0 , listView_width_windowsize, listView_height_windowsize * 0.8); listtable.delegate = self; listtable.dataSource = self; listtable.allowsMultipleSelection = YES; [self.view addSubview:listtable]; listView_width_windowsizeとlistView_height_windowsizeはfloat型で画面の大きさを[[UIScreen mainScreen] bounds];で取得し、計算してtableviewの大きさ決めています。 代入しているものが特にありません。
fuzzball

2015/12/10 06:47

現在、UITableViewは、viewDidLoadで生成したっきりで、削除や再生成は行っていないんですよね? DisplayListはどういうタイミングで呼んでいるのでしょうか?
mm--_--mm

2015/12/10 08:31

返信が遅くなってしまい申し訳ありません。はい、削除や再生性は行っておりません。 DisplayListはサーバと通信をして、新しい値を取得したら呼ぶようにしています。
fuzzball

2015/12/10 09:02 編集

DisplayListの先頭に、 NSLog(@"isMainThread=%@", NSThread.currentThread.isMainThread?@"YES":@"NO"); を入れてみて下さい。 もし NO なら、reloadDataの呼び出しを、 dispatch_async(dispatch_get_main_queue(), ^{ [listtable reloadData]; }); として、メインスレッドで実行するようにしてみて下さい。 (dispatch_async じゃなくて dispatch_sync の方が安全かも)
mm--_--mm

2015/12/10 09:17

NOだったのでdisplay listの中にdispatch_async(dispatch_get_main_queue(), ^{ [listtable reloadData]; });を記述したところ、numberOfRowsInSectionがよばれるようになりました。 しかし、cellForRowAtIndexPathがよばれません...
fuzzball

2015/12/10 09:25

hogeにデータは入っているでしょうか? numberOfRowsInSection が0を返していませんか?
mm--_--mm

2015/12/10 09:33

いえ、中身もありますし、returnの直前でログを出したら、0ではありませんでした...
fuzzball

2015/12/10 09:40

dispatch_async じゃなくて dispatch_sync でも同じでしょうか?
mm--_--mm

2015/12/10 09:46

すいません...先ほどのnumberOfRowsInSectionが呼ばれたのは勘違いで、実際は呼ばれてませんでした。呼ばれた時は試しに、値を取得しなおした時にtableviewを削除してもう一度生成するという方法を残したままで、そちらの処理を行った時に呼ばれたものでした。 なので、dispatch_asyncで呼ばれてないことになります。 わかりにくくて大変申し訳ありません... もう一度、ソースコードを綺麗にして明日、再チャレンジしてみることにします。
mm--_--mm

2015/12/11 05:08

色々と試してみた結果、reloaddataの直後にNSLog(@"listtable=%@", listtable);で確認してみたら、結果がlisttable = (null)と表示されました...releaseしたり、nilを代入したりもしていないのですが...
fuzzball

2015/12/11 05:56

直前はnilになっていないのでしょうか? あと、現在のコードを書いて下さい。(可能な限りコードを書いて下さい。コードがない状態では前に進みません)
mm--_--mm

2015/12/11 06:05

直前がnilではありませんでした... わかりました。 可能な限りでソースコードを追記いたします。
mm--_--mm

2015/12/11 06:45

コードを追記しました。 よろしくお願いいたします。
fuzzball

2015/12/11 07:38

listtableはどこで、どのように定義しているのでしょうか?
mm--_--mm

2015/12/11 07:47

hoge.hで@interface{ UITableView *listtable; } という様に定義してます。
fuzzball

2015/12/11 08:02

userlistarrayは hoge のことでしょうか?
fuzzball

2015/12/11 08:05

OnEnterMember の入り口と出口で listtable を表示してnilかどうかチェックして下さい。
mm--_--mm

2015/12/11 08:30

OnEnterMemberの入り口でnilになっていました...
fuzzball

2015/12/11 08:43

listtableを二箇所で定義してたりしませんかね? listtable生成(initFrameWith)の直後でlisttableの値を調べてみてください。 あと、 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; NSLog(@"[viewWillAppear] listtable=%@", listtable); } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; NSLog(@"[viewDidAppear] listtable=%@", listtable); } を追加して値を調べてみてください。
mm--_--mm

2015/12/11 08:50

viewWillAppear, viewDidAppearでは値は入ってました。 そして確認したところviewdidloadが二回呼ばれていました.... viewdidiloadでtableviewを生成しているのでfuzzballさんのおっしゃる通り二回生成していることになってますね...
fuzzball

2015/12/11 08:57

2回呼ばれててもnilにはならないような気がするのですが、まぁ何かおかしいのは確かですね。とりえあず、viewDidLoadの頭に、[super viewDidLoad]; を入れておいて下さい。
mm--_--mm

2015/12/11 09:06

はい。ありがとうございます。 追記しておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問