How can you search a UIViewController for number of UITextFields? - objective-c

More generally how do you search a UIViewDelegate for UI elements?
Right now, I'd like to count the number of UITextFields in my current view to populate the correct number of UILabels in other views.

- (NSInteger)textFieldCountInsideView:(UIView *)parentView
{
NSInteger count = 0;
for (UIView *subview in parentView.subviews) {
if ([subview isKindOfClass:[UITextField class]])
count = count + [self textFieldCountInsideView:subview];
}
return count;
}
And somewhere in your UIViewController:
NSInteger count = [self textFieldCountInsideView:self.view];

If all the text fields are direct subviews of your current view, just loop through the current view's subviews, and test for whether they're UITextField class. If they're not all direct subviews, then you would need to drill down into all top level subviews to see if any of them also contained UITextFields.

Related

List the tag of Subviews which are visible in a UIview

I have UIView, Initially i will have 4 subview, in runtime. my code will hide to 2 view, so i need the tag values of remaining two view which are visible, is it possible.
Please help me.
Thanks,
Nikhil.Ch
First, iterate the subviews of the view. Check if the subview is a UIView class. From here, you can now check whether the subview is hidden or not.
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UIView class]]) {
if (!subview.isHidden) {
NSLog(#"%i", subview.tag);
}
}
}

UITableView cell retaining out of view data

I am trying to solve this issue regarding a UITableView cell being off screen, or outside the visible area.
Within my tableview cells I have a UITextField which I am able to parse easily using the code below. However I find that that for the cells that are not visible it returns a NULL value.
I am guessing this is a feature to improve memory usage but is there anyway to turn it off? Or if not is there a work around?
InputCell *inputCell = (InputCell *)[self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
UITextField *cellContent = (UITextField *)[inputCell.textInput viewWithTag:0];
NSLog(#"Cell Content: %#" , cellContent.text);
Thanks and thanks again!
Views need models, especially table views. A model is some object (often a group of objects in collection classes) that represents the state of your app. A table view requires an array. The datasource protocol asks you to describe that array. Since tableview cells are part of the view, they shouldn't be relied upon to keep the state of your app. That's up to you as follows:
In your vc's private interface:
#property(strong, nonatomic) NSMutableArray *myDatasource;
Early, like in view did load:
myDatasource = [NSMutableArray array];
// fill it with strings
In numberOfRowsInSection...:
return self.myDatasource.count;
In cellForRowAtIndexPath:
cellContent.text = self.myDatasource[indexPath.row];
Make the vc your textField's delegate and implement:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString *candidateString = [textField.text stringByReplacingCharactersInRange:range withString:string];
NSIndexPath *indexPath = [self indexPathWithSubview:textField];
self.myDatasource replaceObjectAtIndex:[indexPath.row] withObject: candidateString];
return YES;
}
This helper finds the indexPath of any textField (any subview) of any cell:
- (NSIndexPath *)indexPathWithSubview:(UIView *)subview {
while (![subview isKindOfClass:[UITableViewCell self]] && subview) {
subview = subview.superview;
}
return [self.tableView indexPathForCell:(UITableViewCell *)subview];
}
It looks like a lot, but not so bad when you get used to it. The pattern is always - think of the objects that describe the state of your app (model). Think of views that best describe and manipulate that state (view). Make your view controllers (controllers) (a) notice model changes and change the views accordingly, and (b) hear about user actions from the views and update the model.

How do I iterate over all controls in a View

I have a static table view controller. Within some of the cells, I have text boxes. I would like to enable or disable all the text boxes in one go. I know I could do something like
self.nameTextField.Enabled = NO;
self.ageTextField.Enabled = NO;
self.hairColorTextField.Enabled = NO;
But there has to be something more elegant. Something like
for (UIControl* control in self.allChildControls) { // <-- I totally just made that up.
if ([control isKindOfClass:[UITextField class]]) {
control.Enabled = NO;
}
}
I don't think I am asking the right question...
You can use the subviews property od UIView. It contains all child UI elements.
#property(nonatomic, readonly, copy) NSArray *subviews
UIView Documentation
for (UIView *subview in self.view.subviews) {
//check by class or tag
}
If you have a static tableviewController, I am assuming you aren't allowing the user to add/delete cells. If this is the case, your question is simple. You just need to add an outlet to each of the UITextField objects and toggle it's userInteractionEnabled property to no.
self.myTextField.userInteractionEnabled = NO;
self.mySecondTextField.userInteractionEnabled = NO;
Hope this helps :)

Displaying elements of an array on a buttons

I am working on an educational game for a local school system, in this game students are presented with six numbers and they have to try and use as many of them as they can to equal a seventh number, the numbers are stored in an array called currentHand, and the numbers need to be displayed as text on buttons present on the screen. The catch is, as they combined numbers together the values on the buttons need to change accordingly. Say I add two buttons a button with the value 1 and a button with a value 2, the value three gets added to the array and the values 1 and 2 are deleted, then one button needs to become invisible and the other needs to be updated with the value 3. I was told to try this with an IBOutletCollection, but because I am still very new to objective C, I have no idea how to use an IBOutCollection to do this, I had an idea to create a method that would tie each button to an element in the array, as the list shrank in size so would the number of buttons, so if you had the numbers
{1,2,3,4,5,6}
each button would have one value assigned to them, but as the list changed to say
{1,2,3,4,11}
the button displaying the number 6 would disappear and the button holding the number 5 would change to 11, but as I said I have no idea how to accomplish this.
As I cannot display pictures being such a new member, I have linked one to how I tried to set up the IBOutletCOllection
and below is the code that instantiates currentHand
-(NSMutableArray *) currentHand{
if (_currentHand == nil) {
_currentHand = [[NSMutableArray alloc]init];
}
self.currentHand = self.myDeck.giveHand;
return _currentHand;
}
Any advice on this would be greatly appreciated, thanks in advanced.
Here is one way to approach this problem. As I said in my comments, I don't see any need for an array to keep track of the numbers as you click the button (just one to provide the original numbers for the title), or the need for an IBOutletCollection.
So, in the example below, I created a single view project, added 6 buttons to the view controller's view, set all their tags to 1 and connected them all up to the one action method, buttonPressed:. I don't use any outlets for the buttons, because you can do what you need to do just by looping through the view's subviews -- the tags aren't really necessary in this example, but if you had any other buttons in your view, the tags would be a way to distinguish these 6 game buttons from any others.
I'm not sure this is exactly the look you were going for, but try it out and see if it's close.
#interface ViewController : UIViewController
#property (assign) int total;
#property (retain) UIButton *previousButton;
#import "ViewController.h"
#implementation ViewController
#synthesize previousButton,total;
- (void)viewDidLoad
{
[super viewDidLoad];
self.total = 0;
NSMutableArray *theData = [NSMutableArray arrayWithObjects:#"1",#"3",#"5",#"7",#"8",#"4",nil];
for (id obj in [self.view subviews]) {
if ([obj isKindOfClass:[UIButton class]] && [obj tag] == 1) {
[(UIButton *)obj setTitle:theData.lastObject forState:UIControlStateNormal] ;
[theData removeLastObject];
}
}
}
-(IBAction)buttonPressed:(UIButton *)sender {
self.total += sender.titleLabel.text.intValue;
[sender setTitle:[NSString stringWithFormat:#"%d",self.total] forState:UIControlStateNormal];
self.previousButton.hidden = YES;
sender.enabled = NO;
[sender setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
self.previousButton = sender;
}

Changing view for selected in view-based NSTableView

How do I change the view for the selected row when using a view-based NSTableView? Specifically, I'd like to have a simple NSView subclass for unselected rows and a more complex NSView subclass for the selected row which allows editing of more information associated with the row item.
An example is the way Things allows you to expand the item being edited as seen here: http://culturedcode.com/things/
My guess is that you want to use a different NSTableCellView subclass when the row is selected. I think you should be able to do something like this:
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSTableView *table = [notification object];
NSIndexSet *allColumns = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [[table tableColumns] count])];
[table reloadDataForRowIndexes:[table selectedRowIndexes] columnIndexes:allColumns];
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
if ([[tableView selectedRowIndexes] containsIndex:row])
{
// If the row is selected, return an instance of the class for selected views
SelectedTableCellView *selectedView = ...; // Get from makeViewWithIdentifier:
// Set up selectedView
return selectedView;
}
else
{
NonSelectedTableCellView *nonSelectedView = ...; // Get from makeViewWithIdentifier:
// Set up nonSelectedView
return nonSelectedView;
}
}
It might be nice if you elaborated a little bit more on what you mean by "change the view to a more complex view"
Nonetheless, you could for instance, implement - (void)tableViewSelectionDidChange:(NSNotification *)notification in the delegate of the table view, get the selected NSTableRowView if it is visible, and change it in what way you want, which includes making it more complex, expanding it (see below), etc.
To modify the size of a row, you would need to implement - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row in the same delegate, and call the table view's -noteHeightOfRowsWithIndexesChanged to update the height for particular rows.
I think the app is created by NSOutlineView in outlineview only you can easily expand your selected row...
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
if ([item isKindOfClass:[NSDictionary class]])
{
return YES;
}else
{
return NO;
}
}
I think this way is write..