All UITextFields in TableView - objective-c

I have had some problems with checking if all UITextFields where filled in in my UITableView with Custom UITableViewCell classes
I was trying to do something with this sort of code:
for (UITextField* textField in self.view.subviews ){
NSLog(#"Text: %#", textField.text);
}
And this is the error:
-[UITableView text]: unrecognized selector sent to instance 0x10b034400
Oke, so I seem to be trying to get the UITableView say its text value, so that is not good. But how can I get the TableViewCell's TextFields? So I can check if the user filled in everything and it can save the information.
Grz

You need to get reference to UITableViewCell and do the enumeration on cell.contentView, all controls are stored on contentView cell property, not view directly. All course you should do check if the view is type of UITextField if you have some other controls than UITextField on cell.
The other thing is that you are not able to get UITextField reference for the cell which are not visible because they will be most likely dequeued.
This gives you all visible table view cells and you just need to enumerate it:
NSArray *arr = [self.tableView visibleCells];
for (UITableViewCell *cell in arr) {
for (UIView *v in cell.contentView.subviews) {
if ([v isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *) v;
NSLog(#"Text: %#", textField.text);
}
}
}

that because view's subviews are not necessarily UITextField objects, try this:
for (UIView *subview in self.view.subviews //be sure you are looping through the right view){
if ([subview isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *) subview;
NSLog(#"Text: %#", textField.text);
}
}

if it is in iOS 7, Your textfields should be in the first view in Cell's subviews
for (UITextField* textField in self.view.subviews[0] ){
NSLog(#"Text: %#", textField.text);
}

Related

NSTableViewCell selectedRow number for IBAction click

I'm running into a simple problem but have yet to find an optimal solution. I have a view based NSTableView that is loading it's cell views from different xibs. My table view is dynamic and based on user input I will dynamically add and remove rows ultimately adjusting the table data source. Each one of my NSTableCellViews have a button in it and I link the IBAction click handler to the NSView that holds the table view. What I need to do is get the row number for the button that was clicked in the table view so I can process the logic. I am able to do this successfully in : tableViewSelectionDidChange:(NSNotification *)notification
Here is how I do it:
- (void)tableViewSelectionDidChange:(NSNotification *)notification {
NSTableView *tableView = [notification object];
NSInteger selectedRow = [tableView selectedRow];
}
This works perfectly for a user actually clicking the row. Now when I move the NSButton IBAction and link it in the NSView as follows:
- (IBAction)buttonClickHandler:(NSButton *)sender {
NSInteger selectedRow = [self.tblView rowForView:sender];
NSLog(#"%ld", (long)selectedRow);
}
I based this approach from this selected answer.
I also tried this:
- (IBAction)buttonClickHandler:(NSButton *)sender {
id representedObject = [(NSTableCellView *)[sender superview] objectValue];
NSLog(#"%#", representedObject);
}
//My configuration
- (void)configureView {
[self.view setFrame:[self bounds]];
[self addSubview:self.view];
[self.view setWantsLayer:YES];
[self.view setTranslatesAutoresizingMaskIntoConstraints:NO];
self.tblView.delegate = self;
self.tblView.dataSource = self;
[self.tblView setIntercellSpacing:NSMakeSize(0, 0)];
[self.tblView registerNib: [[NSNib alloc] initWithNibNamed:#"ParentCellXib" bundle:nil] forIdentifier:#"ParentCell"];
[self.tblView registerNib: [[NSNib alloc] initWithNibNamed:#"ChildCellXib" bundle:nil] forIdentifier:#"ChildCell"];
[self.tblView registerNib: [[NSNib alloc] initWithNibNamed:#"HeaderCellXib" bundle:nil] forIdentifier:#"HeaderCell"];
}
But the represented object returns null. If it's worth mentioning, I've set my File's Owner as the View that holds the tableView so I can link the IBAction and I've subclassed the TableCellView to a different class. However, I don't think this is part of the problem as far as I can see. Is there a simple solution to reliably give me the selectedRow number based on a button click in that cell? Both approaches I tried above return -1 and null respectively.
I would set the row in NSButton's tag property:
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
SomeTableCellView *cell = [tableView makeViewWithIdentifier:#"cell" owner:self];
if (cell == nil) {
cell = // init some table cell view
cell.identifier = #"cell";
}
cell.button.tag = row;
[cell.button setTarget:self];
[cell.button setAction:#selector(buttonAction:)];
}
- (IBAction)buttonAction:(id)sender {
NSLog(#"row: %d", sender.tag);
}
Try This
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
yourCustomeCell *aCell;
NSString *aStrIdentifier = #"yourIdentiFier";
aCell = (yourCustomeCell *)[tableView dequeueReusableCellWithIdentifier:aStrIdentifier];
//you have to set your indexpath
objc_setAssociatedObject(aCell.btnUpload_or_Add, #"objBtn", indexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[aCell.YourButton addTarget:self action:#selector(yourButtonActiontapped:) forControlEvents:UIControlEventTouchUpInside];
return aCell;
}
-(IBAction)yourButtonActiontapped:(UIButton *)sender{
NSIndexPath *aIndPath = objc_getAssociatedObject(sender, #"objBtn");
NSLog(#"row:%#",aIndPath.row);
}
also you have to import #import <objc/runtime.h>
another way to get row in IBAction is TAG but objc is better option insted of TAG.
Create a subclass of UIButton and add a property for NSIndexPath for the button. Use this button in cellForRowAtIndexPath method. assign the index path of the cell to that of index path of the button.
On Tap, get the index path from its sender. In your case index path of that button.

Unable to Get View Class in the top

I am trying to get current view open in my code using this code in delegate while handling Push Notification
NSArray *views = window.subviews;
NSLog(#"views: %#", views);
UIView *topview=[views lastObject];
when is click on topview and see using below tool (eye mark) it shows the current view
open .
But when i am try to get its kind of class using below two method none of these work
for(UIView *view in window.subviews)
{
if([view isKindOfClass:[MyClass class]])
{
NSLog(#"view is a MyClass\n");
}
}
or
if ([topview isKindOfClass:[MyClass class]])
{
NSLog(#"topview is a MyClass\n");
}
else
{
NSLog(#"topview is NOT a MyClass\n");
}
How can i get my visible view name of kind of class.
self.navigationController.viewControllers returns a UIViewController* array, not a UIView* array.
So, for your first solution:
for(UIViewController *viewController in self.navigationController.viewControllers)
{
if([viewController.view isKindOfClass:[MyClass class]])
{
NSLog(#"view is a MyClass\n");
}
}
will work.
For the visible UIViewController*, you can use:
UIViewController* viewController = self.navigationController.visibleViewController;
For the topmost view:
UIView* topmostView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];

Get labels in current view

I have a need to get all labels in current view. is it possible? If yes, please advise how can i realize this?
For example, i need to collect all labels from startup screen, then from currently showing popup and etc.
Thanks!
Here is the way to go----
NSMutableArray *labels = [NSMutableArray array];
for (UIView *v in someSuperview.subviews) {
if ([v isKindOfClass:[UILabel class]]) {
[labels addObject:v];
}
}
Suppose if you want to collect label in an array, you can try this:
for (UIView *subview in self.view.subviews)
{
if(subview isKindOfClass:[UILabel class])
{
[arrayOfLabels addObject:subview];
}
}
If you want it to do by means of accessibilityLabel, here are the steps to get view from given accessibilityLabel. Method viewContainingAccessibilityElement:element is extension method to UIAccessibilityElement class.
UIAccessibilityElement *element = [[UIApplication sharedApplication] accessibilityElementWithLabel:label];
UIView *view = (UIView*)[UIAccessibilityElement viewContainingAccessibilityElement:element];
Let me know if it works

How to set cursor position for UITextView inside UITableViewCell

We are doing a validation in a UITableViewCell. The cell has a textView and a custom button on clicking which a pop over containing a UIDatePickerView should open & the user will select the date. Here selecting the date is mandatory. So we did a validation using the below code. In the textViewBeginEditing delegate method of the textView inside the cell in the immediate next row. i.e when the user clicks on the textView in the next row the previous row values will be validated.
Here the validation seems to be working but the cursor still blinks in current cell and do not move to the previous cell that is being validated.
UITableViewCell* myCell = (UITableViewCell*)textView.superview ;
UITextView *txtviewMycelltext;//=[[UITextView alloc]init];
for (UIView *view in myCell.subviews)
{
if([view isKindOfClass:[UILabel class]])
{
UILabel *lbl=view;
lbl.text=[lbl.text stringByReplacingOccurrencesOfString:#"." withString:#""];
int tablerowindex=[lbl.text intValue];
NSLog(#"%#",lbl.text);
break;
}
if([view isKindOfClass:[UITextView class]])
{
txtviewMycelltext=view;
}
}
inttablerowindex-=1;
if(inttablerowindex>0)
{
if([[arrActionvalues objectAtIndex:inttablerowindex1]objectForKey:KEY_FOLLOWUPDATE]==EMPTYSTRING)
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle: #"Alert"
message: ALERT_FOLLOWUPDATE
delegate: nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
// UITableView *mytable=(UITableView *)((textView.superview).superview).superview;
UITableView *myTable=(UITableView*)[[myCell superview]superview];
NSIndexPath *indexPath = (NSIndexPath*)[myTable indexPathForCell:
(UITableViewCell*)textView.superview.superview];
UITableViewCell *previousCell = (UITableViewCell*)[myTable cellForRowAtIndexPath:[NSIndexPath indexPathForRow:indexPath.row - 1 inSection:indexPath.section]];
for (UIView *view in previousCell.subviews)
{
NSLog(#"%#",view);
if([view isKindOfClass:[UIView class]]) {
UIView *subView=view;
for(UIView *view2 in subView.subviews)
{
if([view2 isKindOfClass:[UITextView class]]) {
UITextView *txt=view2;
[txtviewMycelltext resignFirstResponder];
[txt becomeFirstResponder];
break;
}
}
}
}
}
}
Please let me know what needs to be done to get the cursor position to the correct cell.
It is not very clear from you code, but, I am guessing you are performing your validations inside textViewDidEndEditing.
textViewShouldEndEditing is the appropriate delegate method to perform validation of the text view contents. You can return NO if you want to prevent the switching of focus from the current text view.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UITextViewDelegate_Protocol/Reference/UITextViewDelegate.html#//apple_ref/occ/intfm/UITextViewDelegate/textViewShouldEndEditing:

Pushing to a Detail View from a Table View Cell using Xcode Storyboard

I have a table view inside a View Controller. I can populate all my information inside the table view. However I am a bit lost for setting up the detail views. I believe each table cell needs a segue to a each detail view but not completely sure.
Here is my code. What am I missing to accomplish the segue from the table view to the detail views?
Code:
.h
#interface DetailViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>
{
IBOutlet UITableView *myTable;
NSMutableArray *contentArray;
}
#property (strong, nonatomic) IBOutlet UITableView *myTable;
.m
- (void)viewDidLoad
{
contentArray = [[NSMutableArray alloc]init];
[contentArray addObject:#"Espresso"];
[contentArray addObject:#"Latte"];
[contentArray addObject:#"Capicino"];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
//Table Information
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [contentArray count];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
if([[contentArray objectAtIndex:indexPath.row]isEqualToString:#"EspressoViewController"])
{
EspressoViewController *espresso = [[EspressoViewController alloc]initWithNibName:#"EspressoViewController" bundle:nil];
[self.navigationController pushViewController:espresso animated:YES];
}
else if ([[contentArray objectAtIndex:indexPath.row] isEqualToString:#"Latte"])
{
LatteViewController *latte = [[LatteViewController alloc] initWithNibName:#"Latte" bundle:nil];
[self.navigationController pushViewController:latte animated:YES];
}
}
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"CellIdentifier"];
}
NSString *cellValue = [contentArray objectAtIndex:indexPath.row];
cell.textLabel.text = cellValue;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.font = [UIFont systemFontOfSize:16];
cell.detailTextLabel.text = #"Hot and ready";
UIImage *image = [UIImage imageNamed:#"coffeeButton.png"];
cell.imageView.image = image;
cell.textLabel.text = [contentArray objectAtIndex:indexPath.row];
return cell;
}
I think you made this a little too complicated. Don't worry, I do the same thing often.
First, by sending tableView:didSelectRowAtIndexPath: from within tableView:accessoryButtonTappedForRowAtIndexPath: there is no difference between the two methods. Tapping the cell, or it's accessory button performs the same action. If you don't need the accessory button to perform a different action than tapping the cell itself, remove it.
Second, if you're using a storyboard, you do not need to alloc/initWithNib for your view controllers. Instead, use a segue. If you do this through the storyboard, you also don't need to programmatically push viewControllers onto your navigationController
Build your storyboard first:
Drag out a UITableViewController. Make sure you set the class of the UITableViewController you dragged out to your own "DetailViewController" using the inspector pane on the right side.
Then select this controller and using the menus choose "Editor->Embed In->Navigation Controller".
Next, drag out three generic UIViewControllers. Set the class of one to "LatteViewController", another to "EspressoViewController", and a third to "CapicinoViewController" (using the inspector again).
Control+drag from the UITableViewController over to each of these viewControllers and choose PUSH.
Click on the little circle that's on the arrow between your UITableViewController and each of these viewControllers. In the inspector (on the right side), give each segue a unique name in the Identifier field. You will need to remember this name for your code. I would name them "EspressoSegue", "LatteSegue", and "CapicinoSegue". You'll see why in the code below.
Then put the following code in your UITableViewController:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
//Build a segue string based on the selected cell
NSString *segueString = [NSString stringWithFormat:#"%#Segue",
[contentArray objectAtIndex:indexPath.row]];
//Since contentArray is an array of strings, we can use it to build a unique
//identifier for each segue.
//Perform a segue.
[self performSegueWithIdentifier:segueString
sender:[contentArray objectAtIndex:indexPath.row]];
}
How you implement the rest is up to you. You may want to implement prepareForSegue:sender: in your UITableViewController and then use that method send information over to segue.destinationViewController.
Note that I passed the string from your contentArray as the sender for the segue. You can pass whatever you like. The string that identifies the cell seems like the most logical information to pass, but the choice is up to you.
The code posted above should perform the navigation for you.