Trouble displaying tableview in iOS with dynamic cells - ios

I have an nslog that is successfully telling me that the information I will load into dynamic cells is there. However, I've discovered that my tableView is not loading the array "dogs" with object "dogs" at all because the nslog for name11Label is returning null despite the fact that there is a value for dogs in viewDidLoad. What would I need to do to initiate the tableView? (.h does have an iboutlet and a property(just to make sure) for my "tableView" and also has as well as and import for cell11.h)
.m file
-(void)viewDidLoad{
...
self.tableview.delegate = self;
...
}
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
if ( dogs != NULL ) {
return [dogs count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Cell11 *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell11"];
if (cell == nil)
{
cell = [[[Cell11 alloc] initWithFrame:CGRectZero reuseIdentifier:#"Cell11"] autorelease]; //I know that this method is depreciated, but it is not the source of this problem
}
NSDictionary *itemAtIndex =(NSDictionary *)[dogs objectAtIndex:indexPath.row];
cell.name11Label.text = [itemAtIndex objectForKey:#"dogs"];
NSLog(#"dogs array = %#", dogs); //returns correct information of the object dogs
NSLog(#"%#", cell.name11Label.text); //returning null even though "dogs" in viewDidLoad is showing a result;
return cell;
}
Cell11.h
#import <UIKit/UIKit.h>
#interface Cell11 : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *name11Label;
#end
Cell11.m
#import "Cell11.h"
#implementation Cell11
#synthesize name11Label;
#end

Change:
Cell11 *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell11"];
to
Cell11 *cell = [tv dequeueReusableCellWithIdentifier:#"Cell11"];
tableView is probably not hooked up right.
The nslog statement will never get called. Move it above:
NSLog(#"%#", cell.name11Label);
return cell;
Also you are initializing the cell with cgrect zero which won't display anything. Make sure it has a height and width that are expecting (e.g. CGRectMake(0.0f, 0.0f, 320.0f, 50.0f))
If the cell still doesn't display, are you calling reloadData on the tableview after the array dogs is set up?

Have you assigned your UITableView's "dataSource" property to the object with the UITableViewDataSource protocol (the above methods)?

First of all: The NSLog after the return will never be called.
NSLog(#"%#", cell.name11Label);
return cell;
}
Second: Control drag from you tableview of the interface builder to your class. And make sure the connection dataSource is properly connected.

Related

UILabel is nil in cellForRowAtIndexPath

I am using a Storyboard's prototype cell with a custom table cell class and the UILabels are nil in cellForRowAtIndexPath. Xcode's Identifier is correct, the cell is initialized, and the default UILabels (i.e. textLabel and detailTextLabel) are initialized but not the custom UILabels I added and setup IBOutlets for. A couple things I have tried:
I tried removing the registerClass calls in ViewDidLoad but that crashes since the cells need it to be initialized as the custom class GenericDetailCell.
viewWithTag returns nil
I tried iterating through all the subviews of UITableView to see if I was getting the wrong cell. The correct cell is getting returned by dequeueReusableCellWithIdentifier
Has anyone run into this?
#implementation PeopleGroupPickerViewController
{
NSArray *people;
NSArray *searchResults;
}
- (void)viewDidLoad
{
[super viewDidLoad];
people = [[DAL sharedInstance] getPeople:false];
[self.tableView registerClass:[GenericDetailCell class] forCellReuseIdentifier:#"PersonCell"];
[self.searchDisplayController.searchResultsTableView registerClass:[GenericDetailCell class] forCellReuseIdentifier:#"PersonCell"];
// stackoverflow.com/questions/5474529
[self.searchDisplayController setActive:YES];
[self.searchDisplayController.searchBar becomeFirstResponder];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(tableView == self.searchDisplayController.searchResultsTableView)
{
return 1;
}
else
{
return 1;
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView == self.searchDisplayController.searchResultsTableView)
{
return searchResults.count;
}
else
{
return people.count;
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
GenericDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:#"PersonCell" forIndexPath:indexPath];
Person_ *thisPerson;
if(tableView == self.searchDisplayController.searchResultsTableView)
{
thisPerson = (Person_ *) searchResults[indexPath.row];
NSLog(#"searchResultsTableView, %#",thisPerson.sName);
}
else
{
thisPerson = (Person_ *) people[indexPath.row];
NSLog(#"UITableView, %#",thisPerson.sName);
}
Person_ *thisSpouse = [[DAL sharedInstance] getSpouse:thisPerson People:people];
// cell.fieldName and cell.fieldValue are nil, cell is not nil
cell.fieldName.text = thisPerson.sName;
cell.fieldValue.text = thisSpouse.sName;
return cell;
}
GenericDetailCell.h:
#interface GenericDetailCell : UITableViewCell
#property (nonatomic,weak) IBOutlet UILabel *fieldName;
#property (nonatomic,weak) IBOutlet UILabel *fieldValue;
#end
Seems to me you might be attempting to combine a UITableViewCell predefined style (e.g. UITableViewCellStyleSubtitle) with a custom cell.
In your storyboard, if you have selected a predefined style for your Prototype cell, other controls will not be recognised.
To remedy this problem, in the Attribute Inspector for your Prototype UITableViewCell, select "Custom" type. Then add into the Prototype cell all the controls you require, including those needed to replace the default controls previously added automatically into the predefined cell type.

cellForRowAtIndexPath not being called - using tag to identify TableView

I've seen a number of people who have asked a similar thing, but answers to their questions are not the answers to mine.
1) I have created a single view application with an empty View Controller. In that, I dragged a new Table View (style Plain) with a single prototype cell of style Basic.
2) I am trying to learn about dynamically changing the behaviour of TableViews, so I have a mutable array called sectionRows, which will contain the number of rows per section. At the moment, a single section with a number of rows would be an achievement :)
3) In my ViewController.h I have set the delegates
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#end
I have also control-dragged from the TableView to the ViewController Yellow-Circle and set the datasource and delegate outlets.
4) In my ViewController.m, I have defined some global variables
#interface ViewController ()
{
NSMutableArray *sectionRows;
UITableView *myTableView;
}
The first is my data array (containing the number of rows per section and the second is a pointer to my TableView, which I have identified using a numeric View tag of '1'.
5) In my viewDidLoad, I initialize everything:
- (void)viewDidLoad
{
[super viewDidLoad];
myTableView = (UITableView *)[self.view viewWithTag:1];
sectionRows = [[NSMutableArray alloc] init]; // Create sectionarray
[sectionRows addObject:[NSNumber numberWithInteger:1]];
myTableView.dataSource = self;
myTableView.delegate = self;
[myTableView reloadData];
}
As you can see, I even make sure that I set the datasource and delegate again but this hasn't made any difference.
5) I have overloaded 3 methods.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
NSLog(#"Returning %li sections", sectionRows.count);
return sectionRows.count; // the size of the sectionRows array
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = #"xxx";
NSLog(#"Setting cell to %#", cell);
return cell;
}
Now, when I run this, I am getting NSLog returning confirmation that there is a single section and a single row:
2014-07-27 19:58:34.599 TableViewTests[12877:60b] Returning 1 sections
2014-07-27 19:58:34.600 TableViewTests[12877:60b] Returning 1 rows
However, as you can see cellForRowAtIndexPath is not being called.
None of the other things I have seen point to what I am doing wrong. I am doing what I thought I did successfully in another simple project (to learn) but I must be doing something else differently.
Any ideas what I am missing?
Thanks in advance
Jon
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return (NSInteger)[sectionRows objectAtIndex:section]; // the number referenced in the array...
}
This is incorrect. You cannot cast what you get from your array to an NSInteger. It's a pointer. Assuming you store NSNumbers into the array:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"Returning %# rows", [sectionRows objectAtIndex:section]);
return [[sectionRows objectAtIndex:section] integerValue]; // the number referenced in the array...
}

Data disappears from UITableView upon touch and release

UITableView data disappears on touch, as per screen shots below
The data loads correctly when the view is first loaded, like so.
On touching the screen and then releasing, the data disappears. (If I touch and hold, the data is still present.)
I set a breakpoint in the UITableView custom class and noticed that the methods within (such as cellForRowAtIndexPath:) are called when the view is loaded, but not after touch. The didSelectRowAtIndexPath: method is never called.
The code is very similar to the DateCell example. I'm trying to load a DatePicker (configured to show time only) when a cell is touched.
The relevant code is below, along with a screenshot of the IB delegate and datasource connections. Please let me know if you need any more info. I am new to iOS, so I would greatly appreciate as much detail of possible causes and solutions as possible.
#interface ScheduleTableViewController ()
#property (nonatomic, strong) NSArray *dataArray;
#property (nonatomic, strong) NSDateFormatter *timeFormatter;
#property (nonatomic, strong) NSIndexPath *timePickerIndexPath;
#property (assign) NSInteger pickerCellRowHeight;
#property (nonatomic, strong) IBOutlet UIDatePicker *pickerView;
#property (nonatomic, strong) IBOutlet UIBarButtonItem *doneButton; //to be used later for ios 6 compatability
#end
#implementation ScheduleTableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableDictionary *itemOne = [[#{ kPeriodKey : #" Tap a cell to change the survey time: " } mutableCopy ] autorelease];
NSMutableDictionary *itemTwo = [[#{ kPeriodKey : #"Morning Survey",
kTimeKey : [NSDate date] } mutableCopy] autorelease];
NSMutableDictionary *itemThree = [[#{ kPeriodKey : #"Evening Survey",
kTimeKey : [NSDate date] } mutableCopy] autorelease];
self.dataArray = #[itemOne, itemTwo, itemThree];
self.timeFormatter = [[[NSDateFormatter alloc] init] autorelease];
[self.timeFormatter setDateFormat:#"h:mm a"];
[self.timeFormatter setDateStyle:NSDateFormatterNoStyle];
[self.timeFormatter setTimeStyle:NSDateFormatterShortStyle];
UITableViewCell *pickerViewCellToCheck = [self.tableView dequeueReusableCellWithIdentifier:kTimePickerID];
self.pickerCellRowHeight = pickerViewCellToCheck.frame.size.height;
[self.tableView setDelegate:self];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.reuseIdentifier == kDayPeriodAndTimeCellID) {
// todo check for ios < 7.0
[self displayInlineTimePickerForRowAtIndexPath:indexPath];
} else {
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = nil;
NSString *cellID = kDayPeriodAndTimeCellID;
if ([self indexPathHasPicker:indexPath]) {
cellID = kTimePickerID;
}
cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (indexPath.row == 0) {
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
NSInteger modelRow = indexPath.row;
if (self.timePickerIndexPath != nil && self.timePickerIndexPath.row < indexPath.row) {
modelRow--;
}
NSDictionary *itemData = self.dataArray[modelRow];
if ([cellID isEqualToString:kDayPeriodAndTimeCellID]) {
cell.textLabel.text = [itemData valueForKey:kPeriodKey];
cell.detailTextLabel.text = [self.timeFormatter stringFromDate:[itemData valueForKey:kPeriodKey]];
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if ([self hasInlineTimePicker]) {
NSInteger numRows = self.dataArray.count;
return ++numRows;
}
return self.dataArray.count;
}
I am adding to an existing application, so all of the existing UI is implemented in XIB files, however this table is implemented in a storyboard. Here is a screen shot of the delegate and datasource outlet connections.
I think you need to provide a little more context here, but I have a guess. A UITableView needs a UITableViewDataSource to tell it what data should be in the cells. Do you hook that up in the XIB? If so, I don't see any of the methods implemented in your ScheduleTableViewController.
Make sure you implement that protocol and specifically the method "tableView:cellForRowAtIndexPath:". This is where you actually configure the cells that appear in the table view.
It sounds like you created the prototype table cells in InterfaceBuilder. For each prototype cell you created, make sure you set it's cell identifier in the properties inspector. Then use this cell identifier to identify which cell you are configuring in the call to "tableView:cellForRowAtIndexPath:".
Have you tried setting your table data with the functions
numberOfSectionsInTableView:tableView
tableView:tableView numberOfRowsInSection:section
I had the similar issue (in swift). It was solved by putting an instance variable to my tableViewManager responsible for presenting tableView. Initially an instance of it was created and called from button action method. So it was deallocated by ARC and consequently tableView had disappeared when I was trying to interact with it.
Inspired by: iOS TableViewController in PopOver disappears after touching tableview
In my case I was using SwipeMenuViewController (https://github.com/yysskk/SwipeMenuViewController)
and in each page there was a table view.
When I click the tabs it's switch the tables with no problem. but when I touched the table the data disappeared although
the table exists (I used background colours to check)
My solution was to hold a reference to the UIViewControllers return from the SwipeMenuViewController method:
func swipeMenuView(_ swipeMenuView: SwipeMenuView, viewControllerForPageAt index: Int) -> UIViewController {
viewControllers[index.description] = baseContactsTableViewController
return baseContactsTableViewController
}

UITextField inside UITableViewCell - method for preventing text reset

I have a UITableView tall enough that it necessitates scrolling. The top-most cell in the table contains a UITextField for the user to enter some text.
The standard way to build this might be to create and add the text field and add it to a cell created or recycled in cellFOrRowAtIndexPath: However, this constant re-creation means that the text entered in the field is erased when the cell is scrolled out and back into view.
The solutions I've found so far suggest using UITextField delegation to track the text as it changes and store it in an iVar or property. I would like to know why this is recommended instead of the simpler approach I am using:
I am creating the UITextField in the init method of the UITableViewController and immediately storing it in a property. In cellFOrROwAtIndexPath I am simply adding the pre-existing field instead of initializing a new one. The cell itself can be recycled without issue, but because I am always using the one and only UITextField, the content is maintained.
Is this a reasonable approach? What might go wrong? Any improvements (perhaps I could still create the field in cellForRowAtIndexPath but first check if the property is nil?)
When you are creating cells in cellForRowAtIndexPath you have to use one reusable identifier for that first cell (ie. cellId1) and another for the rest (ie. cellId2).
If you do this, when you get the cell for the first element by calling [tableView dequeueReusableCellWithIdentifier:#"cellId1"] you will always get the same Object and will not be reused by other cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = nil;
// Only for first row
if (indexPath.row == 0) {
static NSString *cellId1 = #"cellId1";
cell = [tableView dequeueReusableCellWithIdentifier:cellId1];
if (cell == nil) {
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId1];
}
}
else {
static NSString *cellId2 = #"cellId2";
cell = [tableView cellId2];
if (cell == nil) {
cell = [[MyCell alloc] initWithStyle:UITableViewCellStyleDefault cellId2];
}
}
// do whatever
return cell;
}
If there is only one UITextField, then I agree that your approach would be better/same as compared to using UITextField delegation (I think).
However, let us assume that you want to "expand" your view so that there are about 7-8 or more TextFields now. Then if you go about using your approach, then the problem will be that you will be storing 7-8 or more TextFields in memory and maintaining them.
In such a situation, a better approach would be that you create only that number of textfields as visible on screen. Then you create a dictionary which would maintain the content present in the textfield (which you can get by UITextFieldDelegate methods). This way, the same textfield can be used when the cell is reused. Only the values will change and will be dictated by the values in the dictionary.
On a sidenote, do minimal creation in cellForRowAtIndexPath as that is called during every table scroll and so creating a textField in cellForRowAtIndexPath can be expensive.
#import "ViewController.h"
#import "TxtFieldCell.h"
#define NUMBER_OF_ROWS 26
#interface ViewController ()<UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tablView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tablView.datasource = self; //set textfield delegate in storyboard
textFieldValuesArray = [[NSMutableArray alloc] init];
for(int i=0; i<NUMBER_OF_ROWS; i++){
[textFieldValuesArray addObject:#""];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark - TableView Datasource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TxtFieldCell *cell = [tableView dequeueReusableCellWithIdentifier:#"TxtFieldCellId" forIndexPath:indexPath];
cell.txtField.tag = indexPath.row;
if (textFieldValuesArray.count > 0) {
NSString *strText = [textFieldValuesArray objectAtIndex:indexPath.row];
cell.txtField.text = strText;
}
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return NUMBER_OF_ROWS;
}
#pragma mark - TextField Delegate
- (void)textFieldDidEndEditing:(UITextField *)textField {
[textFieldValuesArray replaceObjectAtIndex:textField.tag withObject:textField.text];
}

heightForRowAtIndexPath is never called though delegate is set

I already searched Google the entire day but I just can't figure out a solution for this one.
I am trying to implement a table view with custom cells in my iOS App. I'm using custom cells that display different images and Labels. Everything is working fine except that the Cells are too large for the table view. I know that I need to implement the heightForRowAtIndexPath method but it is never called.
I've tried setting the delegate for the TableView in the nib file and in the ShowPostsViewController in the code but nothing helps. I expect that the problem probably is that the dataSource is set but not the delegate. I can't understand why though.
Every solution I found until now says that the delegate is not set correctly. However, I'm pretty sure it is in my case?!
I'm grateful for any help. Here's my code:
ShowPostsViewController.h
#interface ShowPostsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property (nonatomic, strong) IBOutlet UITableView *postsTableView;
#end
And ShowPostsViewController.m
#implementation ShowPostsViewController
#synthesize postsTableView;
- (void)viewDidLoad
{
[super viewDidLoad];
self.postsTableView.delegate = self;
self.postsTableView.dataSource = self;
NSLog(#"Delegate set");
[postsTableView beginUpdates];
NSMutableArray *tempArray = [[NSMutableArray alloc] init];
for(int i=0; i<8; i++){
[tempArray addObject: [NSIndexPath indexPathForRow:i inSection:0]];
}
[postsTableView insertRowsAtIndexPaths:tempArray withRowAnimation:UITableViewRowAnimationAutomatic];
NSLog(#"Updates Called");
[postsTableView endUpdates];
[postsTableView reloadData];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 8;
}
//PostTableViewCell is my custom Cell that I want to display
-(PostTableViewCell*)tableView: (UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
PostTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if(!cell){
cell = [[PostTableViewCell alloc]initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:#"cell"];
}
return cell;
}
//This method is not called for some reason
-(CGFloat)tableview: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath{
NSLog(#"Height Method called");
CGFloat returnValue = 1000;
return returnValue;
}
//This method is called
-(NSInteger) numberOfSectionsInTableView:(UITableView *)tableView{
NSLog(#"Section Number called");
return 1;
}
#end
I've also got the tableView linked to the ShowPostsViewController in the Interface Builder.
Thank you all for your great support.
You are going to kick yourself for this mistake. You have implemented the method:
-(CGFloat)tableview: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath
But the actual delegate method should be:
-(CGFloat)tableView: (UITableView*)tableView heightForRowAtIndexPath: (NSIndexPath*) indexPath
The only difference is the capital V in tableView. You have a lowercase v by mistake.
Try to make use of as much code completion in Xcode as you can to help avoid these types of mistakes.

Resources