1

I have a custom UITableViewCell with multiple buttons. I would like to remember whether the buttons are in the selected or unselected state and store that in a property of a custom core data model class. There are multiple custom UITableViewCells, and each has a different number of buttons.

The buttons are cleverly named as a string: 1,2,3...

To explain the project: imagine a teacher that wanted to keep track of the number of chapters read by a student for a list of books. The goal is to track the total number of chapters read for each student. Each book is a UITableViewCell. Each book has a unique number of chapters. The teacher (or student) selects a button when each chapter is read. The chapter read would be saved as a property so that it could be presented as such the next time the UITableViewCell displayed.

#import "Student.h"

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
    // Initialization code
    chaptersInBook = 16;
    self.dickensArray = [NSMutableArray array];

    // Book title
    UILabel *bookLabel = [[UILabel alloc]initWithFrame:CGRectMake(20, 10, 100, 30)];
    bookLabel.text = @"David Copperfield";

    for (NSInteger index = 0; index < chaptersInBook; index++) // for loop runs 16 times
    {
        // Need to make correct number of buttons based on the chapters in each book
        UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 
        button.tag = index;
        //buttons in rows of seven
        button.frame = CGRectMake(40*(index%7) + 20,40 * (index/7) + 40, 30, 30);
        [button setTitle:[NSString stringWithFormat:@"%d", index+1] forState:UIControlStateNormal];

        [button setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.png",index+1]] forState:UIControlStateNormal];
        [button setTitle:[NSString stringWithFormat:@"%d", index+1] forState:UIControlStateNormal];
        [button setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateSelected];
        [button addTarget:self action:@selector(toggleOnOff:) forControlEvents:UIControlEventTouchUpInside];
        [button addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];

        [self.contentView addSubview:button];
        [self.contentView addSubview:bookLabel];
    }
}
return self;
}


-(IBAction)toggleOnOff:(id)sender
{
UIButton *button = (UIButton *)sender;
button.selected = !button.selected; // In storyboard the default image and selected image are set
}


-(IBAction)buttonPressed:(id)sender {
    UIButton* button = (UIButton *)sender;
    if (button.selected) {
      int chapter = button.tag + 1;
      NSString *nameOfButton = [NSString stringWithFormat:@"%d",chapter];
      NSString *buttonIsSelected = @"YES";


//Now I want to set student.ch1 to yes but I want to set the '1' to 'chapter'
//Not sure how to do this: append the name of a property with a variable.


}

So, my question is, how best to store the button state into the student property for the selected chapter? I wish I could append the chapter number to the 'student.ch[append chapter number here]', but I don't think that is possible.

//eg.
student.ch1 = [NSNumber numberWithBool:YES];//but replace '1' with the value in the int variable 'chapter'

Thank you in advance. I think I'm barking up the wrong tree.

Kurt

Rodrigo Guedes
  • 1,169
  • 2
  • 13
  • 27
Kurt
  • 855
  • 2
  • 12
  • 22
  • Is there a limit on the number of buttons, say, 32 or 64? – Sergey Kalinichenko Aug 21 '12 at 17:37
  • I think the most number of buttons is 28. Why? – Kurt Aug 21 '12 at 17:42
  • possible duplicate of [Objective C Equivalent of PHP's "Variable Variables"](http://stackoverflow.com/questions/2283374/objective-c-equivalent-of-phps-variable-variables), [Create variables based on an int count](http://stackoverflow.com/questions/2231783/create-multiple-variables-based-on-an-int-count/), [Variable as object name](http://stackoverflow.com/questions/7940809/syntax-help-variable-as-object-name) – jscs Aug 21 '12 at 18:15

2 Answers2

1

Since the number of buttons is small (you indicated 28 in the comment), you can use powers of two as tags on your buttons, and use an integer bitmask to store the state of all 28 buttons in a single integer field.

Consider this example with four buttons (you can expand it to 32 without much changes). Tag your buttons as follows:

button1.tag = 0x01; // Binary 0001
button2.tag = 0x02; // Binary 0010
button3.tag = 0x04; // Binary 0100
button4.tag = 0x08; // Binary 1000

When a button is selected, bitwise-OR its tag with the current state:

NSUInteger currentState = 0;
...
currentState |= button.tag;

When a button is un-selected, bitwise-AND its tag's inverse with the current state:

currentState &= ~button.tag;

To toggle the state, you can XOR the tag with the current state:

currentState ^= button.tag;

When you need to re-apply the selected/not selected state to your buttons, you can do it in a loop like this:

for (int i = 0 ; i != 28 ; i++) {
    NSUInteger tag = 1<<i;
    if (storedState & tag) {
        UIButton *btn = [myView viewWithTag:tag];
        // ... make the button selected ...
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Thank you so much. It will take me awhile to digest. I found this link that is helpful. I have never used an integer bitmask before. http://stackoverflow.com/questions/3427585/understanding-the-bitwise-and-operator – Kurt Aug 21 '12 at 18:10
  • @Kurt You are welcome! Bit masks are very useful, and they aren't all that hard. They are excellent for representing small sets of objects, too, because of their speed and compactness. – Sergey Kalinichenko Aug 21 '12 at 18:13
  • I'm trying to name and tag my buttons with a for loop. Using my example above, how do I name the tag with '0x'? I can use the pow function with my index to get the power of two. If it were a string I could append, but since it is an int, I'm not sure how. – Kurt Aug 21 '12 at 20:22
  • @Kurt Powers of two in integers are easily obtained by shifting `1` to the left the number of times equal to the power to which you're raising `2`. It is the same as obtaining powers of ten by writing zeros to the right of `1`. So `2` to the power of `4` is `1<<4`, `2` to the power of `5` is `1<<5`, and so on. – Sergey Kalinichenko Aug 21 '12 at 20:26
  • This is really very cool. Thank you again. I just have a few bugs to work out. – Kurt Aug 21 '12 at 22:49
  • I got this working nicely. Thank you. For future reference, is there a limit to the number of chapters? – Kurt Aug 23 '12 at 04:12
  • @Kurt If you use an `int`, the limit is 31; for `unsigned int` its 32. You can expand to 63/64 by using `long long` or `unsigned long long`. – Sergey Kalinichenko Aug 23 '12 at 04:14
  • I just wanted to add, that if you use Core Data to store the storedState, make sure to use Integer 32 as the type for the attribute for any button numbers greater than 16. I assume that you should use Integer 64 as the type for numbers greater than 32. Thanks again dasblinkenlight. – Kurt Aug 28 '12 at 23:16
0

If I got your question right, it is easy to answer: Have a look at Key-Value-Coding - that should help you!

http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/KeyValueCoding/Articles/KeyValueCoding.html

Steffen Blass
  • 276
  • 1
  • 4