Displaying elements of an array on a buttons - objective-c

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;
}

Related

UIVIew: Is there a way to have multiple tags to retrieve the superview?

I'm coding for iOS7.
I have a grouped UITableView, with 3 different sections, each one of them has multiple rows.
In every row there is an UITextField added as accessoryView:
UITextField *myTextField = [UITextField alloc] init];
cell.accessoryView = myTextField;
I need to retrieve the right cell/textField in other places of my code, for example this code was working up to iOS6:
-(void) textFieldValueDidChange: (UITextField*) sender
{
NSIndexPath *indexPath = [self.tableView indexPathForCell: (UITableViewCell*) sender.superview];
switch (indexPath.section){
case(SECTION_1):{
switch(indexPath.row){
case(ROW_1):{
//DO SOMETHING
}
}
}
}
}
This kind of code breaks in iOS7.
On another thread someone suggested to me to never retrieve my subviews like this but to assign the indexPath.row value to the tag property of the sender when the cell is created and then retrieve the right cell from it. This works perfectly when the table is a normal one and I am dealing just with the row number but here I have to keep track both of the row and the sections and there is only one tag property.
What would be my best option to deal with it? I thought about adding 1000, 2000, 3000 etc.. to keep track of the section, example: 2003 would mean indexPath.section = 2 and indexPath.row = 3 but this doesn't apper an elegant solution to me. Any idea?
Thanks
Nicola
What about creating a category on UIView with a property that will hold the indexPath?
.h:
#interface UIView (IndexPathTag)
#property (nonatomic, retain) NSIndexPath *indexPathTag;
.m
#implementation UIView(IndexPathTag)
Then, in your code, if you import UIView+IndexPath, you can do:
#import "UIView+IndexPathTag.h"
myView = [[UIView alloc] init];
myView.indexPathTag = indexPath;

How can you search a UIViewController for number of UITextFields?

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.

Issue with a checkBox in a viewbased NSTableView

I have an NSDictionary that holds all the data:
One title (not important for this question)
One link (not important for this question)
One array of NSDictionary containing again 1 title and 1 link
I'm displaying this data in a view based table view like this:
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tv
{
if (tv == _downloadTable)
//I use this "if" because I have another tableView that has nothing to do
//with this one
{
return [[myDictionary objectForKey:#"myArray"] count];
}
}
I want 2 columns in this tableView, one to display the title and one with a checkbox, that would do something letting me know which row is checked.
- (NSView *)tableView:(NSTableView *)tv viewForTableColumn :(NSTableColumn *)tableColumn row :(NSInteger)row
{
if (tv == _downloadTable)
{
if (tableColumn == _downloadTableTitleColumn)
{
if ([[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"])
{
NSString *title = [[[myDictionary objectForKey:#"myArray"]objectAtIndex:row]objectForKey:#"title"];
NSTableCellView *result = [tv makeViewWithIdentifier:tableColumn.identifier owner:self];
result.textField.stringValue = title;
return result;
}
}
if (tableColumn == _downloadTableCheckColumn)
{
NSLog(#"CheckBox"); //I wanted to see exactly when that was called
//But it didn't help me :(
NSButton *button = [[NSButton alloc]init];
[button setButtonType:NSSwitchButton];
[button setTitle:#""];
return button;
}
}
}
Right now when I run it and click on the checkbox it does nothing
(of course because I don't know how to make it do something.
Where should I put the code that should do something?
The main goal is an editable list of downloads, right now the list is displayed, with the checkbox right next to the title at each lines.
I would like to know which checkBox are checked and which are not.
I tried this:
[button setAction:#selector(checkBoxAction:)];
- (void)checkBoxAction: (id)sender
{
NSLog(#"I am button : %# and my state is %ld", sender, (long)[sender state]);
}
But I can't figure out how to get the row of that button, to know which title is associated with this checkBox.
I also tried the setObjectValue method of the tableView without success.
The way I would like it to work is:
I have a "start downloading" button that check if each checkbox is checked or not and launch the next action (downloading) only with the checked row.
I would like to avoid bindings because I plan to make it work on iOS too and I don't want to have different code for iOS.
You can use the NSTableView method -rowForView: to get the row a particular view is in.
In your case you'd have something like this:
- (void)checkBoxAction:(id)sender
{
NSInteger row = [_downloadTable rowForView:sender];
NSLog(#"The button at row %ld was clicked.", row);
}
Here are the docs for NSTableView: https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
You could try using the button' tag property setting it for each button you place as the number (location) in the tableview. Look here!!!
Detecting which UIButton was pressed in a UITableView
[EDIT1]
If people actually decided to read the linked post you would realize that the answer is actually there.
Try adding:
[button setTag:row];
[button addTarget:self action:#selector(checkBoxAction:) forControlEvents:UIControlEventTouchUpInside];
inside the else of your viewForTableColumn routine:
In your checkBoxAction routine:
- (void)checkBoxAction: (id)sender{
NSLog(#"I am button : %# and my state is %#", sender.tag, [sender state]);
}
I also think that once you begin digging further into your code, you are going to want to start using the auto-dequeuing capability of the TableViewCell objects. I believe that you are going to find yourself in a memory alloc/dealloc problem.

In Objective-c, detecting when all of a variable number of UIButton have been pressed

I have a quick question about the best method to check if all of my UIButtons have been pressed.
I have x number of UIButtons which I created programmatically.
Each button has its own unique tag (starting at 100 and incrementing upwards.)
When you click on a button is runs this:
- (void)myButtonAction:(id)sender
{
[self handleButton:sender];
}
- (void)handleButton:(UIButton *)button
{
// ???
}
If and only if the user has clicked on all buttons do a want an instance [self allButtonsClicked] to run.
What is the best way to do this? Should I make a NSMutableArray, and check to see if the tag number is in the NSMutableArray and if it is not, then add it.
And then when the NSMutableArray is equal in size to the x number of buttons then run [self allButtonsClicked].
What is the simplest method to make sure each and every button has been clicked?
*edit I figured it out after typing it out. Writing it out helped me get it.
-(void)letterreveal: (id)sender {
//data
UIButton *button = (UIButton *)sender;
//action
[self clickcheck:[NSNumber numberWithInt:button.tag]];
}
-(void)clickcheck:(NSNumber*)currenttag {
if ([self.buttonPressCounts containsObject:currenttag]) {
NSLog(#"case A");
}
else {
[self.buttonPressCounts addObject:currenttag];
NSLog(#"case B");
if([self.buttonPressCounts count]==[self.currentword length])
{
NSLog(#"fininshed");
}
}
}
buttonPressCounts is a NSMutablearray.
I just had to make sure to set it whenI made the buttons.
self.buttonPressCounts = [NSMutableArray arrayWithCapacity:[self.currentword length]];
currentword is a NSString (each button is a letter derived from the NSString).
You could create an NSMutableSet with all buttons and then remove each clicked button from that set until it is empty. Once the set is empty, you have certainly clicked all buttons.
If you dont mind, if a button was pressed once or more often, use a member ivar of NSMutableSet.
And I would use a number of the tag, but add /remove the button itself.

How to put score in label on second screen after NSTimer?

I have a file (.m) wich is counting the clicks on a button
counter=counter +1;
count.text = [NSString stringWithFormat:#"%i",counter];
After a NSTimer a new screen appears (a new .m / .h / .xib file) but i want the score (clicks on button) in a label on the new screen.
On the first screen header file i'm doing:
IBOutlet UILabel *count;
but after the NStimer countdown i want to display to score on the new screen (screen 2)
Does anyone know how i can do this?
Need some more information? Please ask me!
In your randomMainVoid: action set the property of the label before you push the second view.
I don't know the name of your secondViewController and what you named the label in the secondViewController, so I can't give you exact code here.
Can you tell me what those names are and I will post the code here for you.
You should always name your ViewControllers with a Capital letter like Score, not score. But in either case:
Score *scoreView = [[Score alloc]initWithNibName:#"Score" bundle:nil];
[scoreView.count setText:count.text]; //Replace this with the text you want to pass
[self presentModalViewController:scoreView animated:YES];
Or if your using a NavigationController you could push the view onto the stack:
[self.navigationController pushViewController:scoreView animated:YES];
So, how are you initializing your timer? I assume you are using something like...
timerWithTimeInterval:target:selector:userInfo:repeats:
This method takes a selector, which is called when the timer expires/fires. In this method you should be displaying your view and you can pass the count to the new view you are creating. When your view loads you can set the count to a label on the view.
Just give your second view controller an initializer like:
- (id)initWithScoreText:(NSString*)scoreText {
if ((self = [super initWithNibName:#"MyNibName" bundle:nil])) {
scoreLabelText = [scoreText copy];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
//set the text of the label
scoreLabel.text = scoreLabelText;
}
- (void) dealloc {
//release the string since we copied it
[scoreLabelText release];
[super dealloc];
}
Then in your first view controller, you would do something like:
SecondViewController* newController = [[[SecondViewController alloc] initWithScoreText:count.text] autorelease];
[self.navigationController pushViewController:newController animated:YES];
Edit: updated based on feedback from Paul.s.