Selector with argument - iphone

I have a method like this:
- (void)methodWithParameter:(id)parameter {
}
and I want to call it using an UIBarButtonItem
barButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(methodWithParameter:)];
I want to specify the parameter but I can't use withObject: after action: because I get a warning:
No -initWithBarButtonSystemItem:target:action:withObject: method found
can anybody help me with this?

It doesn't work that way. You cannot pass a parameter to an action. An action method will always have either:
no arguments at all,
one argument (id)sender,
or two arguments (id)sender and (UIEvent *)event.

Related

Arguments with NSTimers

Is it possible to give an argument in a method when setting a NSTimer? I want to create something like the following:
[NSTimer [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(moveParticle:imageView) userInfo:nil repeats:YES];
Where "imageView" is the argument of the method. It gives me a error saying the it's expecting a semi-colon right after the parathesis after "imageView".
Any help?
You want to use the userInfo to send arguments. Look at the documentation on how to use it. You will just make your function take a single NSTimer argument then the timer will return itself and you can read its userInfo dictionary.
That's what the userInfo parameter is for. You can pass your imageView as userInfo and cast it to the desired type (NSView?) in the method you provide as selector.
e.g.:
- (void)moveParticle:(NSTimer*)theTimer
{
NSView* imageView = (NSView*)[theTimer userInfo);
...
}
Another approach (probably more useful here - as your target is self), would be to make the imageView an iVar and access that within moveParticle.
See duplicate thread :
You'll need to used +[NSTimer scheduledTimerWithTimeInterval:invocation:repeats:] instead. By default, the selector used to fire a timer takes one parameter. If you need something other than that, you have to create an NSInvocation object, which the timer will use instead.
An example :
NSMethodSignature * mSig = [NSMutableArray instanceMethodSignatureForSelector:#selector(moveParticle:)];
NSInvocation * myInvocation = [NSInvocation invocationWithMethodSignature:mSig];
[myInvocation setTarget:myArray];
[myInvocation setSelector:#selector(moveParticle:)];
[myInvocation setArgument:&imageView atIndex:2]; // Index 2 because first two arguments are hidden arguments (self and _cmd). The argument has to be a pointer, so don't forget the ampersand!
NSTimer *myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 invocation:myInvocation repeats:true];

#selector to a function in a separate class

If I have a function that is defined in class Foo, and my class Bar has a reference to class Foo, can I use the #selector to call that function? Something like
#selector([Foo someFunctionInFoo:])
I have only used the #selector to call functions in the same class. I tried doing something similar to the above code, but it didn't work and I wasn't sure if it was even possible. Thanks.
#selector doesn't store any calls information, just the selector.
[Foo performSelector:#selector(someFunctionInFoo:) withObject:nil];
You can also do:
Class class = SomeClass;
id obj = [class someObject];
SEL sel = #selector(someFunction);
[class performSelector:sel];
[obj performSelector:sel];
As long as both implement someFunction.
To specify which target is used by buttons etc you set the target and the action as two properties, e.g.:
[[UIBarButtonItem alloc] initWithTitle:#"Filter"
style:UIBarButtonItemStyleBordered
target:foo // The object to send the message to
action:#selector(someFunctionInFoo:)]; // The message to send

Return customized UIButton in method?

I have a method that takes a UIButton, modifies its properties and returns a UIButton. However, it doesn't ever seem to be initialized. I'm sure I'm doing something wrong with the memory management here, but don't exactly know how to fix it. No runtime errors occur.
It is called like so...
newGameBtn = [self customButtonFromButton:newGameBtn
withText:[NSString stringWithFormat:#"NEW GAME"]
withFontSize:22
withBorderColor:[UIColor orangeColor]
isSilent:YES];
[dashboardContainer addSubview:newGameBtn];
The method is defined as follows...
- (UIButton*) customButtonFromButton:(UIButton*)button withText:(NSString*)text withFontSize:(int)fontSize withBorderColor:(UIColor*)borderColor isSilent:(BOOL)isSilent {
button = [[[UIButton alloc] init] autorelease];
// Set properties from parameters
// Other conditional custom stuff here
return button;
}
NOTE: newGameBtn is of type UIButton* and is initialized with:
newGameBtn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
Another option might be to subclass UIButton, but I figured I'd try to fix this since I've already walked down this path.
You should use +[UIButton buttonWithType:] when creating buttons to get a properly initialized button.
Most classes are not properly initialized by the default -[NSObject init] method. So please look at the class reference, or superclass reference, for a usable initialization method.
In this case you should also set a frame.
You don't modify this button with your method, you're creating a completely new one with alloc-init!
If you want to change the button in your first argument just remove the first line of your method

Simple #selector Syntax Error

This seems to be the simplest of problems... yet I can't figure out what's syntactically incorrect with this snippet.
Running this:
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:appDelegate action:#selector(addImage:NO)];
Returns:
Expected '(' before ')' token
I've looked it over hundreds of times, yet I can't find what's wrong with it. Thanks for any assistance.
You can't have NO in your #selector() directive.
Be careful. UI Actions selectors should have the method signature:
- (void)myMethod:(id)sender;
and not
- (void)myMethod:(BOOL)someBool;
You may need a wrapper method:
- (void)doneAction:(id)sender;
{
[appDelegate addAction:NO];
}
#selector() can't accept default values, change it to
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:appDelegate action:#selector(addImage:)];
Edit:
To make things clear, when you have
- (void)addImage:(BOOL)resize;
this is translated to "addImage:" as "method" name (selector) and when you pass over "addImage:NO" you are telling objc to look
- (void)addImage:(BOOL)resize NO:(BOOL)nod; // just for the example
ending up with wrong (invalid) selector, resulting in double back trace to all super objects calling respondsToSelector(addImage:NO) then throwing BAD_ACCESS.
p.s. Its more then year since I wrote my last line of objc.
Edit 2:
You can use wrapper as mentioned above or UIBarButtonItem.tag property
cancelButton.tag = 1; // 1 indicating addImage:NO
- (void) addImage:(id)sender {
UIBarButtonItem *button = (UIBarButtonItem *)sender;
if (button.tag == 1) {
// your value is NO
} else {
// your value is YES
}
}
but I would not go with this anyway. :)

perform:#selector using a method with parameters

I have a method hideButton
-(void) hideButton:(UIButton) *button {
[button setHidden:YES];
}
and I get a "can not use an object as parameter to a method" error.
I want to be able to give the button as a parameter to the method when calling this
[self performSelector:#selector(hideButton:smallestMonster1)
withObject:nil afterDelay:1.0];
How can this be done? as the above attempt doesnt work. I need to be able to give the button as a parameter or at least make the method aware of which button is calling to be hidden after 1 second.
Thanks
You can pass parameter to selector via withObject parameter:
[self performSelector:#selector(hideButton:) withObject:smallestMonster1 afterDelay:1.0];
Note that you can pass at most 1 parameter this way. If you need to pass more parameters you will need to use NSInvocation class for that.
Edit: Correct method declaration:
-(void) hideButton:(UIButton*) button
You must put parameter type inside (). Your hideButton method receives pointer to UIButton, so you should put UIButton* there