Get UITableViewCell from indexPath not Working - ios

i was trying to updated the cell item while updating the height of the cell but its not working.
[_tblBillHistory beginUpdates];
[_tblBillHistory endUpdates];
these method i have used to updated the cell height
Err- > EXC_BAD_ACCESS(code=2,address=0x7fff5b4daf98)
this error message getting for cellForRowAtIndexPath method. Nslog also printing the selected row correctly. any idea??? thank you.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if((selectedPath!=nil ) & ([indexPath isEqual:selectedPath])) {
NSLog(#"%ld",indexPath.row);
UITableViewCell *tempCell = [_tblBillHistory cellForRowAtIndexPath:indexPath];
UIStackView *stkItems=(UIStackView *)[tempCell viewWithTag:8];
for(int i=0;i<20;i++)
{
UIButton *btn=[UIButton buttonWithType:UIButtonTypeSystem];
[btn setTitle:#"test button" forState:UIControlStateNormal];
[stkItems addArrangedSubview:btn];
}
return 700;
}
return 250;
}

I think this method is not good place to update cell's components.
If you want to add element to the cell you can create it at any other methods, for example:
- tableView:willDisplayCell:forRowAtIndexPath:
heightForRowAtIndexPath may be called many times (every reloadData or animation block).
You should divide your code, in heightForRowAtIndexPath you should only calculate height without request the cell (because the tableView not have cells in this method).
Adding or removing elements to the cell you can create in the didSelectMethod (but more better solution move this code to the cell or create a custom class for selected cell):
- tableView:didSelectRowAtIndexPath:

Please refer this
EXC_BAD_ACCESS in heightForRowAtIndexPath iOS

Try to replace following line
UITableViewCell *tempCell = [_tblBillHistory cellForRowAtIndexPath:indexPath];
with this one
UITableViewCell *tempCell = [self tableView:_tblBillHistory cellForRowAtIndexPath:indexPath];
This will stop recursive call as this is calling cellForRowAtIndexPath as a function not as data source of table view....

Related

Autolayout is breaking when UITableViewCell is scrolled especially for UIImageView

I need UITableViewCell in a dynamic height depends on the content length.
This is a prototype cell
And the content shows fine when first loaded like this
But when I scroll the UITableView, the cell's content breaks like this, especially for UIImageView.
In the implementation of the cell, I only used setImage and setText method.
What seems the problem? Or, is there another way to set each cell's height differently after viewDidLoad?
** Edit: this is my implementation of cellForRowAtIndexPath
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NotificationCell *cell = [tableView dequeueReusableCellWithIdentifier:#"notification"];
if(!cell) {
[tableView registerNib:[UINib nibWithNibName:#"NotificationCell" bundle:nil] forCellReuseIdentifier:#"notification"];
cell = [tableView dequeueReusableCellWithIdentifier:#"notification"];
}
[cell setContent:[notifications objectAtIndex:indexPath.row]];
[cell layoutIfNeeded];
return cell;
}
And setContent in NotificationCell.m has only setText and setImage
Because the tableView already has an imageView property and it is on the left side of the cell, you set the image to that imageView. You should rename the outlet of your custom imageView. So, it should be not called imageView, give the other name for it.

How to get a cell without calling cellForRowAtIndexPath in objective C iOS?

We can get a cell from:
UITableViewCell * cell = [self tableView:tableVie cellForRowAtIndexPath:indexPath]
but it will calling the method cellForRowAtIndexPath:
if I know the cell's tag or indexPath , it's there a way to get the specified cell without to calling cellForRowAtIndexPath:?
Add some reason why I can't call cellForRowAtIndexPath:indexPath
I want to get the cell in the method cellForHeightAtIndexPath to reset the height of each cell. :
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CommentsListResponseDataModel * model = self.liveCommentData[indexPath.row -1];
if (model.viewHeight > 0) {
return model.viewHeight;
} else {
if (model.parentComment) {
CommentParentCell * cc = (CommentParentCell *)cell;
return cc.viewHeight;
} else {
CommentSingleCell * cc = (CommentSingleCell *)cell;
return cc.viewHeight;
}
}
}
}
But this will become a dead loop because it all cellForRowAtIndexPath:indexPath and cellForRowAtIndexPath:indexPath will recall cellForHeightAtIndexPath:indexPath
As of my understanding, you are trying to get the cell object by calling UITableView datasource method. But when you try to do like that then it will be infinite loop call and you will never get the cell object. So in order to get cell object from UITableView, do the following steps.
Declare your UITableView as global to the your ViewController, something like UITableView *_tableView; or #IBOutlet weak UITableView *_tableView;
Then try to call the
//specify the item indexpath
NSIndexPath *_indexPath = [NSIndexPath indexPathForItem:3 inSection:1];
//now try to access cell object by passing cell indexPath
UITableViewCell *_cell = [_tableView cellForRowAtIndexPath:_indexPath];
It seems you want something unrelated to your original question - you want your table view cells to size automatically, depending on content.
What you need to do is:
1. add constraints to your cell - make sure it doesn't have a height constraint, but its content must have Top and Bottom constraints.
2. remove heightForRowAtIndexPath as it will not be necessary
3. set your table view row height to automatic
tableView.rowHeight = UITableViewAutomaticDimension
Now just setup your cell - resize its content to desired height and table cell will automatically be resized

Xcode remove cell with animation programmatically

Hi i have been searching around to find a way to remove a static cell with animation but i have not found a solution to the problem.
I have also tried: [tableView deleteRowsAtIndexPaths:[self.taskArray objectAtIndex:indexPath.row] withRowAnimation:UITableViewRowAnimationFade];
but no success.
You need to hide cell before it is shown, in UITableViewDelegate's tableView:willDisplayCell:forRowAtIndexPath: method. This is the last method in your control where you can manipulate the cell display. It does not remove the space the cell takes, so another thing you can try is to set cell row's height to 0 using the tableView:heightForRowAtIndexPath: method of the same protocol.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];
if (yourCell) {
return 0;
} else {
return [super tableView:tableView heightForRowAtIndexPath:indexPath];
}
}
As your tableview is static, you cannot use deleteRowsAtIndexPath. The best option would probably be to migrate your data into a dataSource method for the tableview.
If this is impossible, then this answer ("UITableView set to static cells. Is it possible to hide some of the cells programmatically?") gives that the best method is to use the third party library
StaticDataTableViewController 2.0 (https://github.com/xelvenone/StaticDataTableViewController).
Otherwise you have to use the somewhat hacky method of changing the row height to 0.

Set different height for two custom UITableViewCell

I have two custom UITableViewCell in my table view, that I can't resize properly. The problem is that in IB there is a row height option for the table view, that sets the same height for both cells. I can't just edit the height of the cells in IB, somewhy it doesn't works, the table view's row height overwrites it. I'm using static heights so I tried to set it based on the cell's type, but can't make it work. Is it possible that just my if statement is wrong or I done the whole thing wrong?
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *) indexPath {
InboxCellTableViewCell *cellMessage = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
InboxCell2TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell2" forIndexPath:indexPath];
if(cell) {
[cellMessage layoutIfNeeded];
return 200;
} else {
[cell layoutIfNeeded];
return 155;
}
}
You definitely can do this, and you will do it in -heightForRowAtIndexPath as you suspect.
Instead of attempting to load the cell as you are doing, you should instead use the IndexPath to determine what type of cell is there and then return the proper height for that cell type.
In your cellForRowAtIndexPath method you must have some logic that is already determining the cell type for a given IndexPath, as you return a varying type of Cell from that method already? That same logic can be used to return the appropriate height in the heightForRowAtIndexPath method.

Update label on UITableViewCell

I have a NSTimer that calls this method every fourth second:
- (void)timerDecrement
{
timerCount = timerCount-1;
[OtherViewControllerAccess updateTimeLeftLabel];
}
In the updateTimeLeftLabel in the other class:
- (void)updateTimeLeftLabel
{
int timeLeft = OtherClassAccess.timerCount;
UILabel *timeLeftLabel = [[UILabel alloc] initWithFrame:CGRectMake(200, 10, 120, 20)];
timeLeftLabel.text = [NSString stringWithFormat:#"Tid kvar: %ih", timeLeft];
[cell addSubview:timeLeftLabel];
}
Basically I want my app to update a label in a cell in the tableview with the current time left, but the above method doesn't do anything to the call. So my question is, how can I add this subview to the cell outside the cellForRowAtIndexPath:delegate method, and then make it update that label every time the method is called.
So my question is, how can I add this subview to the cell outside the
cellForRowAtIndexPath:delegate method, and then make it update that
label every time the method is called.
The answer is, don't add subviews to a table view cell outside of cellForRowAtIndexPath. The cells belong to the table view, and you absolutely, categorically, should NOT try to modify them. That's the table view's job.
Just as a small example of what's wrong with your code, you would be adding an ever-increasing number of label views to your table view cell, one every 1/4 second. That's bad.
Second point: Which cell is "cell"? A table view manages a whole table of cells. If the user scrolls, some cells are scrolled off-screen and replaced with different cells.
Instead, you should figure out which indexPath contains the cell with your data in it, change the data in your model, and tell your table view to update the cell at the appropriate indexPath. That will cause it to redraw with updated contents.
Here is how I did something similar. I created a custom UITableViewCell class that has a timestamp UILabel:
#property (nonatomic) UILabel *labelTimestamp;
In that cell's layoutSubviews, I update the label size based on its title.
- (void)layoutSubviews {
[super layoutSubviews];
[self.labelTimestamp sizeToFit];
...
}
I then have an NSTimer firing every minute in my UIViewController that update that label in every visible cell (you could adapt to update only one cell with a specific indexPath).
- (void)timerDidFire
{
NSArray *visibleCells = [self.tableView visibleCells];
for (GroupViewCell *cell in visibleCells) {
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
[cell.labelTimestamp setText:[self.groupController statusUpdateDateAtIndexPath:indexPath]];
[cell setNeedsLayout];
}
}
I would keep the set up of the cell's centralized in cellForRowAtIndexPath: method. You can keep using your NSTimer to call reloadRowsAtIndexPaths:withRowAnimation: with the indexes of the cell/cells you want to update and therefore cellForRowAtIndexPath: will be called again.
Why don't you put that value (which you want to display in the cell) in a variable and assign a UILabel that value. In your updateTimeLeftLabel just call [self.tableView reloadData].
You can reload whole table or some specific rows but that needs connection of datasource with your views . You have to change your dataset first and then you have to call
[self.tableview reloadData];
another method is that, after changing dataset call
[self.tableview reloadRowsAtIndexPaths:indexPath withAnimation:animation];
2nd method requires indexPath i.e. you know that which cell you need to edit .
My problem was same . In my project there were 2 TextFields and 1 label in each cell . Now depending on the values of 2 textfields, I have to show their multiplication in UILabel. and this is my code.
-(void)textFieldDidChange:(id)sender{
UITextField *_sender = (UITextField *)sender;
int tag = _sender.tag;
int row = tag / 3;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
((UILabel *)[[self.tableView cellForRowAtIndexPath:indexPath] viewWithTag:row * 3 + 2]).text = #"hello";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"here");
static NSString *CellIdentifier = #"procedureDetailsCell";
UITableViewCell *cell = (procedureCell *)[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if ( cell == nil ) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
[((procedureCell *)cell).Quantity setTag:indexPath.row + 0];
[((procedureCell *)cell).Quantity addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).Cost setTag:indexPath.row + 1];
[((procedureCell *)cell).Cost addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
[((procedureCell *)cell).total setTag:indexPath.row + 2];
return cell;
}
Logic is simple I have used Custom TableViewCell which contains 2 textfields and 1 label. when one of the two textfield's value is changed we are calling "textFieldDidChange" method which finds indexpath and then find UITableViewcell and then updates its lastview's text value, that is our UILabel. we have to give unique tag to each of our views .

Resources