Reloading the UITableView with new UITableViewCells - ios

Normally using the function reloaddata which just reload the data in the table, but what if I want to change to different type of UITableViewCell?
basically I like to dynamically invoke
-(UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
which allows different type of cells to be loaded in.

Have you tried to set an NSString property and then use that as the dequeueReusableCellWithIdentifier: parameter. Then a call to reloadData may swap out the cells?
Not tried this myself - just a thought.

Try
- (void)reloadRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
and pass in array of indexes you want to reload. It will call cellForRowAtIndexPath callback for you.

Define a typedef for your different cell types:
typedef enum {
kTableCellType1,
kTableCellType2
} TableCellType;
Then, define a class instance variable that uses your new TableCellType, e.g.
#interface MyTableViewController ()
{
TableCellType _tableCellType;
}
#end
In viewDidLoad, initialize this ivar:
- (void)viewDidLoad
{
[super viewDidLoad];
// do all of your other initialization
_tableCellType = kTableCellType1;
}
Then, your cellForRowAtIndexPath can check to see what cell type to use:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (_tableCellType == kTableCellType1)
{
// build first table cell type
}
else if (_tableCellType == kTableCellType2)
{
// build the other table cell type
}
}
Finally, when you want to change your cells, you change your ivar and then reload the data:
_tableCellType = kTableCellType2;
[self.tableView reloadData]; // or reloadRowsAtIndexPaths or reloadSections

Related

How to configure UITableView inside custom UITableViewCell in a Storyboard?

I have a layout in which I will have 2 UITableViews with custom cells. The second UITableView must be inside the first.
My question is: how to delegate second UITableView?
Can I delegate both to my ViewController? In that case it will use the same methods and I have to find out which UITableView is managed right now.
Or I have to delegate it inside custom UITableViewCell of the first UITableView?
Any recommendations are appreciated.
EDIT: I don't know how to implement solutions here, because I have Storyboard. Inside my current UIViewController I set delegate and dataSource of the first UITableView to my View Controller.
My problem is that I don't know how to set the same properties of the second Table View (which will be inside UITableViewCell). I can not set them to UITableViewCell (IB does not allow that).
Where and how to set then in the IB?
A far better solution would be to abstract the DataSource and Delegate implementations away from your view controller so that they can be personalised per tableview as required (please note that the code is taken from the objc.io article Lighter View Controllers.
E.g.
#implementation ArrayDataSource
- (id)itemAtIndexPath:(NSIndexPath*)indexPath {
return items[(NSUInteger)indexPath.row];
}
- (NSInteger)tableView:(UITableView*)tableView
numberOfRowsInSection:(NSInteger)section {
return items.count;
}
- (UITableViewCell*)tableView:(UITableView*)tableView
cellForRowAtIndexPath:(NSIndexPath*)indexPath {
id cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier
forIndexPath:indexPath];
id item = [self itemAtIndexPath:indexPath];
configureCellBlock(cell,item);
return cell;
}
#end
Then you could utilise it as follows:
void (^configureCell)(PhotoCell*, Photo*) = ^(PhotoCell* cell, Photo* photo) {
cell.label.text = photo.name;
};
photosArrayDataSource = [[ArrayDataSource alloc] initWithItems:photos
cellIdentifier:PhotoCellIdentifier
configureCellBlock:configureCell];
self.tableView.dataSource = photosArrayDataSource;
The same process could be followed with the UITableViewDelegate implementations to provide you with a very clean, separated and de-coupled code base. Your requirement for two tableviews will then be intrinsically easier to implement.
My answer is
For identifying two table view data source and delegate method is,better to set tag for the table views.
Set this below coding in your tableview delegates method.
if(tableView.tag==0)
{
}
else
{
}
Also you can vary this by assigning different name to these table view.
if(tableView==FirstTableView)
{
}
else
{
}
You just check table condition for every delegate method
Use this code to register custom cell.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if(tableView == self.yourFirstTable)
{
CustomCell *cell=[tableView dequeueReusableCellWithIdentifier:#"cellModifier"];
// your code
}
else
{
// second table cell code
}
return cell;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(tableView == self.yourFirstTable)
{
// first tableView number of row return
}
else
{
// second table number of row return
}
}
And create prototype cell in TableView
And Set CellReusableId like this way

UITableViewCell lazy instantiation cell

I have a UITableView called UserProductViewController and this table view used for two purpose "create and edit" some data. When user click "edit button" open this UserProductViewController edit mode and populate some data within cell from another method. I don't want to store all server-side values in property instead I was use Lazy instantiation cell. This approach sometimes makes trouble. To be clear here is my code this approach correct or not ? Could you please guide me correct way to do this?
Implementation Interface
#interface UserProductViewController()
#property(strong, nonatomic) MyCustomTableViewCell *myCustomCell;
#end
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
if(indexPath.row == 2) return self.myCustomCell;
...
}
- (MyCustomTableViewCell *)myCustomCell {
if(!_myCustomCell) {
_myCustomCell = [self.tabView dequeueReusableCellWithIdentifier:#"CustomIdentifier" forIndexPath:[self customIndexPath]];
}
return _myCustomCell;
}
- (NSIndexPath *)customIndexPath {
// 2 correspond to cellForRowAtIndexPath indexPath value.
return [NSIndexPath indexPathForRow:2 inSection:0];
}
Server side method I'm using that cell as a property like this:
- (void) getUserValues {
....
// getting server-side result
// completion block
self.myCustomCell.titleLabel = result.title;
}
Other question is what would happen if I don't want to use tableview dequeue system ?

Calling methods when UITableViewCell is pressed

I would like to call a method when a UITableViewCell is selected/tapped. I could do it easily with a static table view, but it requires a UITableViewController which is not good for me in this case, therefore I'm using a normal vc.
I have 10 specified methods like this:
- (void) methodOne {
NSLog(#"Do something");
}
- (void) methodTwo {
NSLog(#"Do something");
}
....
And I would like to call the methodOne when the first cell was tapped, call the methodTwo when the second cell was tapped and so on..
As a first step I set the numberOfRowsInSection to return 10 cells, but have no idea how could I connect the selected cells with the methods. Is there any quick way to do it? It would be a dirty solution to create 10 custom cells and set the every method manually for the custom cells, and there is no free place for it.
You can create an array of NSStrings with method names in the order they should be called from their corresponding UITableViewCells.
NSArray *selStringsArr = #[#"firstMethod", #"secondMethod", #"thirdMethod];
Then create a selector in tableView:didSelectRowAtIndexPath: from the strings array and call it using performSelector:.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *selString = selStringsArr[indexPath.row];
SEL selector = NSSelectorFromString(selString);
if ([self respondsToSelector:#selector(selector)]) {
[self performSelector:#selector(selector)];
}
}
Of course, there are some limitations to using performSelector: which you can read here.
You can use this method for whenever any cell is tapped on the table view
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger selectedRow = indexPath.row; //this is the number row that was selected
switch (selectedRow)
{
case 0:
[self methodOne];
break;
default:
break;
}
}
Use selectedRow to identify which row number was selected. If the first row was selected, selectedRow will be 0.
Don't forget to set the table view's delegate to your view controller. The view controller also has to conform to the UITableViewDelegate protocol.
#interface YourViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
As long as the table view has a data source and a delegate, it doesn't matter what kind of view controller it is on. All a UITableViewController really is is a UIViewController that already has a table view on it and is that table view's delegate and data source.

Set Text Properties of UITableViewCell object dynamically with an array - cellForRowAtIndexPath never called

I am a beginner in Objective-C & iPhone development.
I add dynamically cells in a TableView. I want to set labels's text properties with an array. I saw many tutorials, and I searched during several hours but labels are never filled.
My code is :
- (void)insertNewObject
{
for (NSInteger ic=0; ic<((pages.count)); ++ic) {
NSLog(#"%d", ic);
NSDictionary *monDico = pages[ic];
menu = [monDico objectForKey:#"Name"];
NSIndexPath *indexPathTable = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPathTable] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]]; // I try include & exclude : never call
}
[self.tableView reloadData];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = menu[indexPath.row];
NSLog(#"%#%#", #"Cell Label = ", cell.textLabel.text);
return cell;
}
Please note that insertNewObject method is called during viewDidLoad execution.
I use a breakpoint in the cellForRowAtIndexPath method : it never calls ! I try with :
explicit calling
forcing reloadData method
but did not work too.
Can you please tell me why ?
Thanks in advance.
If cellForRowAtIndexPath is not being called then most likely you have not set:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [menu count]; // indicates the number of rows in your table view
}
This method needs to return the number of rows you expect to render within your table view. The default is 0 = no rows. I'm assuming you want to show all the items in your menu array so simply return [menu count].
Check this: UITableViewDataSource Protocol Reference
If you want to access to textLabel property of your cell, then it must be style of: UITableViewCellStyleDefault. Or, if you use storyboard, then set Cell's style to Basic.
And, of course, make sure that you have set delegate and datasource properties of your tableView.
- (void)viewDidLoad
{
[super viewDidLoad];
//...
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
------------------EDIT------------------
If you're using UITableViewController, then no more need to set delegate and dataSource properties manually, because they will automatically set by UITableViewController when your view did load.
If cellForRowAtIndexPath: method still not being called, then make sure that following methods that you implemented, both returns value >0:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
and
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
Set a breakpoint before return and see returning values, or just NSLog them before returning.

UITableViewCell will disappear

I made an UITableView and contained some custom UITableViewCells, in the fist cell (named cell0 for example) there are some UITextFields for input, when I scroll the tableView, cell0 will disappear from the top of screen, then How can I get the UITextField's text in cell0?
cellForRowAtIndexPath will return nil.
The only method I found is a tableview delegate
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
[cell dealloc]
}
According to Apple Documentation about cellForRowAtIndexPath:, it returns "An object representing a cell of the table or nil if the cell is not visible or indexPath is out of range."
A UITableViewCell is a view, according to MVC Pattern. So I'd prefer maintaining a model object -- maybe it is as simple as a NSString instance -- to hold the text in the cell if I were you. You can observe UITextField's change by adding an observer of UITextFieldTextDidChangeNotification key to your controller.
- (void)textFieldDidChangeText:(NSNotification *)notification
{
// Assume your controller has a NSString (copy) property named "text".
self.text = [(UITextField *)[notification object] text]; // The notification's object property will return the UITextField instance who has posted the notification.
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Dequeue cell...
// ...
if (!cell)
{
// Init cell...
// ...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(textFieldDidChangeText:) name:UITextFieldTextDidChangeNotification object:yourTextField];
}
// Other code...
// ...
return cell;
}
Don't forget to remove the observer in your -dealloc.
As UITableViewCells leave the viewable area of the UITableView it is actually removed from the tableview and placed back into the reuse queue. If it is the selected for reuse it will be returned by dequeueReusableCellWithIdentifier:.
There is no callback for when a cell is removed from the view. However, prepareForReuse is called on the cell just before it is returned by dequeueReusableCellWithIdentifier:.
What are you ultimately trying to do?
You need to save the text somewhere (e.g. an NSArray) the moment it gets changed.
You can init textfield as instance variable.
look like:
.h
UITextField *textfiled;
.m
-(void)viewDidLoad
{
//init textfield
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//init cell...
[cell addSubview:textfield];
return cell;
}

Resources