I have two ViewControllers:
An UIViewController with a "push" button, Another UIViewController with a tableView.
PushAction
- (IBAction)pushViewController:(id)sender {
NSArray *dataArr = #[#1,#2,#3,#4,#5];
NextViewController *nextViewController = [[NextViewController alloc] init];
[nextViewController setDataAndReload:dataArr];
[self.navigationController pushViewController:nextViewController animated:YES];
}
NextViewController.h
#interface NextViewController : UIViewController
- (void)setDataAndReload:(NSArray *)dataArr;
#end
NextViewController.m
#import "NextViewController.h"
#interface NextViewController () <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, strong) UITableView *tableView;
#end
#implementation NextViewController {
NSMutableArray *_arr;
}
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
[self.tableView reloadData];
}
- (void)setDataAndReload:(NSArray *)dataArr {
//[self loadViewIfNeeded];
_arr = [dataArr mutableCopy];
[self.tableView reloadData];
}
#pragma mark - data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _arr.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"CellIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.textLabel.text = [NSString stringWithFormat:#"Cell %#", _arr[indexPath.row]];
return cell;
}
#pragma mark - delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_arr removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
_tableView.delegate = self;
_tableView.dataSource = self;
_tableView.backgroundColor = [UIColor whiteColor];
}
return _tableView;
}
You have noticed that I called [self.tableView reloadData] before tableView was added to any view
Then, when I select any cell on the tableView, which will call [self.tableView reloadData] after selected, the tableView doesn't reload as expected.
After debugging with adding some breakpoints to tableView's dataSource methods, I found that numberOfRowsInSection: has been called correctly, but cellForRowAtIndexPath has not been called.
Then I think what cause the issue maybe is that setDataAndReload: call [self.tableView reloadData] before I added the tableView to viewController's view. So I added [self loadViewIfNeeded] and cellForRowAtIndexPath: was called correctly.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_arr removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
}
Thus, I wonder why cellForRowAtIndexPath can not be called after [self.tableView reloadData] in the tableView's delegate method didSelectRowAtIndexPath:.
I have found what cause cellForRowAtIndexPath can not be called after [self.tableView reloadData]
When I call [self.tableView reloadData] in setDataAndReload: It will call the lazy method of tableView.
As I used self.view.bounds to initialize the table view, an at the first time setDataAndReload: was called, the view has not been loaded. So it will load as below (while the tableView has not been created and returned)
:
loadView -> viewDidLoad -> [self.view addSubview:self.tableView] -> lazy method agian
-> return second tableView
-> self.tableView is the second tableView
-> second tableView is added to superView
-> return first tableView
-> self.tableView is the first tableView
Thus, the tableView that self.tableView finally pointed to, was never added to a superView!
When you are setting your in - (void)setDataAndReload:(NSArray *)dataArr, like you sad, the tableView is not even initialised and not part of the view hierarchy. so i would recommend to rename the method to - (void)setData:(NSArray *)dataArr and reload the tableView in viewDidLoad only.
So here is your the updated code:
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.tableView];
[self.tableView reloadData];
}
- (void)setDataAndReload:(NSArray *)dataArr {
_arr = [dataArr mutableCopy];
}
In didSelectRowAtIndexPath, if the tableView doesn't reloadData.You should check the caller self.tableView, it must have some problem. And you will find the self.tableView has change its pointer to a new tableView. Then you should check your getter method. In getter method, if we want to use some properties, we must be careful.Because sometimes we may be call the getter more than once,Why?. In your example, you try to get the bounds from self.view, and self.view will send message to -(void)loadView; ,which is the lifecycle method of VC, and -(void)loadView will send message to -(void)viewDidLoad; Now, -(void)viewDidLoad call the self.tableView again. Fortuantely, it doesn't cause a loop.
Related
I know that this question have been asked so many times but unfortunately non of the solutions in those questions worked for me.
Here are some of the things I tried:
making sure that numberOfSectionsInTableView is not returning 0
making sure that numberOfRowsInSection is not returning 0.
insuring that reloadData is being called on the main thread by using performSelectorOnMainThread as shown below:
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO]
setting the delegate :
self.tableView.dataSource = self; self.tableView.delegate = self;
making sure that tableview background color was changed.
making sure that tableview frame was adjustable.
But cellForRowAtIndexPath method never called
Please find the code:
UITableView *tableView;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320,480) style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView]
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = "test";
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 44;
}
If you have any idea what to do, please let me know.
Thanks
You created the tableView added it as subView to your ViewController's view in ViewDidLoad() which is fine :) But where are you calling reload Data on tableView buddy :)
Add
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320,480) style:UITableViewStylePlain];
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView]
[self.tableView reloadData];
}
It will work like a charm :)
just uninstall app from simulator and run again. sometimes its not work.
you have to delegate and datasource Protocol to view controller
#interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
First
#interface yourController ()<UITableViewDelegate,UITableViewDataSource>
Second
-(void)viewDidLoad {
[super viewDidLoad];
self.tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 320,480) style:UITableViewStylePlain];
[self reloadData]; //call your webservice here
self.tableView.delegate = self;
self.tableView.dataSource = self;
[self.view addSubview:self.tableView]
[self.tableView reloadData]; //most imp
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return yourArray.count; //your array which is get from webservice
}
I've been banging my head against the wall since I thought I tried everything possible on stackoverflow.
So currently I am creating a table like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
NSLog(#"CHECK IF THIS IS CALLED");
static NSString *CellIdentifer = #"CellIdentifier";
CBPeripheral *placeHolder;
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifer];
// Using a cell identifier will allow your app to reuse cells as they come and go from the screen.
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifer];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
placeHolder = _connectedPeripherals[indexPath.row];
cell.textLabel.text = placeHolder.name;
}
return cell;
}
and I am calling [self.tableView reloadData] from another function that I call. I know it's getting called in that function, but cellForRowAtIndexPath does not get called again.
I created a UITableView property on my .h file
#property (strong, nonatomic) UITableView *tableView;
And created the table like this
self.tableView = [[UITableView alloc] init];
self.tableView.rowHeight = 60.0f;
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[self.view addSubview:self.tableView];
[self.view addConstraints:#[ [HTConstraints leftAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints topAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints rightAlignView:self.tableView
toView:self.view
withSpacing:5],
[HTConstraints bottomAlignView:self.tableView
toView:self.view
withSpacing:5],
]];
So far what I've tried was making sure that [self.tableView reloadData] was being called in the Main thread. Making sure my sections did not return 0.
Edit
This is my reloadData function and is called in another class
by [[RootViewController sharedInstance] reloadData]; and the log prints when I call it.
- (void)reloadData {
NSLog(#"Reloading");
[self.tableView reloadData];
}
set a break point inside -(void)reloadData or try to append the count of your UITableView datasource in your NSLog.
Usually cellForRowAtIndexPath is not getting call because it does not have anything to display.
I saw, in your code you forgot to add your tableView as a subView to the controller.
Add below code after your tableView's initialization
[self.view addSubview:tableView];
So i created a custom cell (using the .xib file) and linked it using a custom controller class and I also didn't forget to write in the cell identifier. I also gave the same cell identifier in my table view controller prototype cell. In the custom cell controller class I just have an outlet to a text label in the .h file. Below is the code for my table view controller. When I run the app, the custom cells are not displayed but there are cells there because i can click on them (but they are just white). What am I doing wrong, why aren't the custom cells displaying?
If I use the default cells (not custom), then everything works fine. So the problem is that I'm not using my custom cells correctly somewhere.
#import "ListmaniaTableViewController.h"
#import "ListmaniaTableViewCell.h"
#interface ListmaniaTableViewController ()
#property (strong, nonatomic) NSMutableArray *tasks; //of task object
#end
#implementation ListmaniaTableViewController
- (void)viewDidLoad{
[super viewDidLoad];
task *task1 = [[task alloc] init];
task1.taskDescription = #"TASK 1";
[self.tasks addObject:task1];
task *task2 = [[task alloc] init];
task2.taskDescription = #"TASK 2";
[self.tasks addObject:task2];
task *task3 = [[task alloc] init];
task3.taskDescription = #"TASK 3";
[self.tasks addObject:task3];
}
- (NSMutableArray *)tasks{
if(!_tasks){
_tasks = [[NSMutableArray alloc] init];
}
return _tasks;
}
/*- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}*/
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"Add New Item"]) {
}
}
- (void)addNewTask:(task *)newTask{
[self.tasks addObject:newTask];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.tasks count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ListmaniaTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListmaniaCell" forIndexPath:indexPath];
if(!cell){
[tableView registerNib:[UINib nibWithNibName:#"ListmaniaTableViewCell" bundle:nil] forCellReuseIdentifier:#"ListmaniaCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"ListmaniaCell" forIndexPath:indexPath];
}
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(ListmaniaTableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
task *task = [self.tasks objectAtIndex:indexPath.row];
NSString *taskLabel = task.taskDescription;
cell.taskLabel.text = taskLabel;
}
#end
But the
[self.tableView registerNib:[UINib nibWithNibName:#"ListmaniaTableViewCell" bundle:nil] forCellReuseIdentifier:#"ListmaniaCell"];
in viewDidLoad:.
The code you have in tableView:willDisplayCell:forRowAtIndexPath: method should be in tableView:cellForRowAtIndexPath: method. Like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
ListmaniaTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListmaniaCell" forIndexPath:indexPath];
if(!cell){
[tableView registerNib:[UINib nibWithNibName:#"ListmaniaTableViewCell" bundle:nil] forCellReuseIdentifier:#"ListmaniaCell"];
cell = [tableView dequeueReusableCellWithIdentifier:#"ListmaniaCell" forIndexPath:indexPath];
}
task *task = [self.tasks objectAtIndex:indexPath.row];
NSString *taskLabel = task.taskDescription;
cell.taskLabel.text = taskLabel;
return cell;
}
I figured out the problem. I had an outlet in the custom cell that was doubly linked. I also moved the line below into viewdidload as suggested by #dasdom
[self.tableView registerNib:[UINib nibWithNibName:#"ListmaniaTableViewCell" bundle:nil] forCellReuseIdentifier:#"ListmaniaCell"];
I have a programmatically implemented tableView, in the grouped style.
All I am getting is the gray pinstripes when it should be populated. So it is loading, but not ... something...
What more is necessary?
If no more, then where else ought I look?
Also, how can I make the background color of the table the same as the cell's white color?
- (void)loadView {
[super loadView];
UITableView *view = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame style:UITableViewStyleGrouped];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth];
self.view = view;
[view reloadData];
}
Is viewDidLoad necessary?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
Thank you,
Morkrom
You have to provide your tableView with data.
For staters you'll need to define a dataSource. Its common to just use your viewController as the dataSource.
// in the .h find something similar and add <UITableViewDataSource>
#interface ViewController : UIViewController <UITableViewDataSource>
then when you make the tableView.
view.datasource = self;
Then you'll need to provide the data itself. Implement these methods:
#pragma mark - UITableView Datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 3;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
[cell.textLabel setText:#"A Cell"];
return cell;
}
Those methods will create 3 sections each with 3 rows. All the cells will just say A Cell. This is the basis for all tableViews. Just customize the data :)
You need to set dataSource and delegate properties for your table view so it will be able to pull data from them:
UITableView *view = ...
view.dataSource = self;
view.delegate = self;
have protocol in .h file and attach delegate and source with file owner
I am trying to create a UITableView application on Xcode 4.2. I just want each cells (ex. Cali) to push a new UIViewController when it's touched.
The issue I'm running into is whenever I press the cell it's not pushing the new view controller.
When I put a break point at the didSelectRowAtIndexPath method, I see 5 threads.
Here's my code:
#import <UIKit/UIKit.h>
#interface Adam : UITableViewController
{
NSMutableArray *states;
}
#end
#import "Adam.h"
#import "ViewController.h"
#implementation Adam
- (void)viewDidLoad
{
[super viewDidLoad];
states = [NSMutableArray arrayWithObjects:
#"cali",
#"ohio",
nil];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [states count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
UILabel *cellLabel = (UILabel *)[cell viewWithTag:1];
[cellLabel setText:[states objectAtIndex:indexPath.row]];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if ([[states objectAtIndex:indexPath.row] isEqual:#"cali"])
{
ViewController *cali = [[ViewController alloc] initWithNibName:#"cali" bundle:nil];
[self.navigationController pushViewController:cali animated:YES];
}
}
#end
First the TableViewCell has a textLabel property so you don't need to create your own label.
cell.textLabel.text= [states objectAtIndex:indexPath.row];
and is there a reason your deselecting the cell?Try deselecting it after you use the indexPath
And try:
if([states objectAtIndex:indexPath.row] isEqualToString:#"cali"]];){
}