Sorry but I've been stuck with this tricky problem. I have a tableView and once the user clicks it, a checkmark will appear and it is highlighted. However, when the user clicks it again, only the checkmark is gone and the highlight remains. On the third click, the checkmark is gone but I get the highlight. On the fourth click, the tableViewCell is finally cleared. I suspect this has something to do with my didSelectRowAtIndexPath method.
Here is my cellForRowAtIndexPath method.
What I basically do here is that I set the next labels and the checkmark if needed.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *ItemCellIdentifier = #"CellIdentifier";
SearchResultTableViewCell *tableCell =(SearchResultTableViewCell *)[tableView dequeueReusableCellWithIdentifier:ItemCellIdentifier];
//set text labels here
[tableCell.price setText:[NSString stringWithString:[priceList objectAtIndex:indexPath.row]]];
[tableCell.itemName setText:[NSString stringWithString:[itemNameList objectAtIndex:indexPath.row]]];
//set check mark and highlights.
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
tableCell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else{
tableCell.accessoryType = UITableViewCellAccessoryNone;
}
return tableCell;
}
Here is my didSelectRowAtIndexPath method. In this method, I toggle the checkMark value by switching it to 0 if it's 1 and vice versa, so when the [self.searchResults reloadData]; gets called, it knows which rows needs the checkmark and which ones do not. I also set the selected cell as selected or not because I save the index path for the selected rows so when I reload the table, I know which ones were selected and I can highlight it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
[checkList replaceObjectAtIndex:indexPath.row withObject:#"0"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO];
}
else{
[checkList replaceObjectAtIndex:indexPath.row withObject:#"1"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:YES];
}
NSArray *indexPaths = [self.searchResults indexPathsForSelectedRows];
//searchResults is my tableView
[self.searchResults reloadData];
for (NSIndexPath *indexPath in indexPaths) {
[self.searchResults selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
}
I have a feeling I'm doing the [[tableView cellForRowAtIndexPath:indexPath] setSelected:NO]; wrong. How do I properly access the tableViewCell from the tableView object and how do I properly set it as selected or not?
Thanks in advance
In your -didSelectRowAtIndexPath:, make sure to call [tableView deselectRowAtIndexPath:indexPath animated:YES].
Change value passed to animated as desired.
Just noticed, I wouldn't set selected manually in -didSelectRowAtIndexPath:. I'd set the cell selected or not only in the configuration of the cell. Take out your call to setSelected: and see if it works.
I think the
[self.searchResults reloadData];
maybe causing the table to be reloaded and then independently figure out if a cell is selected or not. I use this command all the time particularly when there are changes to the underlying array or data, and it maybe important to what you are doing when the row is selected. In which case you amy want to do this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSArray *indexPaths = [self.searchResults indexPathsForSelectedRows];
//searchResults is my tableView
[self.searchResults reloadData];
for (NSIndexPath *indexPath in indexPaths) {
[self.searchResults selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
if ([[checkList objectAtIndex:indexPath.row] integerValue] == 1){
[checkList replaceObjectAtIndex:indexPath.row withObject:#"0"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:NO];
}
else{
[checkList replaceObjectAtIndex:indexPath.row withObject:#"1"];
[[tableView cellForRowAtIndexPath:indexPath] setSelected:YES];
}
}
Related
Im using UITableView with checkboxes. In my cellForRowAtIndexPath method, I have set selected few cells as follows,
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(tableView == self.sideBarTbl){
cell.textLabel.text = [titleArray objectAtIndex:indexPath.row];
cell.tag = indexPath.row;
if(indexPath.row == 0){
[cell setSelected:true];
}else if(indexPath.row == 1){
[cell setSelected:true];
}else {
[cell setSelected:false];
}
}
In short, if the row is 0,1 then Im checking the checkboxes of the UITableView.
when the user clicks the row 0 or row 1, it should call didDeselectRowAtIndexPath since row 0 and row 1 checkmarks are already checked. But, it is always calling the didSelectRowAtIndexPath. no matter if the checkbox is checked or not, it always calls the didSelectRowAtIndexPath. How can I let it call didDeselectRowAtIndexPath when the checkbox is checked and call didSelectRowAtIndexPath when the checkbox is not checked?
didDeselectRowAtIndexPath method will only be called for cells which has been touched to select before. It's not related to the cell's selected property. If you want to do something for deselected cells, just record the selection manually in NSMutableArray with didSelectRowAtIndexPath method. Forget the didDeselectRowAtIndexPath. For reference: UITableView cell on double click should go to previous state
And an Objective-C example:
#interface SomeViewController : UIViewController<UITableViewDelegate> {
NSMutableArray *selectedIndexPaths;
}
#implementation SomeViewController
//......
- (void)viewDidLoad {
[super viewDidLoad];
selectedIndexPaths = [NSMutableArray array];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if ([selectedIndexPaths containsObject:indexPath]) {
[selectedIndexPaths removeObject:indexPath];
//Do something when deselecting.
}
else{
[selectedIndexPaths addObject:indexPath];
//Do something when selecting.
}
}
//......
#end
If the selection is single and exclusive, like a radiobox, just use single variable NSIndexPath *selectedIndexPath; to record selection in didSelectRowAtIndexPath, after handling the deselecting process for previous selected cell.
Use the following code in your cellForRowAtIndexPath instead of [cell setSelected:true];
[tableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionBottom];`
Use the following code when the user wants to deselect. Use it in your didDeselectRowAtIndexPath
[tableView deselectRowAtIndexPath:indexPath animated:YES];
Finally, you can get the selected indexes as follows,
-(void) getSelectedIndices
{
NSArray *indexPathArray = [tableView indexPathsForSelectedRows];
for(NSIndexPath *index in indexPathArray)
{
NSLog(#"Index: %ld",(long)index.row);
}
}
Revert back in case if you have any queries
I just saw a post about selecting multiple UITableView rows and based on which row/rows are selected, something will happen when you press a button linked to an IBAction.
It's an interesting question and I've played around with it, but now I'm stuck a bit.
As you can see I have a NSMutableArray called selectedIndexes, and the selected row/rows are shown in the console using a NSLog. This works fine:
- (IBAction)doSomethingWithSelectedRows:(id)sender {
for (NSNumber *data in self.selectedIndexes) {
NSLog(#"Row %ld is selected.", (long)[data integerValue] +1);
}
if (WHAT SHOULD BE PUT HERE?) {
}
//Do whatever you want here.
}
The question is, what should be put in that if statement above if you want this to happen:
if (row 2 and row 1 are selected {
//Run this code.
}
UPDATE:
Here's more code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[_selectedIndexes addObject:[NSNumber numberWithInteger:indexPath.row]];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[_selectedIndexes removeObject:[NSNumber numberWithInteger:indexPath.row]];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (IBAction)doSomethingWithRowsSelected:(id)sender {
for (NSNumber *data in self.selectedIndexes) {
NSLog(#"Row %ld is selected.", (long)[data integerValue] +1);
}
}
While you can use an array, as you do, an NSMutableIndexSet is a much better data structure for this task. It allows you to check whether a given index is in the set without having to iterate through all of the objects.
#property (strong,nonatomic) NSMutableIndexSet *selectedRows;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger row = indexPath.row;
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.selectedRows containsIndex:row]) {
[self.selectedRows removeIndex:row];
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[self.selectedRows addIndex:indexPath.row];
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
Now you can easily check if any two rows are selected:
- (IBAction)doSomethingWithRowsSelected:(id)sender {
if ([self.selectedRows containsIndex:1] && [self.selectedRows containsIndex:2]) {
// Do whatever
}
}
Also, don't forget to set the accessory type in cellForRowAtIndexPath based on [self.selectedRows containsIndex:indexPath.row] otherwise your checkmarks will be wrong when you scroll.
Here is what I will do,
1st, get the array of selected rows by using indexPathsForSelectedRows,
2nd, iterate the array to check if if indexPath.row is 1 or 2.
3rd, if your if statement's condition is true, then do ...
hey i have created a table view with multiple selection and checkmark accessory which users can tap on and select relevant rows in table... retailerid and retailernaem of individual selection will be stored in NSMutableDictionary and all dictionaries in return will be stored in NSMutableArray... i have done this till now
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
NSMutableDictionary *theDictionary = [[NSMutableDictionary alloc] init];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes addObject:theDictionary];
}
else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
NSLog(#"this is deselected row %#",[selectedIndexes objectAtIndex:indexPath.row]);
NSMutableDictionary *dictionary = [selectedIndexes objectAtIndex:indexPath.row];
[selectedIndexes removeObject:dictionary];
dictionary = nil;
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
now problem is in the else block... its not removing objects from randomly selected row...
for example if i select first row and then deselect the same it works fine but when i select the last row and then deselect the same app crash..
Since my other answer dealt with multiple sections, I will provide a simpler, single section answer here
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableIndexSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableIndexSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([self.selectStates containsIndex:[indexPath.row]) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeIndex:indexPath.row];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addIndex:indexPath.row];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsIndex:[indexPath.row]) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
If you need the ability to easily insert and delete rows then you can use an NSMutableSet instead of an NSIndexSet - just store the data source object. If you do allow deletion you need to make sure that the object is removed from the set, if necessary, when the row is deleted.
First, declare a property for your selection state -
#property (strong,nonatomic) NSMutableSet *selectStates;
Initialise it in viewDidLoad
self.selectStates=[NSMutableSet new];
The use it in didSelectRowAtIndexPath -
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
Brand *brand=(Brand *)[BrandsArray objectAtIndex:indexPath.row]; // Change "Brand" to the appropriate object class
if ([self.selectStates containsObject:brand) {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
[self.selectStates removeObject:brand];
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
[self.selectStates addObject:brand];
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
You will also need to check the selectedStates in cellForRowAtIndexPath to set the correct accessory when the cell is scrolled back into view. Just add the snippet -
if ([self.selectStates containsObject:brand) {
[cell setAccessoryType:UITableViewCellAccessoryNone];
} else {
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
}
The problem is the way you use the array.
Let's say you select the last element from a table view with 10 cells. Then the array size is 1, but when you select again the last row, [selectedIndexes objectAtIndex:indexPath.row]; is trying to access the element with index 9 in the array, which does not exist at the moment.
Try to implement something like this:
NSInteger ARRAY_INITIAL_SIZE = 100;
NSMutableArray *selectedIndexes = [NSMutableArray arrayWithCapacity:ARRAY_INITIAL_SIZE];
for (NSInteger i = 0; i < ARRAY_INITIAL_SIZE; ++i) {
selectedIndexes[i] = [NSNull null];
}
Make selectedIndexes to be a property in your View Controller class, and whenever you use it, put self.selectedIndexes instead.
In the didSelectRow: atIndexPath: method, the first line is recommended to be:
[tableView deselectRowAtIndexPath:indexPath animated:NO];
Then, write the code:
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
selectedCell.accessoryType = UITableViewCellAccessoryCheckmark;
NSMutableDictionary *theDictionary = [NSMutableDictionary dictionary];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerID"] objectAtIndex:indexPath.row] forKey:#"id"];
[theDictionary setObject:[[BrandsArray valueForKey:#"RetailerName"] objectAtIndex:indexPath.row] forKey:#"name"];
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:theDictionary];
} else {
selectedCell.accessoryType = UITableViewCellAccessoryNone;
[selectedIndexes replaceObjectAtIndex:indexPath.row withObject:[NSNull null]];
}
I hope it helps you. Let me know.
[Edited Post]
For practicing, I developing a contact app without any backend. I followed only one NSMutableArray for maintaining contacts which is displayed in a UITableView.
Objective;
Like to search a contact (Ex: Dad), user given a name in a textfield and touch up a button
In the button action, check if Dad contain in the Mutable array which one i followed.
If present, then it definitely present in the tableView as a row. So i want to put selectionStyle for that row.
If search text changes means (Ex: Mom), then revert previous selectionStyle and apply to the row(Mom).
If not present, label notify "Not Present" as text. (Done!).
IBAction:
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
[self tableView:myTable didSelectRowAtIndexPath:tempIndexPath]; //broke here
NSLog(#"Call Passed!");
}
}
didSelectRowAtIndexPath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
if(myTable.tag==5){
NSLog(#"called done!");
//Here i like to select that row and apply selectionStyle or favorite background color for that cell, idea?.
myTable.tag=0;
}
These are all just other part of my application. I sured that, Delegate and Datasource are connected properly.
You are calling didDeselectRowAtIndexPath and not didSelectRowAtIndexPath.
And I think you have not implemented didDeselectRowAtIndexPath in your class so thats the reason of crash.
and for your another question:
-(void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(cell.tag==100)
{
cell.contentView.backgroundColor=[UIColor grayColor];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell=[tblviw cellForRowAtIndexPath:indexPath];
cell.tag=100;
cell.contentView.backgroundColor=[UIColor grayColor];
}
Change this:
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSLog(#"TEmp index:%i",tempIndex);
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
NSLog(#"Temp IP:%#",tempIndexPath);
[self tableView:myTable didSelectRowAtIndexPath]; //broke here
NSLog(#"Call Passed!");
}
}
And for custom selection background do this in your cellForRowAtIndexPath.
UIView *customColorView = [[UIView alloc] init];
customColorView.backgroundColor = [UIColor colorWithRed:180/255.0
green:138/255.0
blue:171/255.0
alpha:0.5];
cell.selectedBackgroundView = customColorView;
Hope this helps.. :)
EDIT:
didSelectRowAtIndexPath is a delegate. It only get called when user interaction happens. I face a same problem some days ago. I did it in cellForRowAtIndexPath. For selecting a row do this:
if ([[myContactsArray objectAtIndex:indexPath.row] isEqualToString:txtForContactName.text]) {
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}
Please try to see my edited answer...
-(IBAction)actionSearchNameInTable:(id)sender{
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
NSInteger tempIndex=[myContactsArray indexOfObject:txtForContactName.text];
NSLog(#"TEmp index:%i",tempIndex);
NSIndexPath *tempIndexPath=[NSIndexPath indexPathForRow:tempIndex inSection:0];
NSLog(#"Temp IP:%#",tempIndexPath);
[self tableView:myTable didSelectRowAtIndexPath:tempIndexPath]; //Change here......
NSLog(#"Call Passed!");
}
}
Action for searching that if given text is present or not:
-(IBAction)actionSearchNameInTable:(id)sender{
[txtForContactName resignFirstResponder];
if([myContactsArray containsObject:txtForContactName.text]){
myTable.tag=5;
[myTable reloadData];
}
}
In cellForRowAtIndexPath:
//Better delegate to apply selection style
//Code after dequeue...
myTableCell.textLabel.text=[myContactsArray objectAtIndex:indexPath.row];
myTableCell.imageView.image=[myContactsPhotosArray objectAtIndex:0];
{
myTableCell.textLabel.text=[myContactsArray objectAtIndex:indexPath.row];
myTableCell.imageView.image=[myContactsPhotosArray objectAtIndex:0];
if(myTable.tag==5){
NSLog(#"Ready to apply selectionStyle");
if ([[myContactsArray objectAtIndex:indexPath.row] isEqualToString:txtForContactName.text]) {
[myTable selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
myTable.tag=0;
}
}
return myTableCell;
}
I have a UIViewController with a UITableView which has multiple accessory checkmark implemented into it. My problem is, when I click some cells in the tableview it gets checked but there will be some other cell also checked below. I can view it when I scroll down the tableview. I would only want the cell to be checked whichever the user is clicking and not the extra cells. Please let me know how can I do it. Thanks.
Here is the code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [someData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text=[self.someData objectAtIndex:indexPath.row];
cell.textLabel.font=[UIFont fontWithName:#"Times New Roman" size:11];
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
[cell.textLabel setNumberOfLines:2];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
if ([selectedCell accessoryType] == UITableViewCellAccessoryNone) {
[selectedCell setAccessoryType:UITableViewCellAccessoryCheckmark];
NSArray *arrayOfIndexPathsTableOne = [self.tableView indexPathsForSelectedRows];
for (int i = 0; i < [arrayOfIndexPathsTableOne count]; i++) {
NSIndexPath *indexPathImInterestedIn = [arrayOfIndexPathsTableOne objectAtIndex:i];
UITableViewCell *currentCell = [self.tableView cellForRowAtIndexPath:indexPathImInterestedIn];
[saveData addObject:[NSString stringWithFormat:#"%#", currentCell.textLabel.text]];
}
} else {
[selectedCell setAccessoryType:UITableViewCellAccessoryNone];
NSArray *arrayOfIndexPathsTableOne = [self.tableView indexPathsForSelectedRows];
for(int i = 0; i < [arrayOfIndexPathsTableOne count]; i++) {
NSIndexPath *indexPathImInterestedIn = [arrayOfIndexPathsTableOne objectAtIndex:i];
UITableViewCell *currentCell = [self.tableView cellForRowAtIndexPath:indexPathImInterestedIn];
[saveData removeObject:[NSString stringWithFormat:#"%#", currentCell.textLabel.text]];
}
}
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
This is a cell reuse problem.
To fix, ensure that each time you return a cell from cellForRowAtIndexPath: you always set the selection (checkmark) status. That means explicitly setting it true and false as appropriate.
There are only 2 things you need:
Disable multiple selection on your UITableView.
Implement setSelected:(BOOL)selected in your UITableViewCells and make it select/deselect the cell's sub-views (your checkmarks) accordingly.
When you select table you show check box on it but when you scroll and the cell desapeare and it goes to reusable pool after you scroll back the cell is taken from this pool and it doesn't remember the 'state'.
The solution is create NSMutableArray and in didSelectCellAtIndexPath: method add or remove the indexPath for that cell to the array and in cellForRowAtIndexPath: check this array and show/hide checkmark base on that table.
dont write this line in cell for row at index path
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
it must be in loadview or viewdidload