So I have been trying to get help with this from other users, but we can never get anywhere, my syntax and code looks good but no matter what I can not get rid of "undecared identifier" error when trying to call my button's method. Im starting to think it is a issue of global/vs not global. Here is my code and my errors
UIButton *add = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[add addTarget:self
action:#selector(aMethod:)forControlEvents:UIControlEventTouchDown];
[add setTitle:#"add new" forState:UIControlStateNormal];
add.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:add];
- (void) aMethod:(id)sender
{
button[0].backgroundColor = [UIColor greenColor];
}
This is all my code for that button in my ViewController.m file... I have 1 warning and 1 error. My warning is
"method definition for 'aMethod' not found"
And this error is tagged under the line "#implementation ViewController" near the top of my code.
My error is
Use of undeclared identifier 'aMethod'
And this is tagged under my "-(void) aMethod: (id)sender"
And I have this in my ViewController.H file
- (void)aMethod;
No erros with that.. I have tried to get help with this before and I keep getting tips and edits that have to do with my programming syntax, But NO MATTER WHAT, i cant get rid of these errors. Is there anything else that could be wrong? Would it be helpful to see the rest of my program? And there is one more piece of info that could be of use. My entire program is written after one of initial lines that xcode sets me up with,
- (void)viewDidLoad
{
//my entire program is between these brackets.
}
When I try this code "-(void) aMethod: (id)sender{ }" before "viewdidload" i dont get an error. but when i put it after "-(void) aMethod: (id)sender{ }" i get the error. I figured that out when i was messing around trying to figure out what's wrong. Let me know if more info is needed. And by the way, i am trying to do it all programmatically, without ever using storyboard...Thank you so much in advance!!
change this in your .h file:
- (void)aMethod;
to this:
- (void)aMethod:(id)sender;
The actual method in your view controller (the .m file) should match this signature.
The "method definition for 'aMethod' not found" is not referring to your button but the fact you have defined the method aMethod in your header but you haven't implemented it in your implementation because you instead have -(void)aMethod:(id)sender;
edit:
Your code should look more like this:
-(void)viewDidLoad {
[super viewDidLoad];
UIButton *add = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[add addTarget:self action:#selector(aMethod:)forControlEvents:UIControlEventTouchDown];
[add setTitle:#"add new" forState:UIControlStateNormal];
add.frame = CGRectMake(100, 100, 100, 100);
[self.view addSubview:add];
}
- (void) aMethod:(id)sender {
button[0].backgroundColor = [UIColor greenColor];
}
Related
I've got the following button written programmatically:
self.button = [[UIButton alloc] init];
[self.button setTitle:#"Reverse String!" forState:UIControlStateNormal];
self.button.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1.0];
self.button.layer.cornerRadius = 5.0;
[self.button addTarget:self action:#selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];
However, my unit test fails when I try to test:
-(void)testButtonActionAssigned
{
XCTAssert([self.vc.button respondsToSelector:#selector(reverseString:)]);
}
I get a failed message saying:
test failure: -[ViewControllerTests testButtonActionAssigned] failed:
(([self.vc.button respondsToSelector:#selector(reverseString:)]) is
true) failed
My setup method is called:
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.vc = [[ViewController alloc] init];
NSLog(#"THIS METHOD IS CALLED");
}
Is it to do with the simulator timing and startup ?
[self.button addTarget:self action:#selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];
First line means that reverseString: method should be in your ViewController (which is specified by target: parameter and you pass self there). So you need to change test with just removing .button
-(void)testButtonActionAssigned
{
XCTAssert([self.vc respondsToSelector:#selector(reverseString:)]);
}
Here is small example which can be changed:
UIButton *button = [UIButton new];
[button addTarget:self action:#selector(doThat:) forControlEvents:UIControlEventTouchUpInside];
NSString *selectorString = [[button actionsForTarget:self forControlEvent:UIControlEventTouchUpInside] firstObject];
SEL sel = NSSelectorFromString(selectorString);
// so now you can check if target responds to selector
// BOOL responds = [self respondsToSelector:sel];
NSLog(#"%#", selectorString);
I got it. I was testing the wrong thing.
The code in the question isn't really testing the button has an action assigned. It's basically saying "does the view controller responds to this method" or "does the view controller have this method".
// this is saying "does the ViewController know about this method"
// rather than "is ViewController's button assigned method reverseString:"
XCTAssert([self.vc respondsToSelector:...]);
This means regardless of whether button has a selector assigned or not, as long as the method is defined, this assert is always true.
I verified it by commenting out the line of code:
[self.button addTarget:self action:#selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];
and the test still passes, which isn't what I was trying to achieve.
The proper test should be:
-(void)testButtonActionAssigned
{
[self.vc viewDidLoad];
NSArray *arrSelectors = [self.vc.button actionsForTarget:self.vc forControlEvent:UIControlEventTouchUpInside];
NSString *selector = nil;
if(arrSelectors.count > 0)
{
selector = arrSelectors[0];
}
XCTAssert([selector isEqualToString:#"reverseString:"]);
}
Now after commenting out the line:
[self.button addTarget:self action:#selector(reverseString:) forControlEvents:UIControlEventTouchUpInside];
The test fails as expected :D
This proper test code fetches the selector from the button and checks to see if it indeed is the method called reverseString:
EDIT
After B.S. answer, and confirming with Apple's documentation, a shorter version can be written as:
-(void)testButtonActionAssigned
{
[self.vc viewDidLoad];
NSString *selector = [[self.vc.button actionsForTarget:self.vc forControlEvent:UIControlEventTouchUpInside] firstObject];
XCTAssert([selector isEqualToString:#"reverseString:"]);
}
I was originally worried that calling firstObject on an empty array would cause an app to crash but Apple's documentation has confirmed to me that firstObject is a property that returns nil if array is empty.
The first object in the array. (read-only)
Declaration #property(nonatomic, readonly) ObjectType firstObject
Discussion If the array is empty, returns nil.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/#//apple_ref/occ/instp/NSArray/firstObject
This button is declared in my base class:
{
// Setup done button for tool bar
UIButton *doneButton = [[UIButton alloc] initWithFrame:CGRectMake(170, 3, 110, 38)];
[doneButton setBackgroundColor:[UIColor blackColor]];
[doneButton setTitle:#"Done" forState:UIControlStateNormal];
[doneButton addTarget:_thisController action:#selector(doneButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
return doneButton;
}
Notice this line:
[doneButton addTarget:_thisController action:#selector(doneButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
The "doneButtonTapped:" method is only used in each sub class of my base class and never in the base class itself.
To avoid a warning in the base class I have to at least define the method:
- (void)doneButtonTapped:(id)sender {
}
Question:
Is there a way to avoid declaring the empty method and not get warnings?
Are blank methods like above a problem?
I know I could addTarget for the selector in each of the sub classes but there are quite a few of them. I just thought leaving everything in the doneButtonTapped method would be easier.
There is a way ;) :
NSString *stringMethod = #"doneButtonTapped:";
[doneButton addTarget:self action:NSSelectorFromString(stringMethod) forControlEvents:UIControlEventTouchUpInside];
In this way you can also change your method at runtime before create the button, just changing the string. And the warning so, are not shown in pre-compile time.
So, enjoy! ;)
I've just started learning the basics of Xcode and Objective C and I am making a basic torch app as a starting point.
I've already picked up most of the basics of things, but I don't know how to make a reference to another element from an separate action (I have no idea if this terminology is correct).
For example:
- (IBAction)screenButtonClicked:(id)sender {
UIButton *button = (UIButton *)sender;
if (_ScreenOnOff) {
[self.view setBackgroundColor:[UIColor blackColor]];
[button setTitle:#"Screen (Off)" forState: UIControlStateNormal];
}
else {
[self.view setBackgroundColor:[UIColor whiteColor]];
[button setTitle:#"Screen (On)" forState: UIControlStateNormal];
}
_ScreenOnOff = !_ScreenOnOff;
}
I have a button on the storyboard which is linked to that, and I have a UIImageView which I want to show and hide (depending on the if's).
I've looked everywhere about how to do this and put it as many ways as I can into Google, but no luck.
This might be a baby step in Objective C, but please help as it will teach me.
Thanks in advance.
Declare an IBOutlet for the UIImageView in the header file:
#property (weak) IBOutlet UIImageView *myImageView;
After that, connect the UIImageView to this IBOutlet in Interface Builder.
Then, you can reference (and hide it) like:
self.myImageView.hidden = _ScreenOnOff;
in your implementation file.
See also: Creating and Connecting an Outlet
This action is probably owned by your view controller. If your view controller has a UIImageView property named 'imageView' you can access it from inside your action just like you're doing with the _ScreenOnOff.
To hide your image view you could do something like this:
self.imageView.hidden = YES;
Note that it is important to use self.imageView and self.ScreenOnOff instead of accessing directly the property by _imageView. When you declare a property in your class (be it an IBOutlet or not) the compiler synthesizes accessor methods to that property (get and sets). So when you call self.ScreenOnOff it would be the similar of doing [self ScreenOnOff].
The only places where you will access the property directly by '_' is inside init and dealloc methods. '- (void) viewDidLoad' is on type of init method. I guess you want something like this:
- (IBAction)screenButtonClicked:(id)sender {
UIButton *button = (UIButton *)sender;
if (self.ScreenOnOff) {
[self.view setBackgroundColor:[UIColor blackColor]];
[button setTitle:#"Screen (Off)" forState: UIControlStateNormal];
self.imageView.hidden = YES;
}
else {
[self.view setBackgroundColor:[UIColor whiteColor]];
[button setTitle:#"Screen (On)" forState: UIControlStateNormal];
self.imageView.hidden = NO;
}
self.ScreenOnOff = !self.ScreenOnOff;
}
I hope that helps.
I am trying to add a button to a view programmatically and i am using the following code:
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:#"Click Me" forState:UIControlStateNormal];
[button addTarget:self action:#selector(click:) forControlEvents:UIControlEventTouchDown];
[button setFrame:CGRectMake(50, 20, 80, 70)];
[self addButton:button];
according to me code looks right but i am getting error "Unknown action click"
addbutton and click is the method of the same class
and i am adding the buttons in my constructor
what's the problem with the click method? is there any syntax error!
Your problem is that you have a method named click but your are telling your button that the method is named click:. Notice the difference (the colon).
Change the #selector to #seletor(click) so it matches the actual method name.
Another option is to leave the #selector as-is but update your click method to click::
- (void)click:(UIButton *)button {
// button was tapped - do something
}
A sample how to add a action to a button ....
UIButton *button = [UIButton buttonWithTypeRoundRect];
[button addTarget:self action:#selector(myMethod) forControlEvents:UIControlEventTouchUpInside];
button.frame = CGRectMake(10,10,100,50);
//Do some more Configuration of the button like title.. Look at UIButton Class Reference
[self.view addSubview:button];
SomeTimes you see a small colon(:) after the method name in the selector something like this #selector(myMethod:)
which means this method takes some argument. the colon plays no role in the name of the method. if you are not sending any argument to the function then don't put colon after the name of the function.....
In addtarget option you can see that self is specified because self contains myMethod function. Here you are supposed to specify the reference of that object which contains your Method.
change
- (void)click:(id)sender{ NSLog(#"Button Clicked"); }
or change action click: to click
[button addTarget:self action:#selector(click) forControlEvents:UIControlEventTouchUpInside];
hi just simply try this -(void)click { // do what ever } i.e just remove colon in #selector(click:) hope it will work
How do I set a tag for a button programmatically?
I later want to compare to tags for a conclusion
I've tried this
-(IBAction)buttonPressed:(id)sender{
NSLog(#"%d", [sender tag]);
}
but that just crashes the app.
Any other ideas?
You need to cast sender as a UIButton:
-(IBAction)buttonPressed:(id)sender{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", [button tag]);
}
Edit: Regarding the message "unrecognized selector"...
Based on your error message, it's not able to call the buttonPressed method in the first place. Notice in the error message it is looking for "buttonPressed" (no colon at end) but the method is named "buttonPressed:". If you are setting the button target in code, make sure the selector is set to buttonPressed: instead of just buttonPressed. If you are setting the target in IB, the xib may be out of sync with the code.
Also, your original code "[sender tag]" should also work but to access button-specific properties, you'll still need to cast it to UIButton.
I know this is an old question and been answered many a time in other questions, but it came up in a google search as second from the top. So, here is the answer to why it was crashing. Change it to 'button.tag'
-(void)myMethod
{
UIButton *theButton = [UIButton buttonWithType:UIButtonTypeCustom];
[theButton addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchDown];
theButton.tag = i;//or whatever value you want. In my case it was in a forloop
}
-(void)buttonPressed:(id)sender
{
UIButton *button = (UIButton *)sender;
NSLog(#"%d", button.tag);
}
No need for casting. This should work:
-(IBAction)buttonPressed:(UIButton*)sender
{
NSLog(#"%d", [sender tag]);
}