在按钮操作上传递参数:@selector

Posted

技术标签:

【中文标题】在按钮操作上传递参数:@selector【英文标题】:Passing parameters on button action:@selector 【发布时间】:2011-04-12 14:40:36 【问题描述】:

我想将动态生成的按钮中的电影 url 传递给 MediaPlayer:

[button addTarget:self action:@selector(buttonPressed:) withObject:[speakers_mp4 objectAtIndex:[indexPath row]] forControlEvents:UIControlEventTouchUpInside];

但是action:@selector() withObject: 不起作用?

还有其他解决办法吗?

感谢您的帮助!

【问题讨论】:

哟!得到了更好的解决方案。只要确保你注意到。 【参考方案1】:

tl;dr:使用块

Obj-C为例,有一个CocoaPod SHControlBlocks,其用法是:

[self.btnFirst SH_addControlEvents:UIControlEventTouchDown withBlock:^(UIControl *sender) 
    [weakSelf performSegueWithIdentifier:@"second" sender:nil];
    NSLog(@"first");
  ];

对于 Swift,我喜欢 pod Actions,它允许阻止 UIControls [1]:

// UIControl
let button = UIButton()
button.add(event: .touchUpInside) 
    print("Button tapped")
    playMusic(from: speakers_mp4, withSongAtPosition: indexPath.row)

并不是说有人在阅读 3 年前的帖子。 ::蟋蟀::

[1] 和UIViewUITextFieldUIGestureRecognizerUIBarButtonItemTimer(原名 NSTimer)和 NotificationCenter(原名 NSNotificationCenter)。

【讨论】:

为什么是-1,各位?什么需要改进/纠正? 感谢您的厚爱!【参考方案2】:

编辑。找到了一个更简洁的方法!

按钮可以接收的一个参数是(id)sender。这意味着您可以创建一个从 UIButton 继承的新按钮,它允许您存储其他预期的参数。希望这两个 sn-ps 说明了该做什么。

  myOwnbutton.argOne = someValue
  [myOwnbutton addTarget:self action:@selector(buttonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside];

- (IBAction) buttonTouchUpInside:(id)sender 
  MyOwnButton *buttonClicked = (MyOwnButton *)sender; 
  //do as you please with buttonClicked.argOne


这是我最初的建议。

有一种方法可以达到相同的结果,但它并不漂亮。假设您想向navigate 方法添加一个参数。下面的代码不允许您将该参数传递给navigate

[button addTarget:self action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];

要解决这个问题,您可以将导航 method 移动到它自己的类并将“参数”设置为该类的属性...

NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];

当然,您可以将 navigate 方法保留在原始类中并由 navAid 调用,只要它知道在哪里可以找到它。

NavigationAid *navAid = [[NavigationAid alloc] init];
navAid.whereToCallNavigate = self
navAid.firstParam = someVariableOne
navAid.secondParam = someVariableTwo
[button addTarget:navAid action:@selector(navigate) forControlEvents:UIControlEventTouchUpInside];

就像我说的那样,它并不漂亮,但它对我有用,而且我还没有找到任何人建议任何其他可行的解决方案。

【讨论】:

您的“原始建议”的问题是您的“NavigationAid”对象从未被释放,因此是内存泄漏 您能发布您的 NavigationAid 课程吗?因为我调试时方法没有调用。 @bhautikmewada191 抱歉,我没有。你晚了5年:P 请问您如何声明您的 MyOwnButton 类?我已通过以下方式声明它,但它不起作用 MyOwnButton.h ` #import @interface MyOwnButton : UIButton @property(nonatomic, strong) NSString* title; @property(nonatomic, strong) NSString* 内容; @end ` MyOwnButton.m ` #import "MyOwnButton.h" @implementation MyOwnButton @synthesize 标题; @synthesize 内容; @end `【参考方案3】:

在参数中添加隐藏的titleLabel是最好的解决方案。

我生成了一个数组 arrUrl,它通过枚举 assets 块来存储我手机相册中 mov 文件的 NSURL。

之后,我抓取 Frame,比如说,在电影文件中获取 3:00 秒的帧,并从该帧生成图像文件。

接下来,遍历arrUrl,并使用程序生成按钮中带有图像的按钮,将按钮附加到self.view的子视图中。

因为我必须将电影 Url 传递给 playMovie 函数,所以我必须为 button.titleLabel.text 分配一个电影 url。和按钮事件函数,从 buttontitleLable.txt 中检索 url。

-(void)listVideos


   for(index=0;index<[self.arrUrl count];index++
      UIButton *imageButton = [UIButton buttonWithType:UIButtonTypeCustom];
      imageButton.frame = CGRectMake(20,50+60*index,50,50);

      NSURL *dUrl = [self.arrUrl objectAtIndex:index];

      [imageButton setImage:[[UIImage allow] initWithCGImage:*[self getFrameFromeVideo:dUrl]] forState:UIControlStateNormal];
      [imageButton addTarget:self action:@selector(playMovie:) forControlEvents:UIControlEventTouchUpInside];
      imageButton.titleLabel.text = [NSString strinfWithFormat:@"%@",dUrl];
      imageButton.titleLabel.hidden = YES;

      [self.view addSubView:imageButton];
   


-(void)playMovie:(id) sender
   UIButton *btn = (UIButton *)sender;
   NSURL *movUrl = [NSURL URLWithString:btn.titleLabel.text];
   moviePlayer = [[MPMoviePlayerViewController alloc] initWithContentURL:movUrl];
   [self presentMoviePlayerViewControllerAnimated:moviePlayer];


-(CGIImageRef *)getFrameFromVideo:(NSURL *)mUrl
   AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:mUrl option:nil];
   AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
   generator.appliesPreferredTrackTransform = YES;
   NSError *error =nil;
   CMTime = CMTimeMake(3,1);
   CGImageRef imageRef = [generator copyCGImageAtTime:time actualTime:nil error:&error];
   if(error !=nil) 
      NSLog(@"%@",sekf,error);
   

   return @imageRef;

【讨论】:

谢谢,这对我帮助很大,但不能以比这更简单的方式做到这一点是非常愚蠢的。【参考方案4】:

您可以设置按钮的标签并从发送者访问它

[btnHome addTarget:self action:@selector(btnMenuClicked:)     forControlEvents:UIControlEventTouchUpInside];
                    btnHome.userInteractionEnabled = YES;
                    btnHome.tag = 123;

在被调用函数中

-(void)btnMenuClicked:(id)sender

[sender tag];

    if ([sender tag] == 123) 
        // Do Anything
    

【讨论】:

【参考方案5】:

我部分基于上述信息提出了解决方案。 我只是将titleLabel.text 设置为我要传递的字符串,然后设置titleLabel.hidden = YES

像这样:

    UIButton *imageclick = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
    imageclick.frame = photoframe;
    imageclick.titleLabel.text = [NSString stringWithFormat:@"%@.%@", ti.mediaImage, ti.mediaExtension];
    imageclick.titleLabel.hidden = YES;

这样,就不需要继承或类别,也没有内存泄漏

【讨论】:

谢谢老兄,这对我有用。当我看到这个时,我正要对 UIButton 进行子类化。天哪!! 智能解决方案,感谢发帖【参考方案6】:

要添加到Tristan's answer,按钮除了(id)sender之外还可以接收(id)event

- (IBAction) buttonTouchUpInside:(id)sender forEvent:(id)event  .... 

例如,如果按钮位于UITableView 的单元格中,并且您想找到被触摸按钮的indexPath,这将很有用(尽管我想这也可以通过@找到987654329@元素)。

【讨论】:

【参考方案7】:

我找到了解决方案。来电:

-(void) someMethod
    UIButton * but;
    but.tag = 1;//some id button that you choice 
    [but addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; 

这里调用的方法是:

-(void) buttonPressed : (id) sender
    UIButton *clicked = (UIButton *) sender;
    NSLog(@"%d",clicked.tag);//Here you know which button has pressed

【讨论】:

是的,UIButton 确实从 UIView 继承了 tag 属性。这很方便。但是标签只包含一个NSInteger。对于其他类型,您可以按照Tristan's answer 的建议创建一个子类。【参考方案8】:

在某些情况下,我有另一种解决方案。

将您的参数存储在隐藏的 UILabel 中。然后将此 UILabel 添加为 UIButton 的子视图。

当按钮被点击时,我们可以检查 UIButton 的所有子视图。通常只有 2 个 UILabel。

一个是UIButton的标题,另一个是你刚刚添加的那个。阅读 UILabel 的 text 属性,您将获得参数。

这仅适用于文本参数。

【讨论】:

【参考方案9】:

您可以将一个名为 MyButton 的 UIButton 子类化,并通过 MyButton 的属性传递参数。

然后,从 (id)sender 取回参数。

【讨论】:

是的,这看起来很不错,可以将事物与类的实例捆绑在一起,然后从中取回它们。但是没有其他方法可以将多个参数传递给 @selector 。 发送者是MyButton,然后你可以从MyButton的属性中取回参数。【参考方案10】:

UIButton 响应 addTarget:action:forControlEvents: 因为它继承自 UIControl。但它不响应 addTarget:action:withObject:forControlEvents:

见reference for the method 和UIButton

您可以使用类别扩展 UIButton 来实现该方法,我想。

【讨论】:

你将如何实现这个类别?你将如何传递参数?您仍然会遇到同样的问题,因为您可以在类别方法中执行的任何操作都可以在原始调用代码中完成【参考方案11】:

我认为正确的方法应该是: - (void)addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents

UIControl Reference

你从哪里得到你的方法?

我看到您的选择器有一个参数,该参数将由运行时系统填充。它会通过该参数将按钮发回给您。

你的方法应该是这样的:

- (void)buttonPressed:(id)BUTTON_HERE

【讨论】:

对,但我想将电影 url 作为参数传递给我的函数 buttonPressed。我该怎么做? 你没有办法做到这一点。您应该将电影 url 存储在实例变量之类的地方,然后在那里调用它

以上是关于在按钮操作上传递参数:@selector的主要内容,如果未能解决你的问题,请参考以下文章

如何将@selector 作为参数传递?

将自定义参数传递给 uibutton #selector swift 3

在#selector 调用中快速传递参数

将参数传递给选择器

记录----点击打开bootstarp模态框时,传递参数进去

MVVMCross iOS如何在TableViewCell按钮中传递参数