将id传递给Objective-C中的按钮操作方法

时间:2013-11-19 06:42:51

标签: ios objective-c

我以编程方式创建了UIButtons。现在,我创建了一个触发按钮的方法,如下所示:

-(void)createButton {
//code to create button
[mybutton addTarget:self action:@selector(myAction:)forState:UIControlStateNormal];
}

-(void)myAction:(id)sender {
if([tag sender] == 0) {
posX = 380;
} else if(....... //set posX to different values
}
[self.myScroll setContentOffset:CGPointMake(poxX, 0) animated:YES];

除了加载数据之外,这几乎就是按钮的作用。基本上,我使用按钮作为选项卡。如果我点击按钮,它会滑到中心。在其中一个按钮中,有一个“更新按钮”按钮,我可以在其中添加和删除更多按钮。如果我点击其中一个按钮,它将自动被删除,如果我点击添加,则会自动添加。没问题。问题是,我想保留“更新按钮”按钮居中,因为它在技术上仍然是所选按钮。以下是视图中更新按钮的方法:

-(void)updateButtons {
NSUInteger index = [self.anArray indexOfObject:@"btnChange"];
id indexId = [NSNumber numberWithInteger: index];
//this following line causes the app to crash because it does not recognize the indexId I'm trying to set
[self myAction:indexId];
}

每次执行updateButtons函数并触发myAction时,应用程序都会因未捕获的异常而崩溃。所以我的问题是,如何正确地将id传递给动作方法?

7 个答案:

答案 0 :(得分:1)

您的问题的准确答案是:传递发送者参数的nil:

 [self myAction:nil];

答案 1 :(得分:1)

 -(void)createButton 
{
    //code to create button
    myButton.tag  = 1; 
    [mybutton addTarget:self action:@selector(myAction:)forState:UIControlStateNormal];
}

-(void)myAction:(id)sender {
    //do something here
}

您正在尝试传递NSNumber对象,但是您需要将UIButton对象传递给myAction:方法,我认为您应该在.h文件中创建UIButton对象并将标记添加到按钮并传递引用该按钮对象的方法

-(void)updateButtons 
{
    NSUInteger index = [self.anArray indexOfObject:@"btnChange"];
    if(myButton.tag == index){

       [self myAction:myButton];

    }
}

答案 2 :(得分:0)

-(void)updateButtons {
NSUInteger index = [self.anArray indexOfObject:@"btnChange"];
mybutton.tag=index
[self myAction:nil];
}

然后在

-(void)myAction:(id)sender {
//do something here
int index=[sender tag]; //this is your index
}

答案 3 :(得分:0)

试试这个:

-(void)createButton 
 {
    //code to create button
    [mybutton addTarget:self action:@selector(myAction:)forState:UIControlStateNormal];
 }

  -(void)myAction:(id)sender
  {
    //do something here
  }

 -(void)updateButtons 
 {
    NSUInteger index = [self.anArray indexOfObject:@"btnChange"];
    id indexId = [NSNumber numberWithInteger: index];
    [self myAction:mybutton];//if u r using my button  else u can use
    [self myAction:nil]
 }

答案 4 :(得分:0)

Objective-C中的

id仅表示任何对象 - 它用于避免指定某种类型的对象。使用target-action时,第一个参数是sender,或者是发送操作的对象。对于按钮,发件人将是UIButton的实例。

我建议您在操作方法中添加NSLog(@"%@",sender);,以便在每次调用方法时查看它的类型。

那么什么应该作为参数传递?好吧,这取决于myAction的作用,你必须分享该代码才能获得更多详细信息。如果myAction未使用sender参数,则可以安全地传递nil,如其他回答者所建议的那样。

请注意,当您使用target-action时,如果您没有使用sender参数,则可以将其完全关闭。只需声明您的方法:

-(void)myAction
{
    // code here
}

答案 5 :(得分:0)

[mybutton addTarget:self action:@selector(myAction:)forState:UIControlStateNormal];

而不是上面,替换下面这行

[mybutton addTarget:self action:@selector(myAction:) forControlEvents:UIControlEventTouchUpInside];

答案 6 :(得分:0)

首先,您使用-addTarget:action:forState. UIButton似乎很奇怪是UIControl的具体子类,因此使用方法-addTarget:action:forControlEvents: 这可以采用可变数量的或UIControlEvent枚举。具体而言,UIButton所需的属性为UIControlEventTouch...

你应该立即崩溃,因为该方法不存在。

话虽如此,在不查看代码的情况下,我们无法确切地告诉您-myAction:方法中的哪一行导致崩溃。但重要的是,通过目标 - 动作模式注册其签名/选择器的方法甚至不需要具有idUIButton或任何类型的参数。

基本上,当您执行-addTarget:action:forControlEvents:时,您告诉UIControl的子类,当它经历所需的事件时,它应该调用您传递给-addTarget:的第一个参数的对象中的方法(目标),其签名是您传递给action:的选择器。传递给此参数的选择器可以依次包含一个或零个参数。如果您传入一个没有(例如,您的操作方法为-doSomething),当UIControl响应UIControlEvent时,它只需调用您的方法就可以了。相反,如果您传入一个带有一个参数的选择器,则触发该操作的UIControl会自动传入该参数,并转换为您的操作方法参数类型所属的任何类型。

例如:

如果您这样注册:

[self.readingListButton addTarget:self action:@selector(doSomething) forControlEvents:UIControlEventTouchUpInside];

你的行动方法如下:

- (void)doSomething
{
    //  Notice we don't have a parameter and so we are limited to doing stuff
    //  that does not require the sender to be passed in.
    NSLog(@"do Something!");
}

如果你这样注册(注意选择器中的):

[self.readingListButton addTarget:self action:@selector(doSomething:) forControlEvents:UIControlEventTouchUpInside];

你可以去:

- (void)doSomething:(id)sender
{
    //  If the button triggers the method, sender will be an id pointer holding the memory
    //  address of a UIButton and we could cast it to UIButton like so: UIButton *b = (UIButton)sender
    // Then again, sender might not be a button. As long as we stick to stuff that any object
    // will respond to we are fine though.
    NSLog(@"do Something! %@", sender);
}

或:

- (void)doSomething:(UIButton*)sender
{
    //  We straight out assume it is a button:
    NSLog(@"do Something! %@", sender);
}

正如您所看到的,参数vs无参数和参数类型的选择取决于您。

现在我的猜测是您的代码崩溃的原因是因为当您手动调用操作方法时,您传递的是NSNumber而不是UIButton,并且在方法内部您使用参数执行某些操作将其视为UIBUtton.

考虑一下这个例子:

- (void)doSomething:(UIButton*)sender
{
    //  Our parameter is a button, so we can totally change its state:
    sender.selected = !sender.selected;
}

如果您将按钮传递给上述方法,它将正常工作。但是在第二种情况下,您传递一个数字。真正发生的是:

    NSNumber *n;
    UIButton *b = (UIButton*)n;
    [target doSomething:b];

-doSomething:

- (void)doSomething:(UIButton*)sender
{
    //  Our parameter is a button, so we can totally change its state:
    sender.selected = !sender.selected;
}

sender现在不是一个按钮。这是按钮的数字。上面的代码尝试更改状态的那一刻,它会尝试在没有该方法的-setState:上调用方法NSNumber,因此您将得到一个经典的例外: 无法识别的选择器已发送到实例。

如此底线,如果您不需要将按钮或任何信息传递到目标方法,只需在没有参数的情况下定义它,或者如果您需要参数,则使参数变为多态(类型{{1在你的方法中检查它是什么并相应地采取行动,或者坚持使用id类型的参数,但是它们确保你只是通过按钮调用它。