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

Passing arguments to selector in Swift

我正在以编程方式将 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' 方法、属性 或初始化程序。

太棒了,所以我将@objc 添加到 handleTap 签名中:

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

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

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

看来您误解了几件事。

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

func doSomething()

func doSomething(sender: Any)

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

哪里……

The sender parameter is the control object sending the action message.

在你的例子中,发件人是 UITapGestureRecognizer

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

func handleTap(sender: UIGestureRecognizer) {
    
}

你应该有……

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

假设func和gesture都在一个view controller中,其中modelObj是一个属性/ivar,不需要通过gesture recogniser传递,可以参考它在 handleTap

第 1 步:创建发件人的自定义对象。

第 2 步:在发件人

自定义对象中添加要更改的属性

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

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

第 1 步:创建

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:在情节提要中也设置自定义 class

步骤 2-b:使用自定义 class 创建该按钮的 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

}

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

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 5.0 iOS 13

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

创建一个自定义 class,将枚举抛给 keep/make 尽可能维护代码。

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
    }
}

给你了。

只需创建自定义 class 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)
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
}

您可以改用 UIAction

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