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{
}
Related
I am trying to extract the values inputted to a textfield. The problem is these textfields are defined programmatically in a cell of a tableview.
-(void)viewDidDisappear:(BOOL)animated{
[super viewDidDisappear:(BOOL)animated];
NSUInteger numOfRows=[userControls count];
for (int i =0; i<numOfRows; i++) {
[self saveValueForRow:i];
}
}
#pragma save defaults
- (void)saveValueForRow :(int)index {
NSString *userDataString=userEntryField.text; //how to access each text field, as this currently just accesses the first one in the table
NSLog(userDataString);
[[NSUserDefaults standardUserDefaults] setObject:userDataString forKey:[controlKeys objectAtIndex:index]];
}
My instinct was to collect all the data after the view disappears. But I don't know how to access each different text field in each different cell.
You need to set the tag of cell in cellForRowAtIndexPath method as:
cell.tag = indexPath.row;
Now at the time of getting values of textField you need to first get the cell by indexPath like:
#pragma save defaults
- (void)saveValueForRow :(int)index {
NSIndexPath *nowIndex = [NSIndexPath indexPathForRow:index inSection:0]
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:nowIndex];
NSString *userDataString = cell.userEntryField.text; //how to access each text field, as this currently just accesses the first one in the table
NSLog(userDataString);
[[NSUserDefaults standardUserDefaults] setObject:userDataString forKey:[controlKeys objectAtIndex:index]];
}
Hope this Helps!
You can set a tag for each UITextField like:
//...
textview.tag = indexPath.row;
//...
So after you can access each textField by tag. I hope this can help you.
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];
}
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.
I have a static UITableView with 4 different prototype cells. Instead of working with 1 reusable cell including a switch, I used 3 different "switchcell-prototypes", switchCell1 - to switchCell3 (I was lazy). The first switchCell is in section 1 of the table, along with a textBoxCell I made. The other 2 switchCells are in section 2.
I am accessing the switches and the textbox within the cells with tags.
Just to give it a try I changed my code so that the tableview now only has one section. Everything is now shown, with no switching to hide certain cells. Seems that it's not the issue of 2 sections, but that there are cells coming after the one having the textfield in it. Weird.
The properties of the switches and the textbox are strong.
This is how I access my switches and the textbox:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
switchCellLabel = (UILabel *)[cell viewWithTag:10];
dailyLimitSwitch = (UISwitch *)[cell viewWithTag:20];
[dailyLimitSwitch setOn:[settings boolForKey:#"limitBool"]];
textBoxCellLabel = (UILabel *)[cell viewWithTag:30];
dailyLimitEntry = (UITextField *)[cell viewWithTag:40];
This is the action for one of the switches:
- (IBAction)dailyLimitSwitch:(id)sender {
if ([settings boolForKey:#"limitBool"]==NO) {
[settings setBool:YES forKey:#"limitBool"];
}else if ([settings boolForKey:#"limitBool"]==YES){
[settings setBool:NO forKey:#"limitBool"];
[settings setDouble:(0) forKey:#"limitDouble"];
I am using the same kind of action for the textbox, too. - (IBAction)dailyLimitEntry:(id)sender
So, here is the complete IBAction for my UITextField
I basically get the string from the UITextField, make it into a number to check that the user entered a real number, then I create an integer to see if it's a decimal number as I only want integers and then I "save" the entry in some NSUserDefaults. Like posted initially, this works as long as only one section of the table is visible. As soon as I show the switches in the second section, the textfield returns null.
- (IBAction)dailyLimitEntry:(id)sender {
NSNumberFormatter *newLimitFormatter = [[NSNumberFormatter alloc]init];
[newLimitFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[newLimitFormatter setMaximumFractionDigits:3];
NSNumber *newLimitNr = [[NSNumber alloc]init];
newLimitNr = [newLimitFormatter numberFromString:dailyLimitEntry.text];
double newLimitDouble = [[newLimitFormatter numberFromString:dailyLimitEntry.text]doubleValue];
int newLimitInt = [newLimitNr intValue];
if (newLimitNr == nil || (newLimitDouble - newLimitInt)>0) {
UIAlertView *invalidLimitAlert = [[UIAlertView alloc]initWithTitle:#"Limit" message:#"Invalid limit" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[invalidLimitAlert show];
}else{
[settings setDouble:newLimitDouble forKey:#"limitDouble"];
if (![settings doubleForKey:#"countDouble"]==0) {
double newRemainingDouble = [settings doubleForKey:#"limitDouble"]-[settings doubleForKey:#"countDouble"];
[settings setDouble:newRemainingDouble forKey:#"remainingDouble"];
}else if ([settings doubleForKey:#"countDouble"]==0){
double newRemainingDouble = [settings doubleForKey:#"limitDouble"];
[settings setDouble:newRemainingDouble forKey:#"remainingDouble"];
}
}
[dailyLimitEntry resignFirstResponder];
}
And finally my cellForRowAtIndexPath:
(This is from where everything still worked. I've added my new "switchcells" from IB by referencing them like the switchcell here and added the numbers 1 and 2 to the identifier (switchcell1 and switchcell2) so that they are different.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSUInteger section = [indexPath section];
NSUInteger row = [indexPath row];
if (section == 0 && row == 0) {
cellIdentifier = #"switchCell";
}
if (section == 0 && row == 1) {
cellIdentifier = #"textBoxCell";
}
NSArray *labelsForCurrentSection = [sectionLabels objectAtIndex:section];
NSString *labelForCurrentCell = [[NSString alloc]init];
labelForCurrentCell = [labelsForCurrentSection objectAtIndex:row];
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
switchCellLabel = (UILabel *)[cell viewWithTag:10];
dailyLimitSwitch = (UISwitch *)[cell viewWithTag:20];
[dailyLimitSwitch setOn:[settings boolForKey:#"limitBool"]];
textBoxCellLabel = (UILabel *)[cell viewWithTag:30];
dailyLimitEntry = (UITextField *)[cell viewWithTag:40];
switchCellLabel.text = labelForCurrentCell;
textBoxCellLabel.text = labelForCurrentCell;
if ([settings doubleForKey:#"limitDouble"]==0) {
dailyLimitEntry.text = #"";
}else{
NSString *dailyLimitStr = [[NSString alloc]initWithFormat:#"%0.f",[settings doubleForKey:#"limitDouble"]];
dailyLimitEntry.text = dailyLimitStr;
}
return cell;
}
Here is the problem:
All switches and the textbox are linked to the interface via IBAction.
I can set my userdefaults with all 3 switches, no matter if the 2nd section is visible or not. But the textfield returns it's value if my 2nd section isn't visible and returns null if it's visible.
Any ideas? It's really driving me crazy.
I solved my issue and it's now working with multiple sections and cells following my UITextField-cell.
Here's what I did:
Create a prototype cell holding a UITextField
Connect the UITextField via an IBAction "didEndOnExit" to .h
When setting up the UITextField-Cell in cellForRowForIndexPath, reference the UITextField like this dailyLimitEntry = (UITextField *)[cell viewWithTag:35]; (this way, the content can be set from the userdefaults via dailyLimitEntry.text
In the IBAction of the didEndEditing of the UITextField - (IBAction)dailyLimitEntry:(id)sender I access the contents of the UITextField from whatever the sender gives me back. To do so, I've set up a temporary variable like this UITextField *cellDailyLimitEntryTextField= (UITextField*)sender; (the long variable name is only so I can remember what I did when I come back later.
Now I can retrieve the value of the textfield via cellDailyLimitEntryTextField.text and proceed with the rest of my code.
The UITextField now behaves like it wasn't even located within a cell of a tableview and getting and setting the content is straight forward.
Whether this is ok for Apple, I'll know as soon as I submit my app. But I basically make apps I want for myself ;-)
By the way, no UITextFieldDelegate and its methods were needed. I think that setting up my cell creates an instance of a UITextField which I didn't access properly to receive the content. Like stated in my question, everything worked fine as long as no more cells followed the UITextFieldCell. Now I've opened up my UITableView to its initial state with 2 sections, and it works.
If you like my answer to my question, please vote for it.
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.
}