In my project, I create everything by code, like tableviews and cells. I have function to add cells.
The situation is: I have 10 object in my array, when program runs, the function (- (TodoTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath) runs through all 10 cells as I scroll, it does run 10 times of init... function in cell class. BUT, when I add a new cell in the program, then I found that this new cell never calls the init function for some reason. (The cell is being successfully created though... weird)
I use this part to add cell:
[self.tableView beginUpdates];
[self.todoItemList insertObject:newItem atIndex:toBeAddedIndex];
[self.tableView insertSections: [NSIndexSet indexSetWithIndex:toBeAddedIndex] withRowAnimation:UITableViewRowAnimationNone];
[self.tableView endUpdates];
and in this function:
- (TodoTableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Scroll to %ld", indexPath.section);
static NSString *cellIdentifier = #"TodoCell";
TodoTableViewCell *cell = (TodoTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
//If the current cell is dummycell, make it transparent
cell.todoItem = (TodoItem *)(self.todoItemList[indexPath.section]);
I don't know why, anyone please kindly help
----------UPDATE-----------------
NSString *cellIdentifier = [NSString stringWithFormat:#"TodoCell%ld",indexPath.section];
I found that if I change to this line. every time a add a new cell, it just calls the init function! but... if I do delete first and then add, problem still there, because this identifier has been created and used and stored I guess.
try to call:
[self.tableView insertRowsAtIndexPaths:<#(NSArray *)#> withRowAnimation:<#(UITableViewRowAnimation)#>]
Related
I've built a UITableView with reusable cells. At some point in my code I need access to a cell at a certain indexPath, so I call
MyCell *cell = (MyCell *) [tableView cellForRowAtIndexPath:indexPath];
Sometimes (usually the first time) this is called, it may take from 0.5 to 1 second.
What can cause this and how can I preven this?
I checked if
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
gets called as a reaction to cellForRowAtIndexpath: but it doesn't.
EDIT:
I just did another test and it also takes long if I call
[tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionMiddle];
Whatever gets called first, does have a lag of half a second
call [tableView reloadData] first, that may force the tableview to load its data. but still, if a cell is not visible on screen, it might not be loaded into memory.
I have been looking for answers for more than 2 days now. It just does not seem to solve.
Here is the code for cell
- (myCustomCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CustomData *m = (CustomData *)[self.allCustomData objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"customCell";
myCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell setBackgroundColor:[UIColor colorWithRed:255.0f green:255.0f blue:255.0f alpha:1]];
[cell.customTitle setText:m.name];
[cell.customStatus setText:#"Download"];
NSLog(#"%#",cell.customTitle.text);
return cell;
}
'cell' never returns nil. the log always prints the correct text. But the cells appear empty for some reason. On load I notice the first cell appears empty, and then on scroll, randomly 2-3 cells of any order become empty. The first cell often appears back on scroll.
I can't seem to understand what the issue could be.
UPDATE
Here are two screen shots. First one is how the table loads, I have put a background color just for debugging purpose. As you see the first cell is not showing up.
The one below is the second screenshot where I changed the orientation and scrolled a bit. You see how the first cell magically appears and the second goes away.
Also for debugging purpose, I added these two methods.
- (void)tableView:(UITableView *)tableView willDisplayCell:(dtEditionCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"Display %# %d %f",cell.editionTitle.text,indexPath.row,cell.frame.origin.x);
}
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(dtEditionCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{
NSLog(#"End Display %# %d %f",cell.editionTitle.text,indexPath.row,cell.frame.origin.x);
}
The log prints as expected. All cells are visible with correct text.
I don't know if it has something to do, but the method you show is not exactly the one used by the tableview. Here is how I do it with custom cells. I'm doing it a lot and works fine:
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TextCell *cell = [tableView dequeueReusableCellWithIdentifier:#"textCellId" forIndexPath:indexPath];
TextFieldContent *cellContent=[[self.dataSource objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
cell.titleLabel.text=cellContent.titleLabel;
cell.textField.placeholder=cellContent.placeHolder;
cell.textField.tag=cellContent.tag;
cell.textField.keyboardType=UIKeyboardTypeDecimalPad;
cell.textField.delegate=self;
return cell;
}
TextFieldContent is a cutom object that hold all the properties of the custom cell. For easier implementation.
I can't solve next problem.
I want to display 20 table cells, each contains a unique UICollectionView.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *package=[_packageList objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"package";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
UICollectionView *cellImageCollection=(UICollectionView *)[cell viewWithTag:9];
cellImageCollection.restorationIdentifier=[NSString stringWithFormat:#"%li", (long)indexPath.row, nil];
cellTracking.text=[NSString stringWithFormat:#"Row #%li",(long)indexPath.row];
return cell;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
int row=[collectionView.restorationIdentifier intValue];
return [[[_packages objectAtIndex:row] valueForKey:#"imageGallery"] count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
int row=[collectionView.restorationIdentifier intValue];
NSString *imgStrLink=[[[_packages objectAtIndex:row] valueForKey:#"imageGallery"] objectAtIndex:indexPath.row];
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"ImageID" forIndexPath:indexPath];
UIImageView *imageView=(UIImageView *)[cell viewWithTag:2];
imageView.image=....;
return cell;
}
Function tableView:cellForRowAtIndexPath: is called 20 times, but collectionView:numberOfItemsInSection: and collectionView:cellForItemAtIndexPath: only 4 times.
As seen in the screenshots UICollectionView is repeated every fourth line.
What is my fault?
I too faced this problem, the reason I got this problem was because both datasource and delegates for the tableview and collectionView were to the same parent viewcontroller.
It started working for me when I changed the datasource and delegate of the collectionView to another View say ParentView, and I added the collectionView to this ParentView and then finally added ParentView as conentView of the cell.
My previous answer which points to two nice tutorials was deleted by someone saying that I should include the essential parts of the content here(because the link may become invalid in future)...but I cannot do that as those are codes written by the tutorial owners and also the whole codes are essential too :), so now I am giving the link to the source code...
HorizontalCollectionViews
AFTabledCollectionView
-anoop
since Xcode 7 and iOS9 you can use UIStackView - best solution for design if collectionview or tableview are containing each other.
I am new in IOS6 dev. I got a problem with UITableView. My code below is to display Check Mark at the end of the row selected. But I received an error like "no visible #interface for UITableView declares the selector cellForRowAtIndexPath:". UITableView has cellForRowAtIndexPath method, but tableView cannot
show it. I don't know why. Please help.
Below is the code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; -----error line
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
The problem is "tableView" cannot recognize all the methods under UITableView. Some it knows such as "numberOfRowsInSection". I cannot figure out why.
The TableView itself does not implement this selector.
The full selector for this method is
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
and is from the protocol for the delegate. Your delegate (e.g. the viewController) has to implement this method. It is not recommended (and not easily possible) to get the cell object from the table.
Instead, change the underlying data and redraw your table with
[tableView reloadData];
Your problem is not in the code sample you include. Your problem rests elsewhere. We can't diagnose the problem on the basis of this one snippet. You'll have to share a more complete code sample with us.
Unrelated to your question, there is a subtle issue in your didSelectRowAtIndexPath. You should not just be updating the cellAccessoryType here. You really should be updating your model that backs your UI. This would be critical if the table had more rows than were visible at any given moment in time.
To illustrate the idea, let's assume your model was an array of objects with two properties, the title of the cell and whether the cell was selected or not.
Thus, your cellForRowAtIndexPath might look like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
RowData *rowObject = self.objects[indexPath.row];
cell.textLabel.text = rowObject.title;
if (rowObject.isSelected)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
And your didSelectRowAtIndexPath might look like:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
RowData *rowObject = self.objects[indexPath.row];
rowObject.selected = !rowObject.isSelected;
[tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
Again, your compiler warning/error is undoubtedly stems from some other problem in your source code, as your original code snippet is syntactically correct. I'm just trying to correct a different flaw in your didSelectRowAtIndexPath. In MVC programming, you really want to make sure you're updating your model (and then updating your view), not just updating the view.
But, to be clear, if you don't correct the error that is causing your current compiler warning/error, you'll probably just get another warning regardless of what you put into didSelectRowAtIndexPath. You have to identify why the compiler is balking at your current code.
I have a tableView that I have set allowsMultipleSelection to YES in storyboard.
EDIT
I was wrong about one thing... [tableView indexPathsForSelectedRows] does return a NSArray with 1 object in it during didSelectRowAtIndexPath.
However it does not work in cellForRowAtIndexPath after I reload the table so it will check which accessory (check mark or not) to apply.
In the original question I was trying to manually select the rows... Apparently that is handled by the tableView itself.. but somewhere along the way it is automatically deselecting my row as I never call deselectRowAtIndexPath on it...
Original Question:
For some reason when I set the cell to selected it does not change.
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
//cell does not update selected property to YES after this next line
cell.selected = YES;
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
I suppose I can keep track of the selected index paths myself... but I can swear I used a method that involved indexPathsForSelectedRows previously with success...
You cannot set the selected property directly
So instead of
cell.selected = YES;
Use
[tableView selectRowAtIndexPath:TheIndexPAth animated:YES scrollPosition:UITableViewScrollPositionBottom];
please post your all codes for this class in pastbean and put your link here we need more information,
and also try:
//in your interface
#interface YourClass (){
NSInteger _selectedIndex;
}
// cellForRowAtIndexPath: method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath
*)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// didSelectRowAtIndexPath: method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
_selectedIndex = indexPath.row;
[self.tableView reloadData];
}
Try [cell setSelected:YES animated:YES]
I'm pretty sure cell.selected is read only
A bit unfair since the question changed but.. for me.. the answer is either don't use
indexPathsForSelectedRows
or don't call
reloadTable
on your tableView.
I opted for the later, I decorated the accessory in didSelectRow and didDeselectRow instead of doing it on reload and just never reloading the table.
If someone can come up with a solution that involves both of the above, I will select that answer instead.