UITextField content gets lost when the view is scrolled off the screen - objective-c

I have a custom UITableViewCell prototype containing UITextField. I am adding new cells automatically when filling the UITextField in the last section. Where there are more sections that do not fit on one screen and I add another one, it gets filled with values from the first section and the first section inputs are emptied!
Screenshots:
Related code:
#implementation TMNewTripPeopleViewController
#synthesize sectionsCount = _sectionsCount;
#synthesize firstCellShowed = _firstCellShowed;
- (int) sectionsCount
{
if (_sectionsCount == 0) {
_sectionsCount = 1;
}
return _sectionsCount;
}
- (IBAction)inputChanged:(id)sender {
UITextField* input = (UITextField*) sender;
NSIndexPath* indexPathName = [NSIndexPath indexPathForRow:0 inSection:input.tag - 1];
UITableViewCell* cellName = [self.tableView cellForRowAtIndexPath:indexPathName];
if (input == [cellName viewWithTag:input.tag]) {
// last name input - add next section?
if (input.tag == self.sectionsCount) {
if (input.text.length > 0) {
self.sectionsCount++;
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:self.sectionsCount - 1] withRowAnimation:UITableViewRowAnimationTop];
}
}
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.sectionsCount;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 2;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = #"PersonName";
if (indexPath.row % 2 == 1) {
CellIdentifier = #"PersonEmail";
}
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UITextField* input = (UITextField*) [cell viewWithTag:indexPath.section + 1];
if (indexPath.row == 0 && indexPath.section == 0 && !self.firstCellShowed) {
[input becomeFirstResponder];
self.firstCellShowed = YES;
}
[cell viewWithTag:1].tag = indexPath.section + 1;
return cell;
}
#end

I'm not seeing tableView:willDisplayCell:forRowAtIndexPath: in your implementation. You generally set your cell's display values in this method.
When you use dequeueReusableCellWithIdentifier (and you almost always should) then your cells will be reused when the table view is scrolled. If you don't update their values in willDisplayCell then they will show whatever values they previously had before reuse (if any).

Related

How to load tableview based on button values with custom cells?

In my app I want to display a tableview(custom cells) based on button tags,when I am clicking on my 1st button it is showing empty table view and clicking on 2nd button it is showing 1st button data.
Here is my Code upto now i tried,
I am Calling my IBAction button in ViewDidLoad Method,
- (void)viewDidLoad
{
value1=0;
[self details:nil];
}
Here is my IBAction Method,
-(IBAction)details:(id)sender
{
value1 = 0;
detaiLine.hidden = NO;
rewardLine.hidden = YES;
[testTableView reloadData];
}
Here is my tableViewDataSource Methods,
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return responseArray.count;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (value1 == 0)
{
return 104;
}
if(value1 == 1)
{
return 180;
}
return 0;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (value1 == 0)
{
static NSString *cellId = #"Cell1";
ContestDetailCell1 * cell = (ContestDetailCell1 *)[contestTableView dequeueReusableCellWithIdentifier:cellId];
if (cell == nil)
{
NSArray *myNib;
myNib = [[NSBundle mainBundle]loadNibNamed:#"ContestDetailCell1" owner:self options:nil];
cell = [myNib lastObject];
}
}
if(value1 == 1)
{
static NSString *cellIdentifier = #"Cell2";
ContestDetailCell2 *cell = (ContestDetailCell2 *)[contestTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
NSArray *myNib;
myNib = [[NSBundle mainBundle]loadNibNamed:#"ContestDetailCell2" owner:self options:nil];
cell =[myNib objectAtIndex:0];
}
}
What is the problem in my code.
You are not assigning tag value to your value1 variable. Try this code,
-(IBAction)details:(id)sender
{
value1 = sender.tag;
detaiLine.hidden = NO;
rewardLine.hidden = YES;
[testTableView reloadData];
}
I think that you have not implemented your logic correctly. I didn't understand why you are calling IBAction from viewdidload.
Please find this as a work around,
add tag for each button in xib or using code.
In your IBAction Method get the tag and identify the button as follows,
-(IBAction)details:(id)sender
{
value1 = sender.tag;
\\your remaining code here
}
Using this value1 load your data in table view.
Hope this will help you. Please correct me if i'm wrong. :P

UISearchDisplayController Not Displaying Results in searchResultsTableView

I have a UISearchDisplayController properly connected to the header of a custom UITableView in IB. However, when I search for anything the searchResultsTableView only displays "No Results", and I cannot seem to find where the code is incorrect.
searchResults Property
- (NSMutableArray *)searchResults {
if (!_searchResults) {
_searchResults = [[NSMutableArray alloc] initWithCapacity:self.listingPreviews.count];
}
return _searchResults;
}
Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
NSInteger numberOfRows = 0;
if (tableView == self.tableView) {
numberOfRows = self.listingPreviews.count;
} else {
numberOfRows = self.searchResults.count;
}
return numberOfRows;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[ListingPreviewTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Search Bar Delegate Method
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSInteger searchTextLength = searchText.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchTextLength) && ([listingPreview.title rangeOfString:searchText].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
}
Just try this instead:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Listing";
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell.
if (tableView == self.tableView) {
cell.listingPreview = [self.listingPreviews objectAtIndex:indexPath.row];
} else {
NSLog([[self.searchResults objectAtIndex:indexPath.row] title]);
cell.listingPreview = [self.searchResults objectAtIndex:indexPath.row];
}
return cell;
}
Please note that the change was applied on:
ListingPreviewTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
This way you deque a Cell from your own tableView and not from the one created by UISearchDisplayController.
It seems that nothing in your code forces searchDisplayController to reload it's searchResultTableView.
The standard approach is to set UISearcDisplayController's delegate (note the protocol - UISearchDisplayDelegate) and implement – searchDisplayController:shouldReloadTableForSearchString:
- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
// perform your search here and update self.searchResults
NSInteger searchStringLength = searchString.length;
for (ListingPreview *listingPreview in self.listingPreviews) {
if ((listingPreview.title.length >= searchStringLength) && ([listingPreview.title rangeOfString:searchString].location != NSNotFound)) {
[self.searchResults addObject:listingPreview];
}
}
// returning YES will force searchResultController to reload search results table view
return YES;
}

Adding unknown number of rows to 'Static Cells' UITableView

I have a static table created in Interface Builder with 6 sections all with different amounts of rows.
I now want to add a 7th section with a varying number of rows.
First off, as soon as I uncomment the standard table delegate methods that are inserted by Xcode, I get a crash at self.tableView.tableHeaderView = containerView; where I have added a header to the table.
More importantly i'm getting a crash with the following code
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 7;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section==6) {
return 4;
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{/*
if (indexPath.section == 6) {
static NSString *CellIdentifier = #"cellWireless";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
return cell;
}*/
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
How do I correctly leave the existing sections as they are, but add an extra one with a few cells?
To add dynamic cells to a static cells table you have to override every UITableView delegate method that has an indexPath.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
-(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
.
-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
-(BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
return NO;
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleNone;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
int section = indexPath.section;
// if dynamic section make all rows the same height as row 0
if (section == self.dynamicSection) {
return [super tableView:tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
- (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
int section = indexPath.section;
// if dynamic section make all rows the same indentation level as row 0
if (section == self.dynamicSection) {
return [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
} else {
return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section == self.dynamicSection ) {
return [self.dataListArray count];
} else {
return [super tableView:tableView numberOfRowsInSection:section];
}
}
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
int section = indexPath.section;
int row = indexPath.row;
if (section == self.dynamicSection) {
// make dynamic row's cell
static NSString *CellIdentifier = #"Dynamic Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [self.dataListArray objectAtIndex:row];
return cell;
} else {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
}
Only once you have every method overridden will your table start to work. For any referencing the static section, just refer to [super].
Darren's answer gave me the idea for what worked for me, however I didn't have to go so far as to implement every single tableView delegate method. You really only need to override numberOfRowsInSection and cellForRowAtIndexPath.
First I defined a static table in Interface Builder with 4 sections, 2 to 4 cells per section. I wanted section 0, 2 and 3 to be static and look exactly as they did in IB, but I wanted section 1 to have a custom number of rows with a custom display in each cell based on an array of values I had.
In the view controller for the static table, override the number of cells returned for your dynamic section, but accept the defaults for all other sections (they'll fall back to the IB values). Do the same for cellForRowAtIndexPath and return the [super] implementation for all sections except section 1.
#implementation myMostlyStaticTableViewController
#synthesize myFancyArray;
- (NSInteger) tableView:(UITableView *) tableView numberOfRowsInSection:(NSInteger) section
{
if (section == 1)
return [myFancyArray count]; // the number of rows in section 1
else
return [super tableView:tableView numberOfRowsInSection:section];
}
- (UITableViewCell *) tableView:(UITableView *) tableView cellForRowAtIndexPath:(NSIndexPath *) indexPath
{
// for cells not in section 1, rely on the IB definition of the cell
if (indexPath.section != 1)
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
// configure a task status cell for section 1
MyCustomTableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"myCustomCell"];
if (!cell)
{
// create a cell
cell = [[MyCustomTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCustomCell"];
}
cell.myCustomLabel.text = [myFancyArray objectAtIndex:indexPath.row];
return cell;
}
#end
And of course you need a custom cell:
#implementation MyCustomTableViewCell
- (UITableViewCell *) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
// initialize cell and add observers
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (!self)
return self;
self.clipsToBounds = YES;
self.selectionStyle = UITableViewCellSelectionStyleNone;
// configure up some interesting display properties inside the cell
_label = [[UILabel alloc] initWithFrame:CGRectMake(20, 9, 147, 26)];
_label.font = [UIFont fontWithName:#"HelveticaNeue-Medium" size:17];
_label.textColor = [UIColor colorWithWhite:0.2 alpha:1];
[self.contentView addSubview:_label];
return self;
}
#end
I will post answer in Swift, but it should work in Objective-C as well.
In my experience, it was enough to override these methods in UITableViewController:
tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
tableView(tableView: UITableView, indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int
If you want to have custom table view cell in your table view, you need to crate subclass of UITableViewCell also with nib, and register it to your table view.
My whole controller looks like this:
var data = ["Ahoj", "Hola", "Hello"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.registerNib(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "reuseIdentifier")
}
// MARK: - Table view data source
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 1 {
return data.count
}
return super.tableView(tableView, numberOfRowsInSection: section)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.section == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! CustomCell
cell.titleLabel.text = data[indexPath.row]
return cell
}
return super.tableView(tableView, cellForRowAtIndexPath: indexPath)
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 44
}
override func tableView(tableView: UITableView, indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int {
return 0
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
if indexPath.section == 1 {
print(data[indexPath.row])
}
}
#IBAction func addItem() {
data.append("Item \(data.count)")
tableView.beginUpdates()
tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: data.count - 1, inSection: 1)], withRowAnimation: .Left)
tableView.endUpdates()
}
#IBAction func removeItem() {
if data.count > 0 {
data.removeLast()
tableView.beginUpdates()
tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: data.count, inSection: 1)], withRowAnimation: .Left)
tableView.endUpdates()
}
}
I thought I'd add an updated answer based on #Darren's excellent answer. Most of the delegate methods are not required. So, I just added the required ones. You can easily add a custom cell if you wish, even using a nib file. The image shows a static table with 3 sections. The final section is run time dynamic. This is extremely handy. This is working in ios7 BTW.
#define DYNAMIC_SECTION 2
#import "MyTableViewController.h"
#interface MyTableViewController ()
#property (strong, nonatomic)NSArray *myArray;
#end
#implementation MyTableViewController
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
_myArray = #[#"ONE", #"TWO", #"THREE", #"FOUR"];
}
return self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [super numberOfSectionsInTableView:tableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (section != DYNAMIC_SECTION) {
return [super tableView:tableView numberOfRowsInSection:section];
}
return [self.myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.section != DYNAMIC_SECTION) {
return [super tableView:tableView cellForRowAtIndexPath:indexPath];
}
static NSString *id = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:id];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:id];
}
cell.textLabel.text = self.myArray[indexPath.row];
return cell;
}
// required
-(NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath
{
int section = indexPath.section;
if (section == DYNAMIC_SECTION) {
return [super tableView:tableView indentationLevelForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:section]];
} else {
return [super tableView:tableView indentationLevelForRowAtIndexPath:indexPath];
}
}
// Not required
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
if (section != DYNAMIC_SECTION) {
return [super tableView:tableView titleForHeaderInSection:section];
}
return #"some title";
}
I think you are going to have to make your UITableView dynamic. Being that you have an "unknown"number of rows, you will most likely set the delegate method to something like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [someArray count];
}
I discovered something pretty interesting I think and it's more worth an answer than a "comment". I had this static tableView with dynamic rows working, and then it stopped working. The reason is simple. I previously had
[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]
and later decided I wanted/needed a Custom Cell that I'd design in my StoryBoard and only set outlets to my UITableView Subclass. So I used the other technique
[super tableView:tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:indexPath.section]];
The problem here seems to be that this cell gets reused and thus you'll only see one of the cells at a time. Sometime you'll even see none, they'll all be empty! If you scroll you'll see the other cells shortly appearing then disappearing (more like flickering!).
This drove me seriously nuts, until I realized what was (im)possible. Furthermore, do not try to do
[super.tableView dequeueReusableCellWithIdentifier:CellIdentifier]
because as mentioned by other people this always returns nil in a static tableView.
———
So I'm unsure what to do. I guess I'll use the "static prototyped" route, which consists of
Using a Prototype Table View with Cell Identifiers like "31" for Section 3 Row 1. I can then do something like
NSString *identifier = [NSString stringWithFormat:#"%d%d", indexPath.section, indexPath.row];
cell = [tableView dequeueReusableCellWithIdentifier:identifier];
Use Prototype Cells as well for the Headers. I use "Cell1-Header" for the Cell Identifier of the header of the section 1 and then have something like
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
NSString *identifier = [NSString stringWithFormat:#"Cell%d-Header", section];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
return cell.contentView;
}
The basic thing to take here is that you can always starts with a static tableView, but the moment where you realize you're gonna need something dynamic, swap it to Prototype (it will keep your rows although I don't remember what it does with the sections!) and use this KISS technique.
I think I found a better and easier solution, with "fantom" sections or rows in IB.
In case you know the maximum number of cells you would use in section 7(lets say 10), you should set the number of rows to 10, when you configure section 7 in IB.
You aren't forced to use all 10 rows in section, this can be set by
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section.
For example if you return 5 when section == 6(actually the 7th section), then only 5 rows will be displayed.
I admit that's not dynamic in the absolute sense of the word, but perhaps resolves most of the cases.

Display multiple custom cells in a UITableView?

I am using Xcode 4.2 on SnowLeopard, and my project is using storyboards. I am trying to implement a UITableView with 2 different custom cell types, sessionCelland infoCell. I can get the 2 types to appear within the same list, but now I have a new problem?! The sessionCell is displayed once, and then X number of infoCells are displayed after it - just as I wanted - except that the first infoCell is always overwritten by the sessionCell!
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.people count];
}
//inside cellForRowAtIndexPath
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
}
...
return cell;
I've tried to say return array count + 1, or even hardcoded return 7 (it fits my example) but both are incorrect!
myObject *person = [self.people objectAtIndex:indexPath.row];
Or does my problem lie in the above line? I've even tried indexPath.row+1...
Any help would be greatly appreciated!!
If I understand your question correctly, the first infoCell (second UITableView row) should display the first person object's data, right?
Then it seems you want:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *sessionCellID = #"sessionID";
static NSString *infoCellID = #"infoID";
if( indexPath.row == 0 ) {
SessionCellClass *cell = nil;
cell = (SessionCellClass *)[tableView dequeueReusableCellWithIdentifier:sessionCellID];
if( !cell ) {
// do something to create a new instance of cell
// either alloc/initWithStyle or load via UINib
}
// populate the cell with session model
return cell;
}
else {
InfoCellClass *cell = nil;
cell = (InfoCellClass *)[tableView dequeueReusableCellWithIdentifier:infoCellID];
if( !cell ) {
// do something to create a new instance of info cell
// either alloc/initWithStyle or load via UINib
// ...
// get the model object:
myObject *person = [[self people] objectAtIndex:indexPath.row - 1];
// populate the cell with that model object
// ...
return cell;
}
}
and you need to return [[self people] count] + 1 for the row count:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [[self people] count] + 1;
}
so that the n'th row shows the (n-1)th data.
if you look at the if else section it shows that the first row is an "sessionCell" and all other rows are "infoCells" what i think you want to do is make the first row an sessionCell, the second row an infoCell and all of the other rows peopleCells
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.people count] + 2; // Added two for sessionCell & infoCell
}
//inside cellForRowAtIndexPath
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
} else if (indexPath.row == 1 {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"personCell"];
Person *person = [self.people objectAtIndex:index.path.row - 2];
}
...
return cell;
Better yet, I would try to make two different sell sections, one for info and one for people
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return section == 0 ? 2 : self.people.count
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell = nil;
if (indexPath.section == 0) {
if(indexPath.row == 0) {
cell = [tableView dequeueReusableCellWithIdentifier:#"sessionCell"];
// configure session cell
} else if (indexPath.row == 1 {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
// configure info cell
}
} else {
cell = [tableView dequeueReusableCellWithIdentifier:#"infoCell"];
Person *person = [self.people objectAtIndexPath:indexPath.row];
// configure person cell
}
return cell;
}

How to pass changes in CustomCell data from didSelectRowAtIndexPath to heightForRowAtIndexPath

I'm trying to get the cell to collapse if it was already expanded. This code is expanding the row when clicked, but the bool cell.cell_expanded is always FALSE in heightForRowAtIndexPath. I've tried [tableView reloadData] but that didn't do the trick. Any idea?
I read that using heightForRowAtIndexPath can have a huge impact against performance, so if possible I would like to remove this method call. Is it possible to refactor this functionality elsewhere?
Here's what I've got:
CustomCell.h
#interface CustomCell : UITableViewCell
{
UIImageView *cell_arrow;
BOOL cell_expanded;
}
#property (nonatomic, strong) UIImageView *cell_arrow;
#property (nonatomic) BOOL cell_expanded;
FirstViewController.m
-(void)tableView:(UITableView *)tv didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedCellIndexPath = indexPath;
CustomCell *cell = (CustomCell *)[tv cellForRowAtIndexPath:indexPath];
NSString *arrow = nil;
if (cell.cell_expanded == TRUE) {
arrow = #"arrow_down.png";
cell.cell_expanded = FALSE;
}
else {
arrow = #"arrow_up.png";
cell.cell_expanded = TRUE;
}
cell.cell_arrow.image = [UIImage imageNamed:arrow];
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
-(CGFloat)tableView:(UITableView *)tv heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = (CustomCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
if (selectedCellIndexPath != nil) {
if (indexPath.row == selectedCellIndexPath.row) {
NSLog(#"cell_expanded = %d for row %i", cell.cell_expanded, indexPath.row);
CGSize theSize = [cell.cell_body.text sizeWithFont:[UIFont systemFontOfSize:12.0f] constrainedToSize:CGSizeMake(265.0f, 9999.0f) lineBreakMode:UILineBreakModeWordWrap];
if (cell.cell_expanded == TRUE) {
NSLog(#"open it");
return theSize.height + 16;
} else {
NSLog(#"close it");
return 44;
}
}
else {
return 44;
}
}
return 44;
}
Okay, a couple of things here:
1) Just call -reloadData instead of -end/beginUpdates.
2) You obviously didn't really understand how an UITableView works. UITableView reuses its cell. This means that you probably have like 5 cell instances. You should probably read the documents about it. To solve your problem you should save the expanded variable in the instance variable represented by the UITableView.