How can I pass a parameter to this function? - iphone

I have the following code:
[replyAllBtn addTarget:self.target action:#selector(ReplyAll:) forControlEvents:UIControlEventTouchUpInside];
- (void)replyAll:(NSInteger)tid {
// some code
}
How can I send a parameter to the ReplyAll function?

The replyAll method should accept (id)sender. If a UIButton fired the event, then that same UIButton will be passed as the sender. UIButton has a property "tag" that you can attach your own custom data to (much like .net winforms).
So you'd hook up your event with:
[replyAllBtn addTarget:self.target action:#selector(ReplyAll:) forControlEvents:UIControlEventTouchUpInside];
replyAllBtn.tag=15;
then handle it with:
(void) ReplyAll:(id)sender{
NSInteger *tid = ((UIControl*)sender).tag;
//...

A selector function will normally be defined as such:
- (void) ReplyAll:(id)sender;
So the only parameter an action will ever receives is the actual control that called it.
You could just add a property to your control that can be read in replyAll

If you want to send an int value, set the tag of the button = the int value you want to pass. Then you can access the tag value of the button to get the int you wanted.
NSInteger is not a pointer. Try this
NSInteger tid = sender.tag;

It's working now :D.
{
NSInteger tid = [sender tag];
}

The MVC model used in Cocoa works differently. Basically, the idea is that a control (=view) such as a button only lets a function know it was pressed, not knowing what this means. The function then has to know all the dynamics and dependencies. In your case, it's the function that has to find the parameter. To accomplish that, you'll "bind" other objects to the function (= controller).
I suggest you read a few Cocoa tutorials first if you want to get ahead with iPhone programming.

There's a few good ways to do this. The two most commonly implemented would be to have the controller (who's receiving the action) know about possible senders, or having the sender itself have a method that you end up using to determine the proper behavior.
The first (my preferable way, but it's easy to argue the opposite) would be implemented like such:
#interface Controller : NSObject {
UIButton *_replyToSender;
UIButton *_replyToAll;
}
- (void)buttonClicked:(id)sender;
#end
#implementation Controller
- (void)buttonClicked:(id)sender {
if (sender == _replyToSender) {
// reply to sender...
} else if (sender == _replyToAll) {
// reply to all...
}
}
#end
The second way would be implemented in a manner such as:
typedef enum {
ReplyButtonTypeSender = 1,
ReplyButtonTypeAll,
} ReplyButtonType;
#interface Controller : NSObject {
}
- (void)buttonClicked:(id)sender;
#end
#interface MyButton : UIButton {
}
- (ReplyButtonType)typeOfReply;
#end
#implementation Controller
- (void)buttonClicked:(id)sender {
// You aren't actually assured that sender is a MyButton, so the safest thing
// to do here is to check that it is one.
if ([sender isKindOfClass:[MyButton class]]) {
switch ([sender typeOfReply]) {
case ReplyButtonTypeSender:
// reply to sender...
break;
case ReplyButtonTypeAll:
// reply to all...
break;
}
}
}
#end

Related

How to Pass parameters in IBAction?

I am accessing IBAction programatically & want to pass two parameter with this IBAction call.
Can any one suggest easy way...
IBActions are usually called by user interface elements, and they can't have an arbitrary number of parameters.
If you want to call the action method programmatically, you could abuse the sender parameter by passing a dictionary as an argument, holding the actual arguments you want to pass, like so:
- (void) foo
{
[self myAction: [NSDictionary dictionaryWithObject: #"bar" forKey: #"baz"]];
}
However, I would recommend creating an additional method with two parameters; the IBAction can call it with arguments appropriate to the sender, and programmatically you can call it using whatever arguments you need. This would be a possible outline for the code:
// The atual "logic" method, doing sth interesting
- (void) foo: (NSString *) s bar: (NSInteger) i
{
// some code
}
- (IBAction) myAction: (id) sender
{
// can be invoked by a button, or any view action
if (sender == self.buttonX) {
[self foo: #"x" bar: 42];
}
if (sender == self.buttonY) {
[self foo: #"y" bar: 4];
}
}
- (void) methodCallingFooBarProgrammatically
{
[self foo: #"s" bar: 17];
}
You can pass an array in the IBAction method like this:
-(IBAction)method:(id)sender
{
[sender objectAtIndex:0];
}
or you can do it like this:
-(IBAction)methodName:(NSString *)stringName:(NSString*)stringName2
{
// You can pass an array and even a dictionary
}
IBAction method follow a spesific pattern either
- (IBAction)action:(id)sender;
or
- (IBAction)action:(id)sender forEvent:(UIEvent *)event;
where sender is the UI object that sends the event, and event being the UIEvent itself.
If you are not sending these arguments then you don't want an IBAction method. Define a normal method that takes the two arguments you want and if you IBAction methods need to call it as well then do that. IBAction methods are defined as IBAction so that interface builder can find them in your code, so there is no reason to define an IBAction method that does not follow the pattern above.
the IBAction methods could receive two parameters about the sender object and the touch event, you cannot "pass" anything, you can receive only these via:
- (IBAction)action
- (IBAction)action:(id)sender
- (IBAction)action:(id)sender forEvent:(UIEvent *)event
you could use only the sender's tag property to pass a custom identifier as NSInteger.
HERE IS THE POINT
everything else what you would like to "pass" must be exists on your Model layer already! if you know what it is...
therefore, you can reach your datas from the Model layer after you receive the action.

How to tell programmatically if a IBAction has been called by code or by user action

How can I tell programmatically if a IBAction has been called by code or by user action.
Eg
I have a method, -(IBAction)someMethodWithIts:(id)sender
which I have linked to a valueChanged on a UISegmentedControl.
It can be called by,
User changing segment
setting the selectedIndex in code
calling [self someMethodWithIts:foo];
Is there a way to distinguish if the call has come from the first way?
Cheers
Sam
If you can pass nil as the sender (which is traditional) and use that to indicate it was sent programmatically, that's ok. But anything else I believe is too fragile and you should break up the code like this:
- (void)someMethod {
// stuff shared by everyone
}
- (IBAction)someMethodWithIts:(id)sender {
// stuff specific to IBAction
[self someMethod];
}
If you really want a sender, then you can do it this way:
- (void)someMethodWithIts:(id)sender triggeredByUser:(BOOL)isUser {
}
- (IBAction)someMethodWithIts:(id)sender {
[self someMethodWithIts:sender triggeredByUser:YES];
}
But in general, if you want the IBAction to be different than programatic changes, then don't wire programatic changes to the IBAction.
if ([sender isKindOfClass:[UIControl class]]) {
UIControl *controlSender = (UIControl *)sender;
if (sender.selected) {
// then it's #1
} else {
// then it's #2
}
} else if ([sender isKindOfClass:[Foo class]]) {
// then it's #3
}
Might work. Or poke around other properties of sender defined on UIControl or UISegmentedControl. Maybe state. My guess is you can find something that's different when the user is interacting vs. when they're not.
You really want to use method like this
-(IBAction)actionWithSender:(id)sender event:(UIEvent*)event
{
if (event) {
} else {
}
}
If you find the event parameter is nil, it's from a call in your code, otherwise, the call is from user event.

Setting a delegate using blocks in iPhone

On a view controller I have multiple textfields, which all use the same delegate. Now in the delegate the code gets really ugly since I have to differentiate between all the textfields (bunch of if/else-if or a switch statement). I came a cross this article:
Blocks in textfield delegates
But from this I still don't understand how this solves the problem? Doesn't this basically call one method and pass it the text and the method has no idea what textfield gave the string? You would still need to differentiate between the textfields, but this time inside the block (with the usual if(textfield == bazTextField)...).
I don't know that it exactly solves the problem so much as shifts it (and into viewDidLoad, which usually gets a bit of mush-mash in it anyway).
However in that example the block itself was being passed in the textfield to run comparisons with and "remembers" the values of all the instance variables as well (if it refers to them), so that's how it knows what text and text field is being dealt with.
I don't see how that code exactly is supposed to help though, since it assigns one block to the single delegate class to be used with all text field delegates - unless perhaps you were supposed to have one per text field, each with a different block. Then you have way more code than you'd have had with the if statements!
The article doesn't make it clear, but I believe the idea is to create one of these blocks (and block delegate objects) for each UITextField that you wish to have respond to textFieldShouldReturn.
hm, maybe I didn't completely understand the article, but I don't see the advantage of using blocks instead of selectors in that concrete example.
you could achieve something similar like this
#interface AlternativeTextFieldDelegate : NSObject <UITextFieldDelegate>
{
SEL selectorToCall;
id objectToCall;
}
- (void) setObjectToCall:(id)obj selector:(SEL)selector;
#end
#implementation AlternativeTextFieldDelegate
- (void) setObjectToCall:(id)obj selector:(SEL)selector
{
objectToCall = obj;
selectorToCall = selector;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[objectToCall performSelector:selectorToCall];
return YES;
}
#end
and the view controller
#interface ViewWithTextFieldsController : UIViewController
{
UITextField *tf1;
AlternativeTextFieldDelegate *delegateForTF1;
UITextField *tf2;
AlternativeTextFieldDelegate *delegateForTF2;
}
// ...IBOutlets and all that...
- (void) tf1ShouldReturn; // handles shouldReturn for tf1
- (void) tf2ShouldReturn; // handles shouldReturn for tf2
#end
#implementation ViewWithTextFieldsController
- (void) viewDidLoad // or wherever
{
delegateForTF1 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF1 setObjectToCall:self selector:#selector(tf1ShouldReturn)];
tf1.delegate = delegateForTF1;
delegateForTF2 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF2 setObjectToCall:self selector:#selector(tf2ShouldReturn)];
tf2.delegate = delegateForTF2;
}
// ...
#end
don't really know if that's any better than chaining if-elses though.
it seems to me that this complicates things more than the problem it solves.

comparing the action in iphone

user can only listen to three songs before he/she has to login or else they won't be able to listen anymore. for that can I compare IBAction like that (if(IBAction < 3)he stop and he have login for more song. This same question as I Ask before I am trying to solve that give me hint to do.
thanks in advance
IBAction is simply a marker for interface builder so that it knows what methods to provide connections for. If you look at in UINibDecleartions.h you will find
#ifndef IBAction
#define IBAction void
#endif
So no, you can do anything in code with IBAction. What you are looking for is probably something like
//Header
#interface SomeController : UIViewController {
NSInteger numTimesPressedButton;
}
-(IBAction)doSomething:(id)sender;
....
//.m File
- (id)initWithNibName:(NSString *)aNibName bundle:(NSBundle *)aNibBundle{
self = [super initWithNibName:aNibName bundle:aNibBundle];
if(self != nil)
{
numTimesPressedButton = 0;
...
}
return self;
}
-(IBAction)doSomething:(id)sender{
numTimesPressedButton++;
if (numTimesPressed > 3)
[someThing doSomeThingElse];
...
}
You should introduce a member of type int. Initialize it with 0. Each time your play action is called, check if it has reached your threshold. If yes, display the login screen, otherwise increase it by 1.

How to add (id) sender to the following -(IBAction)?

How do you add a (id) sender to the following code?
- (IBAction) gobutton: (UIButton *) button5 {
Everything I try fails, any help would be appreciated. Thanks.
EDIT: I need to keep the (UIButton *) button 5 reference in the (IBAction)
If I recall correctly, and if you are using this in the way I think you are,
- (IBAction) gobutton: (id) sender {
if(sender == button5)
//do something...
else
//do something else...
}
Assuming that you specified button5 as a parameter to indicate that this executes in response to button5 being pressed.
Ok, first.... IBAction doesn't really mean anything special except to Interface Builder. Basically:
#define IBAction void
So whenever you see IBAction, think "void". The only reason it's there is as a flag to tell Interface Builder that a method is a valid method to connect control actions to. The Objective-C compiler doesn't need to know about it and so it's defined to void since all "action" methods return void.
Second, action methods also have one argument which could be an object of any number of types. Because of this, action methods are supposed to use type id as the type for their argument. That way they can be passed a pointer to any Objective-C object without causing the compiler to generate a type checking error.
So usually actions should work something like this:
- (IBAction)myAction:(id)sender {
if (sender == self.someButton) {
UIButton *button = (UIButton *)sender;
...
return;
} else if (sender == self.someControl) {
UIControl *control = (UIControl *)sender;
...
return;
}
}
In other words, an id is almost like an untyped pointer like a void * is routinely used in C when some function needs to take a pointer to something of unknown type. sender could be different types of control, so something generic like id is used then sender is cast to something more specific once the code knows what it is.
Anyway, there is absolutely no reason to define something as having a return type of IBAction unless you are going to use that method as a target action in Interface Builder. Having an IBAction in your app delegate seems kind of unusual....
It's not clear what you are trying to do but most actions look like:
- (IBAction) gobutton: (id)sender;
The first parameter to an action is always the sender (you can specify the type and name as appropriate).
If a method is the action for a button, then the first parameter will be the button. If that method is the action for several buttons, then the first parameter will allow you to determine which button was tapped (as Leper describes).
What problem are you actually trying to solve?
There are techniques for passing information to the action method. For example, if you have a button that appears on a table view cell and performs the same action for every cell, then in the action method, you would want to be able to determine which cell's button was tapped.
How can I get the id of the sender before the user touches the control?
Found it! Set a tag and the use viewWithTag.
Can you create a simple structure that contains both the UIButton and the sender and use that?
struct myObject
{
UIButton* button5;
id sender;
}
...or, you could create your own NSObject (probably more cocoa-y):
#instance myObject : NSObject
{
...
}