Get textfields values in dynamic tableview - uitableview

I have a Dynamic table view which has 5 prototype cells, inside each cell I have 6 textfields. I´m tagging the textfields but I´m having trouble understanding How can I get the values from all of them in the "textFieldDidEndEditing".
In my code I have this:
-(void) textFieldDidEndEditing:(UITextField *)textField
{
NSMutableArray *cellOneContentSave = [[NSMutableArray alloc] init];
NSString *cellOneTexfieldOneTxt;
if (textField == [self.view viewWithTag:1503])
{
cellOneTexfield1Txt = textField.text;
[cellOneContentSave addObject:cellOneTexfieldOneTxt];
}
Problem 1: BUT! this only get´s me the value from one texfield in cell one...Should I be using a switch for each cell and texfield?.
Problem 2: I said it was a dynamic tableview, so the user can insert news rows(per section) pressing the green + button that appears on the left side when he enters the commit edit style...and when he enters, should the tag´s of the newtexfields have different tag´s?. In one hand I think not, because it´s new texfields BUT different indepaxth.row....but in the other hand I don´t know if the controller demands new tag´s...

-(void) textFieldDidEndEditing:(UITextField *)textField
{
// assuming your text field is embedded directly into the table view
// cell and not into any other subview of the table cell
UITableViewCell * parentView = (UITableViewCell *)[textField superview];
if(parentView)
{
NSMutableArray *cellOneContentSave = [[NSMutableArray alloc] init];
NSString *cellOneTexfieldOneTxt;
NSArray * allSubviews = [parentView subviews];
for(UIView * oneSubview in allSubviews)
{
// get only the text fields
if([oneSubview isKindOfClass: [UITextField class]])
{
UITextField * oneTextField = (UITextField *) oneSubview;
if(oneTextField.text)
{
[cellOneContentSave addObject: oneTextField.text];
} else {
// if nothing is in the text field, should
// we simply add the empty string to the array?
[cellOneContentSave addObject: #""];
}
}
}
}
// don't forget to actually *DO* something with your mutable array
// (and release it, in case you're not using ARC), before this method
// returns.
}

Related

How do I identify a UITextFiled apart from tags

Went through similar questions and tags is basically the answer to all of them. The issue is I have a custom UITableViewCell which has two text fields first name and last name. In my app I have a + button which when clicked add a new row to the table view and the table view reloads. Now earlier if a user typed something and then clicked the + button a new row would get added but the first and last name in the first row would disappear. To fix this I took a NSMutableArray, say fNameArray and would add the what the user types in - (void)textFieldDidEndEditing:(UITextField *)textField reason:(UITextFieldDidEndEditingReason)reason This works well but now I have to create another NSMutableArray for last name and the issue is I don't know how will I identify the textfield in the above delegate. Currently I am setting the tags in cellForRowAtIndexPath as cell.tf_firstName.tag = indexPath.row;
The tag property won't work if the same tag value is assigned to more than one text field AND the same delegate is used for all text fields.
Below is an implementation that solves this problem by using a different delegate for each set of text fields.
The TextFieldArrayManager manages an array of text fields and their data. It acts as the delegate for the text fields it manages.
#interface TextFieldArrayManager : NSObject <UITextFieldDelegate>
#property NSMutableArray *textItems;
#end
#implementation TextFieldArrayManager
- (void)textFieldDidEndEditing:(UITextField *)textField {
if (_textItems.count >= textField.tag + 1) {
if (textField.text) {
_textItems[textField.tag] = textField.text;
}
else {
_textItems[textField.tag] = #"";
}
}
}
#end
The view controller uses a separate TextFieldArrayManager to manage the first and last names.
#interface ObjcTableViewController ()
#end
#implementation ObjcTableViewController
TextFieldArrayManager *firstNames;
TextFieldArrayManager *lastNames;
- (void)viewDidLoad {
[super viewDidLoad];
firstNames = [[TextFieldArrayManager alloc] init];
firstNames.textItems = [NSMutableArray arrayWithObjects:#"George", #"Ludwig", #"Wolfgang", nil];
lastNames = [[TextFieldArrayManager alloc] init];
lastNames.textItems = [NSMutableArray arrayWithObjects:#"Handel", #"Beethoven", #"Mozart", nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return firstNames.textItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ObjcTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.firstName.delegate = firstNames;
cell.firstName.text = firstNames.textItems[indexPath.row];
cell.firstName.tag = indexPath.row;
cell.lastName.delegate = lastNames;
cell.lastName.text = lastNames.textItems[indexPath.row];
cell.lastName.tag = indexPath.row;
return cell;
}
To add a new, empty row to the table, you can do this:
[firstNames.textItems addObject:#""];
[lastNames.textItems addObject:#""];
[self.tableView reloadData];
When the user enters text, it will be saved to the textItems.

How to save textfield data in dictionary and then in an array?

Once a user finished entering text in a UITextfield I wand the data to be in a dictionary first and then the dictionary added to array. But for some reason after inserting into array .. It logs null..
.h
#interface Bread_TableViewController : UITableViewController <UITextFieldDelegate>
{
NSMutableArray * inventoryarray;
}
**.m**
- (void)textFieldDidEndEditing:(UITextField *)textField
{
// Make sure to set the label to have a ta
NSString*textfieldclicked;
if (textField.tag == 1) {
textfieldclicked=#"Unit";
} else if (textField.tag ==2) {
textfieldclicked=#"Case";
}
id textFieldSuper = textField;
while (![textFieldSuper isKindOfClass:[UITableViewCell class]]) {
textFieldSuper = [textFieldSuper superview];
}
NSIndexPath *indexPath = [self.tableView indexPathForCell:(UITableViewCell *)textFieldSuper];
InventoryTableViewCell *cell = (InventoryTableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
NSMutableDictionary * productinfo = [[NSMutableDictionary alloc] init];
[productinfo setObject:cell.product.text forKey:#"product"];
[productinfo setObject:textField.text forKey:textfieldclicked];
NSLog(#"productin %#", productinfo);
[inventoryarray addObject: productinfo];
}
-(IBAction)save{
NSLog(#"array %#", inventoryarray);
}
The non-visible cells do not actually exist. Only the visible ones plus one outside the screen at each end are actually in memory. The other ones are created when you scroll and their data is pulled from the data source.
As soon as a cell is pushed out of the screen (+1 cell) it will be removed from the hierarchy and added to the reuse pool.
TL;DR: You can't loop through out-of-screen cells since they don't exist. If you want to access the data for each item, do it in your data source.
alloc-init the array in which you want to add your objects.
do alloc-init of your dictionary outside the textFieldDidEndEditing method and where it scope it visible might be in viewDidLoad
like
#interface yourViewController ()
#property (strong, nonatomic) NSMutableDictionary * product info;
- (void)viewDidLoad {
self.productinfo = [[NSMutableDictionary alloc] init];
}

iOS Table View - Set tag on cell or label?

I'm a newbie to iOS development. Currently learning by following tutorials from iOS Apprentice by Matthijs Hollemans. I'm using Xcode 6 and Objective-C to make the tutorial apps.
In the book's second tutorial, he teaches his readers how to build a to-do-list app with table views, navigation controllers, etc.
In the beginning:
A custom Label with the text "Label" is placed in the prototype cell of the table. On running the app at this point, "Label" shows up in the app, as expected.
To display custom text in the table view, he asks the readers to set the 'Tag' identifier for the Label and then display custom text using the 'Tag' as shown in the code below. This leads to abnormal behaviour.
What this does is that it displays "Label" on launching the app. However, on scrolling the text off the screen and then back on the screen, the custom text shows up.
To resolve this, instead of setting the 'Tag' identifier on the Label, I set it on the Table View Cell, in spite of the Author of the book specifically warning against doing this. I also had to remove the default text "Label" from the Label in the table view so that the custom text and "Label" don't overlap.
This fixed the problem, but now I'm confused as to what is the correct protocol to follow for setting the 'Tag' identifier when it comes to using table views. Should the 'Tag' be set on Table View Cell or the Label? If it should be set on the Label then what could be the reason for me to run into this problem?
Here's the code for the main ViewController.m
#import "ViewController.h"
#import "ChecklistItem.h"
#interface ViewController ()
#end
#implementation ViewController
{
NSMutableArray * _items;
}
- (void)viewDidLoad {
[super viewDidLoad];
_items = [[NSMutableArray alloc] initWithCapacity:20];
ChecklistItem * item;
item = [[ChecklistItem alloc]init];
item.text = #"Walk the dog";
item.checked = NO;
[_items addObject:item];
item = [[ChecklistItem alloc]init];
item.text = #"Brush teeth";
item.checked = NO;
[_items addObject:item];
item = [[ChecklistItem alloc]init];
item.text = #"Prepare breakfast";
item.checked = NO;
[_items addObject:item];
item = [[ChecklistItem alloc]init];
item.text = #"Soccer practice";
item.checked = NO;
[_items addObject:item];
item = [[ChecklistItem alloc]init];
item.text = #"Eat ice cream";
item.checked = NO;
[_items addObject:item];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
//data source method no.1 to get the number of rows in section for the table view
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [_items count];
}
- (void)configureCheckmarkForCell:(UITableViewCell *)cell withChecklistItem:(ChecklistItem *) item {
//if the item is checked, display checkmark
if (item.checked) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
- (void)configureTextForCell:(UITableViewCell *)cell withChecklistItem:(ChecklistItem *) item {
UILabel * label = (UILabel *)[cell viewWithTag:1000];
label.text = item.text;
}
//data source mathod no.2 to get the cell to display the row in the given index path
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"ChecklistItem"];
ChecklistItem * item = _items[indexPath.row];
[self configureTextForCell:cell withChecklistItem:item];
[self configureCheckmarkForCell:cell withChecklistItem:item];
return cell;
}
//delegate method to handle taps on rows
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
ChecklistItem * item = _items[indexPath.row];
[item toggleChecked];
[self configureCheckmarkForCell:cell withChecklistItem:item];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
#end
I'm not familiar with the tutorial, but using tags to identify labels within cells this way is not a good idea.
The cell should know about it's own label. It's far better to just have a method on the cell that you can pass the text to, and then let the cell take care of displaying the text in the cell.
By using the tag in this way, you are expecting to know too much about the internal implementation of the cell, and this is brittle and is likely to break.
So my answer is to set the tag on neither of them, and to use a proper configuration method of the cell itself.
Edited to add
You can download a simple version of a project for configuring a cell, without using tags here https://bitbucket.org/abizern/so-27713743/get/543739690dc4.zip
An alternative way to solve this is to not deal with a view tag at all, but create a subclass of UITableViewCell and design your layout with this subclass. When you dequeue the cell in tableView: cellForRowAtIndexPath: or get the cell in tableView:didSelectRowAtIndexPath, use your subclass for the cell.
For example, create a subclass of UITableViewCell and give it a label as a property. If you're using xib's or storyboard, attach this label as an outlet. Then you can access that label directly as you would any other property.

How to do select all function for custom cell in UITableView in iOS

I have a table that imports the address book contacts and displays the image, contact name and a checkbox, i've customized my cell with image, label and a button which serves as a checkmark. I'm successfully able to display all contacts and the checkmark also works fine for individual cells, but i'm having trouble implementing select all functionality that will put all the button in the table in selected state and clicking it again will deselect it all. This is what I have done so far.
//This is the class for my custom cell
#import "InviteFriendsCell.h"
#implementation InviteFriendsCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
//This is my checkmark button
-(IBAction)onAddTouched:(id)sender
{
UIButton *addButton = (UIButton *)sender;
[addButton setSelected:![addButton isSelected]];
}
#end
//This is my tableview display code in FriendListViewController
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"friendsCell";
InviteFriendsCell *cell= [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"InviteFriendsCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Configure the cell...
NSUInteger row = 0;
NSUInteger sect = indexPath.section;
for (NSUInteger i = 0; i < sect; ++ i)
row += [self tableView:tableView numberOfRowsInSection:i];
row += indexPath.row;
cell.thumbImage.layer.cornerRadius=25;
cell.thumbImage.clipsToBounds=YES;
cell.thumbImage.image=nil;
self.persons = CFArrayGetValueAtIndex(self.contactAdd, row);
NSString *tweet=[[NSString stringWithFormat:#"%#",(__bridge_transfer NSString *)ABRecordCopyCompositeName(self.persons)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
[cell.friendName setText:tweet];
if (ABPersonHasImageData(persons))
{
NSData *imgData = (__bridge NSData *) ABPersonCopyImageDataWithFormat(persons, kABPersonImageFormatThumbnail);
cell.thumbImage.image = [UIImage imageWithData:imgData];
}
else
{
cell.thumbImage.image = [UIImage imageNamed:#"name_icon.png"];
}
return cell;
}
//This is my select all button which should put checkmark to all button in tableview
- (IBAction)selectAll:(UIButton *)sender {
//This is where I need to implement the code
}
There is a similar question in stack overflow here Need to create a select all button for UITableView and add selections to an array in iOS
But here the checkmark button is created inside the tableview method, my case is different and I'm unable to implement that code. Is there a better way to do this? I'm using storyboard and xcode 5 and should work for ios 5 or above.
first create a array with boolean values
#property (retain, nonatomic) NSMutableArray *selectedArray;
Initialise your selected array based on the contact add count, better generalise it and store it into an NSArray if u are planning to expand this. Here peopelist is my NSArray
self.peopleList=(__bridge NSArray *)(self.contactAdd);
self.selectedArray=[[NSMutableArray alloc]initWithCapacity:[self.peopleList count]];
for(int i=0;i<[self.peopleList count];i++)
{
[self.selectedArray insertObject:[NSNumber numberWithBool:NO] atIndex:i];
}
In the selectAll button action use this
- (IBAction)selectAll:(UIButton *)sender {
for(int i=0;i<self.selectedArray.count;i++)
[self.selectedArray replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:sender.isSelected]];
[sender setSelected:!sender.isSelected];
[yourTable reloadData];
}
You need to change your data source and your cell. contactAdd needs to know that the contact is selected (you could use a new array for this, but why would you). The cell needs to callback to the controller when the button is tapped to tell the controller about whether it's selected or not. The controller needs to update the cells to set the selected status.
Your code currently won't work properly if you have lots of cells, select some and then scroll (either other rows will show as selected or the selections will be lost depending on if your reuse identifier is configured correctly).
Also, your contactAdd is overly complex. Look at using multiple arrays (one per section) as your current indexing is complicated to maintain.
I really think that using predefined "selected" method is bad and rigid approach. So I would prefer the following solution:
Just connect touch listener to every cell and handle the Tap event. When it occurs set the cell data source "selected" and update the layout of the cell.
If you want to "select all" you should update all cell datasources to "selected" and then update the whole table (reloadData)
Note: instead of making one template and manipulating data you can also create two templates for the cell - selected and unselected one and implement custom template selector in your cell constructor.

How to get UITextField value on custom UITableView cell

I'm new to IOS development and i'm trying to develop my first app.
So my problem is... I've got a UITableView with custom cells, each cell contains an UITextField. When I press a button I'd like to put each UITextField value in a NSMutableArray.
I think I've got to do something like that but I'm not sure:
NSMutableArray *playerNameArray = [[NSMutableArray alloc] init];
for (int i=0; i < nbPlayers; i++){ //nbPlayers is the number of rows in the UITableView
NSString *playerName =UITextField.text;
[playerNameArray addObject:[NSString stringWithFormat: #"%#", playerName]];
}
If someone can help me.... :)
Thanks
You need to reference the instance of your UITextField, what you're doing there is attempting to call text on the UITextField class. Something like this would probably solve your problem:
NSMutableArray *playerNameArray = [[NSMutableArray alloc] init];
for (int i=0; i < nbPlayers; i++){ //nbPlayers is the number of rows in the UITableView
MyTableViewCellSubclass *theCell = (id)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
UITextField *cellTextField = [theCell textField];
NSString *playerName = [cellTextField text];
[playerNameArray addObject:playerName];
}
The text field passed to your delegate is a subview of the cell's contentView.
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
UITableViewCell *cell = (UITableViewCell*) textField.superview.superview;
NSIndexPath *txtIndPath = [self.tblPendingDeliveryData indexPathForCell:cell];
write you code here.....like
if(textField.tag == 1)
{
NSMutableDictionary *dict = [self.arrPendingDeliveryData objectAtIndex:txtIndPath.row];
[dict setObject:textField.text forKey:#"ReOrder"];
}
}
In txtIndPath you will get active textfield's indexpath. Assign the textfield tag property with necessary value. It works well for me.
Look at this thread for a similar question
UITextField in UITableViewCell Help
You should to use one of the textfield delegated method to fill the proper cell of your array
- (void)textFieldDidEndEditing:(UITextField *)textField{
}

Resources