Reputation: 6223
My appDelegate, in the method didFinishLaunchingWithOptions I load my view controller then create a singleton:
UIViewController *MainWinVC = [[p3VC alloc] init];
[[self window] setRootViewController:MainWinVC];
ansButSingleton *ansButs = [[ansButSingleton alloc] init];
ansButSingleton.h looks like this:
#import <Foundation/Foundation.h>
@interface ansButSingleton : NSObject {
// View objects:
UIButton *Ans1;
UIButton *Ans2;
UIButton *Ans3;
UIButton *Ans4;
UIButton *Ans5;
UIButton *Ans6;
UIButton *Ans7;
UIButton *Ans8;
// Other objects:
NSArray *ansButs;
}
@property (strong) UIButton *Ans1, *Ans2, *Ans3, *Ans4, *Ans5, *Ans6, *Ans7, *Ans8;
@property (strong) NSArray *ansButs;
+ (ansButSingleton *) ansButsName; // Declare class method
@end
and ansButSingleton.m like this:
#import "ansButSingleton.h"
@implementation ansButSingleton
static ansButSingleton *ansButsName;
@synthesize Ans1, Ans2, Ans3, Ans4, Ans5, Ans6, Ans7, Ans8;
@synthesize ansButs;
//////////////////// instantiate ////////////////////
+ (ansButSingleton *) ansButsName { // class method
@synchronized(self)
{
if (!ansButsName)
ansButsName = [[ansButSingleton alloc] init];
return ansButsName;
}
}
//////////////////// initialize ////////////////////
- (id)init { // class instance method
NSLog(@"Initializing answer buttons");
if (ansButsName) {
return ansButsName;
}
self = [super init];
if(self) {
// First initialze the individual buttons
self.Ans1 = [[UIButton alloc] init];
[Ans1 setTitle:@"" forState:UIControlStateNormal];
self.Ans2 = [[UIButton alloc] init];
[Ans2 setTitle:@"" forState:UIControlStateNormal];
self.Ans3 = [[UIButton alloc] init];
[Ans3 setTitle:@"" forState:UIControlStateNormal];
self.Ans4 = [[UIButton alloc] init];
[Ans4 setTitle:@"" forState:UIControlStateNormal];
self.Ans5 = [[UIButton alloc] init];
[Ans5 setTitle:@"" forState:UIControlStateNormal];
self.Ans6 = [[UIButton alloc] init];
[Ans6 setTitle:@"" forState:UIControlStateNormal];
self.Ans7 = [[UIButton alloc] init];
[Ans7 setTitle:@"" forState:UIControlStateNormal];
self.Ans8 = [[UIButton alloc] init];
[Ans8 setTitle:@"" forState:UIControlStateNormal];
// Make an array containing the objects: this is the objective-C way!
self.ansButs = [[NSArray alloc] initWithObjects: Ans1, Ans2, Ans3, Ans4, Ans5, Ans6, Ans7, Ans8, nil];
}
NSLog(@"Done initializing answer buttons");
return self;
}
@end
This builds and runs fine (it doesn't do much yet). The buttons are visible due to the successful loading of the nib. However, they are not active since I haven't connected them to the code (no IBActions).
Question: How do I connect buttons created this way to the buttons in the nib? If these were simple buttons (not an array of buttons) I would create a method and use IBAction as part of that method declaration. But this case seems a bit different. Or maybe not. If these were labels (which I also need to do later), my reading leads me to believe IBOutletCollection might work, but there is no IBActionCollection that I can see. Expert guidance needed! Thanks.
EDIT ... working with Rob to implement his ideas. My viewLoad method was copied and pasted from yours, but maybe there was something in it I needed to change?
#pragma mark - View lifecycle
- (void)loadView {
NSDictionary *externals = [NSDictionary dictionaryWithObject:[AnswerButtons answerButtons]
forKey:@"answerButtons"];
NSDictionary *nibOptions = [NSDictionary dictionaryWithObject:externals
forKey:UINibExternalObjects];
[self.nibBundle loadNibNamed:self.nibName owner:self options:nibOptions];
[[AnswerButtons answerButtons] buttonsDidLoad];
}
Upvotes: 1
Views: 781
Reputation: 373
To connect the buttons to interface builder, you'd have to place "IBOutlet" before the UIButton in each one of your variable declarations.
IBOutlet UIButton * Ans1;
Then in interface builder, you can right click and drag from view controller onto the button and select the right button. Then if you wanted to have each button perform a method, you should declare an IBAction method in your .h file:
-(IBAction)doButtonStuff:(id)sender;
Then to hook up the act to each button in interface builder, go to interface builder and right click and drag from the button to view controller and select what method you want to associate it with. Typically using interface builder is quick and easy but if you want to do some extra behind the scenes stuff, you can use the code whitelion posted. Also, just a side note, to use less code when setting up your buttons, you can do a for each loop.
for (UIButton * button in ansButs) {
self.button = [[UIButton alloc] init];
[button setTitle:@"" forState:UIControlStateNormal];
}
This is a lot less code!!! You'd have to declare the array before this code and include all of the buttons in it.
Upvotes: 1
Reputation: 386018
There are a number of ways you could do this. I'd do it by hooking up the singleton's connections in the nib. Here's how.
First, let's fix up the singleton class to match iOS programming conventions and provide the support for wiring up the button connections in the nib:
#import <Foundation/Foundation.h>
@interface AnswerButtons : NSObject
@property (strong, nonatomic) IBOutlet UIButton *button1, *button2, *button3, *button4, *button5, *button6, *button7, *button8;
@property (strong, nonatomic, readonly) NSArray *buttons;
+ (AnswerButtons *)answerButtons;
- (void)buttonsDidLoad;
@end
#import "AnswerButtons.h"
@implementation AnswerButtons
@synthesize button1 = _button1;
@synthesize button2 = _button2;
@synthesize button3 = _button3;
@synthesize button4 = _button4;
@synthesize button5 = _button5;
@synthesize button6 = _button6;
@synthesize button7 = _button7;
@synthesize button8 = _button8;
@synthesize buttons = _buttons;
+ (AnswerButtons *)answerButtons {
static AnswerButtons *singleton;
static dispatch_once_t once;
dispatch_once(&once, ^{
singleton = [[AnswerButtons alloc] init];
});
return singleton;
}
- (void)buttonsDidLoad {
_buttons = [[NSArray alloc] initWithObjects:_button1, _button2, _button3, _button4, _button5, _button6, _button7, _button8, nil];
}
@end
Note that we create the singleton in the class method the first time the singleton is requested. Don't do it in application:didFinishLaunchingWithOptions:
.
Next, let's hook up the buttons in the nib:
p3VC
class. (You should consider changing this name to start with a capital letter and spell out ViewController
or just Controller
.)AnswerButtons
.answerButtons
.Finally, we need to provide the AnswerButtons
singleton to the nib loader when we load the nib. Edit p3VC.m
and give it a loadView
method:
- (void)loadView {
NSDictionary *externals = [NSDictionary dictionaryWithObject:[AnswerButtons answerButtons]
forKey:@"answerButtons"];
NSDictionary *nibOptions = [NSDictionary dictionaryWithObject:externals
forKey:UINibExternalObjects];
[self.nibBundle loadNibNamed:self.nibName owner:self options:nibOptions];
[[AnswerButtons answerButtons] buttonsDidLoad];
}
With this approach, you can also create IBAction
methods in the AnswerButtons
class and use the nib to connect the buttons to those actions.
Upvotes: 1
Reputation: 2227
Since UIButton
inherits from UIControl
you can use the method:
[yourButton1 addTarget:yourObject action:@selector(yourMethod) forControlEvents:UIControlEventTouchUpInside];
Hook that in the loop where the buttons are created and you are good to go. If you are adding the buttons from interface builder then you need to hook an IBOutlet
for each. Example: In your view controller init
:
self.Ans1 = [[UIButton alloc] init];
[Ans1 setTitle:@"" forState:UIControlStateNormal];
//set the action
[Ans1 addTarget:self action:@selector(yourMethod) forControlEvents:UIControlEventTouchUpInside];
Another way would be to create the IBAction
method for each button and hook that method to the method in the singleton, which in my opinion is much more clear.
Example: in your view controller:
-(IBAction) button1Press:(id)sender{
[yourSingleton button1Press];
}
Upvotes: 1