How to enumerate through UITextFields on iOS - ios

Which is the correct way of enumerating through sub views to find text fields?
NSMutableArray *mutableTFs = [[NSMutableArray alloc] init];
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
[mutableTFs addObject:view];
}
}
OR
NSMutableArray *mutableTFs = [[NSMutableArray alloc] init];
for (UITextField *textField in [self.view subviews]) {
[mutableTFs addObject:textField];
}
I know this isn't the correct wording, but what I don't understand is if it is the top method, how do you 'convert' it from a view to a text field?

Which is the correct way of enumerating through sub views to find text
fields?
The first method is the correct one. The second method will iterate over all the subviews, not just the subviews with type UITextField. The type in the for() is only a hint to the compiler.
For more information, see this question.
how do you 'convert' it from a view to a text field?
This is what typecasting is for.
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
// you don't need to cast just to add to the array
[mutableTFs addObject:view];
// typecasting works as it does in C
UITextField *textField = (UITextField *)view;
// do something with textField
}
}

The first method is the only working method of the two.
The second method would add all subviews to the array. That is if you would change subViews to subviews.
You could do the following:
for (UITextField *textField in [self.view subviews]) {
if ([textField isKindOfClass:[UITextField class]]) {
[mutableTFs addObject:textField];
}
}
That way you wouldn't have to convert the view to a text field to do something text field specific instead of just adding it to an array.
EDIT: If you don't want to convert to a text field right away, maybe because you're looking for both text fields and text views. This is how you'd convert it later:
for (UIView *view in [self.view subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)view;
// Do whatever you want with the text field.
}
if ([view isKindOfClass:[UITextView class]]) {
UITextView *textView = (UITextView *)view;
// Do whatever you want with the text view.
}
}

Here's the best way.
// Make sure you're releasing this!
NSMutableArray *textFields = [[NSMutableArray alloc] init];
for (UITextField *textField in [self.view subviews]) {
if ([textField isKindOfClass:[UITextField class]]) {
[textFields addObject:textField];
}
}
By specifying UITextField * as the type that you're performing the fast enumeration with, you'll be working with values that are casted already (by fast enumeration) from id to UITextField *. This does not guarantee that they are actually UITextFields though, so you still need a runtime check, in this case isKindOfClass:, to make sure the object you're currently working is really a UITextField.
So, both of them are correct, but only when combined.

Related

Setting Search Texfield Text Colour from UISearchBar

I have used this piece of code to set Text Color for the Texfield Inside the UISearchBar.
for (UIView* view in subViews)
{
if([view isKindOfClass:[UITextField class]])
{
UITextField* searchTextField = (UITextField*)view;
[self setTextColorToTextField:searchTextField];
break;
}
else
{
for (id view1 in view.subviews)
{
if ([view1 isKindOfClass:[UITextField class]])
{
UITextField* searchTextField = (UITextField*)view1;
[self setTextColorToTextField:searchTextField];
break;
}
}
}
}
Can anyone suggest how to improve the code?
Well there is no need to code when you can set its colour in the StoryBoard.
Here add this line in identity inspector of searchBar.

checking whether all text field in my view is empty or not objective c [duplicate]

This question already has answers here:
Loop through subview to check for empty UITextField - Swift
(2 answers)
Closed 6 years ago.
Need an Assistance.My question is, how do i ensure that all textfields in a View are empty or not ..
I know that it can be achieved by a for loop followed by all textfields length are greater than zero.
Is there any method available to check this ??
TY in Advance.
You can loop through all subviews of your view, and pick all of the UITextField instances.
//replace self.view to whatever your own view
- (void)checkAllTextField {
for (UIView *view in self.view.subviews) {
if ([view isKindOfClass:[UITextField class]]) {
UITextField *textField = (UITextField *)view;
NSLog(#"This is a UITextField, length: %lu", textField.text.length);
} else {
NSLog(#"not a UITextField");
}
}
}
You can get array of all text fields using recursive function and then check for Blank in textfield.
-(NSArray*)findAllTextFieldsInView:(UIView*)view{
NSMutableArray* textfieldarray = [[[NSMutableArray alloc] init] autorelease];
for(UIView x in [view subviews]){
if([x isKindOfClass:[UITextField class]])
[textfieldarray addObject:x];
else if([x respondsToSelector:#selector(subviews)] && [x subviews].count > 0){
// if it has subviews, loop through those, too
[textfieldarray addObjectsFromArray:[self findAllTextFieldsInView:x]];
}
}
return textfieldarray;
}

Clearing data of the textfields and textviews view on toggling of a view

Suppose I have a button and a view consisting multiple fields like textfields, textviews etc. There is some input data in the textfield as well as in textview. When I click on button the view gets hide, when i clicked again, it shows up. What I want is, when view reappear, all the input fields should be clear. I can clear the textfields data manually by setting it as empty string (#"") but I want some cleaner solution, which ll clear all the fields of view. I tried doing self.toggleView = nil too, but it doesn't work.
One option for doing this is
- (void)clearTextFieldOrTextViews{
for (UIView *subview in self.subviews)
{
if ([subview isKindOfClass:[UITextField class]]){
textField = (UITextField*)subview;
textField.text = #"";
}else if([subview isKindOfClass:[UITextView class]]){
textView = (UITextview*)subview;
textView.text = #"";
}else if([subview isKindOfClass:[UIButton class]]){
button = (UIButton*)subview;
[button setTitle:#"" forState:UIControlStateNormal];
}
}
}

How to iterate through self.superview in Xcode?

I have a class called LabelView inheriting from UIView. In the story board have a view dragged and inheriting from LabelView. Now I want to iterate through the self.superview to set the attributed text of each view. Please suggest a method to do so.
Here is my code:
int i=0;
for (UIView *view in labelView) {
if ([view isMemberOfClass:[LabelView class]]) {
[view setTag:i];
NSArray *symbols = #[#"+", #"-", #"*", #"/"];
NSString* symb = [NSString stringWithFormat:#"%#", [symbols objectAtIndex:i]];
UIFont *labelFont = [UIFont systemFontOfSize:view.bounds.size.width*0.80];
NSAttributedString *labelOperator=[[NSAttributedString alloc]initWithString:[NSString stringWithFormat:#"%#", symb]attributes:#{NSFontAttributeName: labelFont}];
CGRect textrect;
textrect.origin=CGPointMake(12, 0);
textrect.size=[labelOperator size];
[labelOperator drawInRect:textrect];
i++;
}
else{
NSLog(#"fail");
}
}
You may want to try something like this:
for (UIView *view in self.view.subviews) {
if ([view isMemberOfClass:[LabelView class]]) {
//DO WHATEVER YOU WANT
}
The above fast enumeration code iterates through all the subviews in your self.view and checks if the view is a member of your custom class which is LabelView. If it finds one, then the statements inside the if condition gets executed. Hope it helps!
The key is to go from your label view to the superview and iterate through its subviews.
for (UIView *label in labelView.superview.subviews) {
if ([label isKindOfClass:[LabelView class]]) {
// configure the label
}
}

Changing the action bound to the send button in MFMessageComposeViewController

I know it's not officially possible. I don't want to release it to the store, it's just a prototype.
I tried finding the button:
MFMessageComposeViewController *messageController = [[MFMessageComposeViewController alloc] init];
messageController.messageComposeDelegate = self;
NSArray * allViewControllers = [messageController viewControllers];
for (UIViewController *viewController in allViewControllers)
{
NSArray *allSubviews = [viewController.view subviews];
NSLog(#"class name: %#", viewController.class);
for(UIView *view in allSubviews)
{
if([view isMemberOfClass:[UIButton class]])
{
UIButton *button = (UIButton *)view;
NSLog(#"title: %#", button.titleLabel.text);
}
}
}
But nothing worked, so is it possible to change that send button? A sort of a hack? or importing a private header?
Thanks you.
Update:
Tried the following:
NSArray *allSubviews = [[messageController toolbar] subviews];
for(UIView *view in allSubviews)
{
if ([view isKindOfClass:[UIToolbar class]])
{
UIToolbar *navigationBar = (UIToolbar *)view;
for(UIView *subview in navigationBar.subviews)
{
NSLog(#"%#", [subview subviews]);
if([subview isMemberOfClass:[UIBarButtonItem class]])
{
UIBarButtonItem *button = (UIBarButtonItem *)view;
NSLog(#"title: %#", button.title);
}
}
}
Behind the hood, yes you can trick the label of Send Button.
Officially it is not allowed, but for private use you can use following framework which is available on github.
https://github.com/nst/iOS-Runtime-Headers/tree/master/Frameworks/MessageUI.framework.
Instead of default framework include this in your project.
And change whatever you want.
If any query let me know i will show the code.
I've never done this but here are some ideas to point you in the right direction.
MFMailComposeViewController is a UINavigationController. The "Send" and "Cancel" buttons are actually in its navigation bar. The navigation bar is a subview of the UINavigationController's view, rather than belonging to any of its children. You are logging the subviews of each child view, so you would never actually see the navigation bar since it is managed by the parent.
Try logging the subviews of the messageController.view, that should give you the navigation bar. The other thing is that you are checking for UIButton whereas you may want to be checking for a UIBarButtonItem.

Resources