UITableViewCell editing one cell changes another cell controls after 8 rows - ios

now I a beginner in IOS programming, I created a view and placed a tableview inside it, then I created a xib with the template I want to use for the tablecell and made a class for that call. the table cell has a label (set on load of the cell), a switch and a textfield.
The table loads fine, with the labels showing the correct text they should, there is 12 rows that are loaded from the database. sqLite.
the problem:
when I edit the textfield in row 1, the text field in row 9 is edited, and vise versa. when I edit in row 2, row 10 is edited! upto row 4,12 not only the text field, but also toggling the switch toggles.
Some code:
AlertViewController.h
#property (weak, nonatomic) IBOutlet UITableView *table;
AlertViewController.m
#synthesize table;
static NSString *alertCellID=#"AlertViewCell";
----some code here ----
-(void)ViewDidLoad
{
---some code here----
self.table.delegate=self;
self.table.dataSource=self;
if(managedObjectContext==nil)
{
id appDelegate=(id)[[UIApplication sharedApplication] delegate];
managedObjectContext=[appDelegate managedObjectContext];
}
[self loadCategories];
[table registerNib:[UINib nibWithNibName:#"AlertViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:alertCellID];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [arrCategories count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Category *cat=[arrCategories objectAtIndex:indexPath.row];
AlertViewCell *cell = [tableView dequeueReusableCellWithIdentifier:alertCellID];
UILabel *lblGroupName=(UILabel *)[cell viewWithTag:101];
lblGroupName.text=cat.nameEn;
UITextField *txtHours=(UITextField *)[cell viewWithTag:103];
txtHours.delegate=self;
return cell;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
Edit:
I dont know is it related to the scroll size fitting 8 records? and how to overcome that?

Ok I solved it as follows:
First the issue was because i m using dequeuereusablecellwithidentifier, which seems to return the same reference every x number of rows, where x is the number of rows that appear on the screen without scrolling, so this made cell 1=cell 9, cell 2=cell 10 and so on.
so to solve it, I had to make the identifier unique, and to solve the issue that the identifier was used to load the registered nib, I had to register the nib with this unique identifier names.. here is the changes:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier=[NSString stringWithFormat:#"%#%d",alertCellID,indexPath.row];
[table registerNib:[UINib nibWithNibName:#"AlertViewCell" bundle:[NSBundle mainBundle]] forCellReuseIdentifier:identifier];
Category *cat=[arrCategories objectAtIndex:indexPath.row];
AlertViewCell *cell = (AlertViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath];
if(!cell)
{
NSArray *topLevelObjects=[[NSBundle mainBundle] loadNibNamed:#"AlertViewCell" owner:self options:nil];
cell=[topLevelObjects objectAtIndex:0];
}
UILabel *lblGroupName=(UILabel *)[cell viewWithTag:101];
lblGroupName.text=cat.nameEn;
UITextField *txtHours=(UITextField *)[cell viewWithTag:103];
txtHours.delegate=self;
return cell;
}

Related

Create UITableView in a VC with 2 Custom Columns UITableViewCell, load custom data from an array to the cell, Objective C

How to create the following UITableView in a VC with 2 Columns? As UITableView only has one column. Is it possible to do it in StoryBoard? How to add shadow, round the corners and add the blurish borders as in the pic? All help or pointer is greatly appreciated.
Edited
How to set the 2 columns in Objective C? I can't find any help over the net especially for objective C. I think both the columns are UILabel.
As for the rows, do I need to set the Prototype Cell to 3 at Story Board?
The 1st column will have static values: NAME, DATE OF BIRTH, LOCATION. The 2nd column will fetch data from an array [John Doe, 06.03.1991, New York]
Do I create a loop to insert the data?
ANSWER
I followed this link and managed to create 2 custom UILabel columns and insert the columns from NSMutableArray
I can't get the following suggested answer to work, the answer suggested that we create an Empty User Interface and then add a Table View Cell and associate it back to the VC. I can't get it to work.
Mine was just creating the 2 labels at the prototype cell at the TableView and then following the link above.
create a customcell and put 7 UILabel first 4 label gives name basic setting,NAME,DOB,LOCATION than remain 3 label set blank and give tham property in cell.h file
#pragma mark tableview delegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [yourdataarray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"yourcustomcellname"];
if (cell == nil) {
// Load the top-level objects from the custom cell XIB.
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"yourcustomcellname" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
id object = [yourdataarray objectAtIndex:indexPath.row];
if ([object isKindOfClass:[NSMutableArray class]]) {
NSMutableArray *Array = (NSMutableArray *)object;
//your cell property use here for fatch like below
[cell.NAME setText:[NSString stringWithFormat:#"%#",[Array objectAtIndex:i]]];//here i=which index your array contain name data
}
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return yourcustomcellheight;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
}
refer this tutorial for customcell
https://www.appcoda.com/customize-table-view-cells-for-uitableview/
You need to use custom UITableViewCell, it seems the first column is just a label and the second column is a textfield.
In order to add boundary and add corner
myTableViewCell.contentView.layer.borderColor = [[UIColor grayColor] CGColor];
myTableViewCell.contentView.layer.borderWidth = 1;
myTableViewCell.contentView.layer.cornerRadius = 5.0;
myTableViewCell.contentView.clipsToBounds = YES;
myTableViewCell.contentView.layer.masksToBounds = YES;
check following example as a reference to learn how to create Custom UITableViewCell and use.
https://www.appcoda.com/ios-programming-customize-uitableview-storyboard/
These columns you need to design in UITableViewCell. It can be anywhere of your preference, storyboard or xib.
For storyboard your view will be like this.
you need to add tags for all the components you add into the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
...
...
UILabel *label1 = (UILabel *)[cell viewWithTag:100];
label1.text = #"NAME";
UILabel *label2 = (UILabel *)[cell viewWithTag:200];
label2.text = #"John";
...
...
return cell;
}
The same way if you create xib your custom cell should be like this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
StackTableviewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = (stackTableviewCell*)[[[NSBundle mainBundle] loadNibNamed:#"StackTableviewCell" owner:self options:nil] objectAtIndex:0];
}
...
...
label1.text = #"NAME";
label2.text = #"John";
...
...
}
For cell UI
self.lable1.backgroundColor = [UIColor lightGrayColor];
self.lable1.layer.borderColor = [UIColor colorWithRed:169/255.0 green:169/255.0 blue:169/255.0 alpha:0.8].CGColor;
self.lable1.layer.borderWidth = 1;
self.lable1.layer.cornerRadius = 5;
self.lable1.clipsToBounds = YES;
self.lable1.layer.masksToBounds = YES;

Not Enough Cell to Use in UITableView

I have created a UITableView in Storyboard and it is dynamically cell. The problem is that when there are not enough cells to reuse, it randomly empties a few of my cells. I think this is logical, but I want to resolve this problem.
I give an example:
I have a UITableView that is capable to generate 10 cells in a view. But now, I only want to show 8 cells out of 10. It gives no problem when I have only a section. With more than 1 section, it will always empty 2 cells and show 8 cells, but it should show 10 cells.
Can anyone help me with this? Thank you.
Updated With Source code
#pragma mark - List View
#pragma mark - Table View Delegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
// Number of rows is the number of time zones in the region for the specified section.
return self.listCollection.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
for (id object in cell.contentView.subviews) {
[object removeFromSuperview];
}
[cell.contentView addSubview:[self.listCollection objectAtIndex:indexPath.row]];
return cell;
}
self.listCollection has an array of UIView Object.
Updated With Images:
Image 1
Image 2
It is happening because you are using 2 sections but are not specifying the content for each section separately. To understand this we need to look into the description of addSubview: method from Apple Documentation
This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview.
Views can have only one superview. If view already has a superview and that view is not the receiver, this method removes the previous superview before making the receiver its new superview.
Have a good look at bold section in second paragraph. As you are using the same view object from listCollection to populate both the section, so newest created cell will become the superview for this view object and previous cell will be left out with nothing but the plane contentView. You can get the real feel by assigning some default color to the cell contentView. Your blank cell will be displaying the color in full content while other cells will display the view
cell.contentView.backgroundColor = [UIColor greenColor];
Solution
I will recommend to use 2 different datasource for both sections as explained below.
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
// Number of rows is the number of time zones in the region for the specified section.
if(section==0)
return self.listCollection.count;
else
return <row count for section 1>
}
Same way you need to modify the cellForRowAtIndexPath: code for each section.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
for (id object in cell.contentView.subviews) {
[object removeFromSuperview];
}
if(section==0)
[cell.contentView addSubview:[self.listCollection objectAtIndex:indexPath.row]];
else
[cell.contentView addSubview:[<second array of views> objectAtIndex:indexPath.row]];
return cell;
}
But if that is your case that you have to use same array, then you can use this technique. Thanks to Rishi for that.
Last but not least, you should use a custom UITableViewCell class as Michal Zygar has suggested in his post.
UIView *tempView = [self.listCollection objectAtIndex:indexPath.row];
NSData *tempArchiveView = [NSKeyedArchiver archivedDataWithRootObject:tempView];
UIView *viewOfSelf = [NSKeyedUnarchiver unarchiveObjectWithData:tempArchiveView];
[cell.contentView addSubview:viewOfSelf];
You are using the UITableView wrong way.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
for (id object in cell.contentView.subviews) {
[object removeFromSuperview];
}
[cell.contentView addSubview:[self.listCollection objectAtIndex:indexPath.row]];
return cell;
}
This is highly inapriopriate. Your listCollection should contain model data. In - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath you should configure the cell with this data.
So you should subclass the UITableViewCell for example
#interface ApartmentCell:UITableViewCell
#property (weak, nonatomic) UILabel* floor;
#property (weak, nonatomic) UILabel* unit;
#property (weak, nonatomic) UILabel* type;
#property (weak, nonatomic) UILabel* area;
#property (weak, nonatomic) UILabel* price;
#end
and then
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ApartmentCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListCell" forIndexPath:indexPath];
Apartment* apartment=self.listCollection[indexPath.row];
cell.unit.text=apartment.unit;
//and so on with other fields
return cell;
}

UITableView with UIStepper change 2 diffent cells

I have a problem controlling UIStepper in a UITableView with custom cell.
When I change one UITextField.text with stepper in (row=0) it works fine, the problem is the textfield in the row=9 change too. The same happen with row=1 and row=10, etc.
I really don't get why.
The code of IBAction of the stepper in the tableviewcontroller:
- (IBAction)sumaRestaNormal:(id)sender {
// Get the cell in which the button was pressed
celdaTabacoNormal *cell = (celdaTabacoNormal *)[[[sender superview] superview]superview];
// Get the value of the stepper (it has an outlet in my custom cell
int value = cell.stepperNormal.value;
// Update the text field of the cell with the new value (also has an outlet in the custom cell)
cell.txtNormal.text = [NSString stringWithFormat:#"%d",value];}
The UITextFields are properties in the customcell.h:
#property (weak, nonatomic) IBOutlet UITextField *txtNormal;
In the cellForRowAtIndexPath I have the next:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
celdaTabacoNormal *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if(!cell){
cell = [[celdaTabacoNormal alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.referenciaTabacoN.text = [arrayRefTabaco objectAtIndex:indexPath.row];
NSString * marcaNombre = [NSString stringWithFormat:#"%# - %#", [arrayMarcaTabaco objectAtIndex:indexPath.row], [arrayNomTabaco objectAtIndex:indexPath.row]];
cell.nombreProductoN.text = marcaNombre;
return cell;
}
Why the UITextFields from row 0 and row 9, etc change at same time...!
Here I show how the cells are:
http://www.imagesup.net/?di=5140982874911
The problem comes from the reuse of cells.
How should I do for controlling this type of cells with steppers and textfields?

Custom Cells are created, but not displayed

So I've used this tutorial to populate a UITableView with custom cells that represent balances. When stepping through the code, I witness the correct amount of cells get created (only 4 with the current test data) and their labels' text set correspondingly.
My problem is when the table is displayed on the screen, only the first row/cell is displayed.
Any insight as to why this could be occurring would be greatly appreciated!
Removed old code.
BalanceCell.h:
#import <UIKit/UIKit.h>
#interface BalanceCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *nameLabel;
#property (weak, nonatomic) IBOutlet UILabel *amountLabel;
#property (weak, nonatomic) IBOutlet UILabel *modifiedLabel;
#end
EDIT:
My TableView delegate methods are now as follows:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [_balances count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
BalanceCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[BalanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.backgroundColor = [_hex colorWithHexString:_themeColourString];
return cell;
}
-(void)tableView:(UITableView *)tableView willDisplayCell:(BalanceCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
Balance *item = [_balances objectAtIndex:indexPath.row];
cell.nameLabel.textColor = _themeColour;
cell.nameLabel.text = item.name;
cell.amountLabel.textColor = _themeColour;
cell.amountLabel.text = [NSString stringWithFormat:#"%#%#", item.symbol, item.value];
cell.modifiedLabel.textColor = _themeColour;
cell.modifiedLabel.text = [NSString stringWithFormat:#"%#", item.modified];
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 94;
}
As #Sebyddd suggested, I now register the NIB in the viewDidLoad method.
- (void)viewDidLoad {
[super viewDidLoad];
[self.tableView registerNib:[UINib nibWithNibName:#"BalanceCell" bundle:nil] forCellReuseIdentifier:#"Cell"];
}
These changes may make my code more correct but still only the first cell is displayed.
If cells are getting created and returned properly I guess height is not being set propery. By default I beleive all cells have a height of 44. If your cell exceeds this height it might not get displayed.
You can tell the tableview to adjust height for every cell using (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath delegate
In that delegate just return your cells height.
EDIT:
You are using dequeueReusableCellWithIdentifier: which will return A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.
Instead use dequeueReusableCellWithIdentifier:forIndexPath: which will return A UITableViewCell object with the associated reuse identifier. This method always returns a valid cell.
You need to register the nib/class for that custom cell in viewDidLoad
Try this:
if (cell == nil) {
[tableView registerNib:[UINib nibWithNibName:#"BalanceCell" bundle:nil] forCellReuseIdentifier:#"Cell"];
cell = [[BalanceCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
Use this tuto : http://www.appcoda.com/uitableview-tutorial-storyboard-xcode5/ , your tuto is a bit outdated, and hard to follow !

ios UITableViewController Label output is nil

I used the following code on a UITableViewController.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [buyer count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell==nil)
{
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
buyerobject = [buyer objectAtIndex:indexPath.row];
UILabel *Label = (UILabel *)[cell viewWithTag:10];
NSString *temp = [[NSString alloc]initWithString:[buyerobject objectForKey:#"text"]];
Label.text = temp;
return cell;
}
When I print the above "temp" I am getting the output. But nothing is shown in the label inside the cell.
All the cell identifier and tag value are correctly given.
If someone had a similar problem and found the solution for this kind of errors then please help out.
This happens because the UILabel does not refer to an actual view in the UITableViewCell view hierarchy (you did not add it as a subview of the UITableViewCell). Try to set the label with cell with
[cell.textLabel setText:temp];
Can you try debugging with a breakpoint where you set the text and print out (po Label) what the label object is?
Based on your code you should use cell.textLabel.text=temp;.
You're also searching for a view with tag 10 inside the cell, but probably you've never set it.

Resources