在 Swift 中将参数传递给选择器

Posted

技术标签:

【中文标题】在 Swift 中将参数传递给选择器【英文标题】:Passing arguments to selector in Swift 【发布时间】:2017-09-01 06:41:59 【问题描述】:

我正在以编程方式将 UITapGestureRecognizer 添加到我的一个视图中:

let gesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTap(modelObj:myModelObj)))

self.imageView.addGestureRecognizer(gesture)

func handleTap(modelObj: Model) 
  // Doing stuff with model object here

我遇到的第一个问题是“'#selector' 的参数没有引用 '@Objc' 方法、属性或初始化程序。

酷,所以我在 handleTap 签名中添加了@objc:

@objc func handleTap(modelObj: Model) 
  // Doing stuff with model object here

现在我收到错误“方法无法标记为@objc,因为参数的类型无法在 Objective-C 中表示。

这只是建筑物地图的图像,其中一些图钉图像指示了兴趣点的位置。当用户点击其中一个引脚时,我想知道他们点击了哪个兴趣点,并且我有一个描述这些兴趣点的模型对象。我使用此模型对象为图钉图像提供地图上的坐标,因此我认为将对象发送到手势处理程序会很容易。

【问题讨论】:

您不能将值传递给这样的选择器。为什么不能将该值保存在实例变量中并从选择器方法中访问它? ***.com/questions/35635595/… 可能重复。 【参考方案1】:

您似乎误解了几件事。

使用target/action时,函数签名必须有一定的形式……

func doSomething()

func doSomething(sender: Any)

func doSomething(sender: Any, forEvent event: UIEvent)

在哪里……

sender参数是发送动作消息的控制对象。

在您的情况下,发件人是UITapGestureRecognizer

另外,#selector() 应该包含 func 签名,并且不包含传递的参数。所以对于……

func handleTap(sender: UIGestureRecognizer) 
    

你应该……

let gesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))

假设func和手势在一个视图控制器中,其中modelObj是一个属性/ivar,则不需要通过手势识别器传递,你可以在handleTap中引用它

【讨论】:

UIControl documentation for Swift 的 The Target-Action Mechanism 部分也是一本很好的读物,展示了操作方法可以采取的三种形式。 为了补充这个很好的答案,某些对象类型(例如 Timer)具有userInfo: Any? 参数,可以与此解决方案结合使用,以将模型对象传递给发送者。【参考方案2】:

第 1 步:创建发送者的自定义对象。

第 2 步:在发送者的自定义对象中添加要更改的属性

第 3 步:将接收函数中的发送者类型转换为 自定义对象 并访问这些属性

例如: 如果要发送字符串或任何自定义对象,请单击按钮

第一步:创建

class CustomButton : UIButton 

    var name : String = ""
    var customObject : Any? = nil
    var customObject2 : Any? = nil

    convenience init(name: String, object: Any) 
        self.init()
        self.name = name
        self.customObject = object
    

步骤 2-a:在情节提要中设置自定义类

步骤 2-b:使用自定义类创建该按钮的 IBOutlet,如下所示

@IBOutlet weak var btnFullRemote: CustomButton!

第 3 步:在发送者的自定义对象中添加要更改的属性

btnFullRemote.name = "Nik"
btnFullRemote.customObject = customObject
btnFullRemote.customObject2 = customObject2
btnFullRemote.addTarget(self, action: #selector(self.btnFullRemote(_:)), for: .touchUpInside)

第 4 步:将接收函数中的发送者类型转换为 自定义对象 并访问这些属性

@objc public func btnFullRemote(_ sender: Any) 

var name : String = (sender as! CustomButton).name as? String

var customObject : customObject = (sender as! CustomButton).customObject as? customObject

var customObject2 : customObject2 = (sender as! CustomButton).customObject2 as? customObject2


【讨论】:

聪明的答案,提供了一个很好的解决方案(而不是说这是不可能的,因为我发现的大多数答案都说)......尝试了这种方法并可以确认它有效 自定义对象包装器传递您需要的一切!好聪明。谢谢。【参考方案3】:

Swift 5.0 ios 13

我同意Ninad 的出色回答。这是我的 2 美分,相同但不同的技术;最小版本。

创建一个自定义类,抛出一个枚举以保持/使代码尽可能可维护。

enum Vs: String 
  case pulse = "pulse"
  case precision = "precision"
 

class customTap: UITapGestureRecognizer 
  var cutomTag: String?

使用它,确保将自定义变量设置为 bargin。这里使用一个简单的标签,注意最后一行,重要的标签通常不会交互。

let precisionTap = customTap(target: self, action: #selector(VC.actionB(sender:)))
precisionTap.customTag = Vs.precision.rawValue
precisionLabel.addGestureRecognizer(precisionTap)
precisionLabel.isUserInteractionEnabled = true

并使用它设置动作,注意我想使用纯枚举,但 Objective C 不支持它,所以我们使用基本类型,在这种情况下为 String。

@objc func actionB(sender: Any) 
// important to cast your sender to your cuatom class so you can extract your special setting.
  let tag = customTag as? customTap
  switch tag?.sender 
    case Vs.pulse.rawValue:
      // code
    case Vs.precision.rawValue:
      // code
    default:
      break
    

你有它。

【讨论】:

太棒了。这行得通。但我认为应该更正 @objc func actionB(sender: Any) let tap = sender as? customTap switch tap?.customTag ...【参考方案4】:
cell.btn.tag = indexPath.row //setting tag
cell.btn.addTarget(self, action: #selector(showAlert(_ :)), for: .touchUpInside)

@objc func showAlert(_ sender: UIButton)
  print("sender.tag is : \(sender.tag)")// getting tag's value

【讨论】:

此问题已在一段时间前得到回答,并且已经接受了答案。这意味着任何额外的答案都应该为这个问题的任何读者提供一个新的视角。因此,我建议您在答案中添加更多上下文,并描述为什么它提供了一种解决问题的独特方法。有关回答问题的更多信息,请查看此处:***.com/help/how-to-answer【参考方案5】:

只需创建一个自定义类的 UITapGestureRecognizer =>

import UIKit

class OtherUserProfileTapGestureRecognizer: UITapGestureRecognizer 

    let userModel: OtherUserModel    
    init(target: AnyObject, action: Selector, userModel: OtherUserModel) 
        self.userModel = userModel
        super.init(target: target, action: action)
    

然后创建 UIImageView 扩展 =>

import UIKit

    extension UIImageView 
    
        func gotoOtherUserProfile(otherUserModel: OtherUserModel) 
            isUserInteractionEnabled = true
            let gestureRecognizer = OtherUserProfileTapGestureRecognizer(target: self, action: #selector(self.didTapOtherUserImage(_:)), otherUserModel: otherUserModel)
            addGestureRecognizer(gestureRecognizer)
        
        
        @objc internal func didTapOtherUserImage(_ recognizer: OtherUserProfileTapGestureRecognizer) 
            Router.shared.gotoOtherUserProfile(otherUserModel: recognizer.otherUserModel)
        
    

现在像 =>

一样使用它
self.userImageView.gotoOtherUserProfile(otherUserModel: OtherUserModel)

【讨论】:

【参考方案6】:

您可以改用UIAction

self.imageView.addAction(UIAction(identifier: UIAction.Identifier("imageClick"))  [weak self] action in
    self?.handleTap(modelObj)
, for: .touchUpInside)

【讨论】:

【参考方案7】:

这可能是一种糟糕的做法,但我只是添加了我想要恢复的任何内容

button.restorationIdentifier = urlString

@objc func openRelatedFact(_ sender: Any) 
        if let button = sender as? UIButton, let stringURL = factButton.restorationIdentifier, let url = URL(string: stringURL) 
            if UIApplication.shared.canOpenURL(url) 
                UIApplication.shared.open(url, options: [:])
            
        

    

【讨论】:

糟糕的做法……是的。太有创意了!工藤的!

以上是关于在 Swift 中将参数传递给选择器的主要内容,如果未能解决你的问题,请参考以下文章

可以在Python中将参数传递给函数对象吗?

使用 UITapGestureRecognizer、UIImageView 和 UITableViewCell 将参数传递给 Swift 中的选择器

如何在swift中将参数传递给post API

将参数传递给选择器

如何将 URL 参数传递给选择器

在 GCC 中将 0 参数传递给可变参数宏失败,但仅在 C++ 中?