Swift “;无法识别的选择器发送到实例”;调用addTarget时在UIView类中
我试图创建一个DropDownMenu类,但是当我试图调用其中一个按钮的addTarget时,出现了这个错误 发送到实例0x7fd167f06120'的无法识别的选择器以NSException类型的未捕获异常终止 我真的很感激任何帮助,没有答案是不好的 这是我的全班同学Swift “;无法识别的选择器发送到实例”;调用addTarget时在UIView类中,swift,class,uibutton,selector,swift5,Swift,Class,Uibutton,Selector,Swift5,我试图创建一个DropDownMenu类,但是当我试图调用其中一个按钮的addTarget时,出现了这个错误 发送到实例0x7fd167f06120'的无法识别的选择器以NSException类型的未捕获异常终止 我真的很感激任何帮助,没有答案是不好的 这是我的全班同学 class DropDownMenu: UIView { // Main button or Pre var main: UIButton! = UIButton(frame: CGRect(x: 0, y: 0
class DropDownMenu: UIView {
// Main button or Pre
var main: UIButton! = UIButton(frame: CGRect(x: 0, y: 0, width: 46, height: 30))
var view: UIView!
// Title
var buttonTitles: [String]! = [""]
var titleColor: UIColor! = UIColor.black
var font: UIFont! = UIFont.systemFont(ofSize: 18)
// Individual Button
var buttonsBorderWidth: CGFloat! = 0
var buttonsBorderColor: UIColor? = UIColor.white
var buttonsCornerRadius: CGFloat! = 0
var color: UIColor! = UIColor.clear
// Button Images
var buttonsImageEdgeInsets: UIEdgeInsets? = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
var images: [UIImage]? = nil
// Onclick stuff
var target: UIViewController!
private var currentSelected: String? = nil
private var optionsStack = UIStackView()
init(main: UIButton) {
self.main = main
super.init(frame: CGRect())
}
func createDropDownMenu() {
main.addTarget(target, action: #selector(DropDownMenu.openDropdown(_:)), for: .touchUpInside)
print("Button Target?: \(main.allTargets), self.target: \(String(describing: target))")
let mainFrame = main.frame
optionsStack.frame = CGRect(x: mainFrame.minX, y: mainFrame.maxY, width: mainFrame.width, height: CGFloat(buttonTitles.count) * mainFrame.height)
optionsStack.axis = .vertical
view.addSubview(optionsStack)
var y: CGFloat! = 0
for title in buttonTitles {
let button = UIButton(frame: CGRect(x: 0, y: y, width: mainFrame.width, height: mainFrame.height))
button.setTitle(title, for: .normal)
button.setTitleColor(titleColor, for: .normal)
button.backgroundColor = color
button.titleLabel?.font = font
button.addTarget(target, action: #selector(DropDownMenu.onclick), for: .touchUpInside)
y += mainFrame.height
optionsStack.addArrangedSubview(button)
}
for button in optionsStack.arrangedSubviews {
button.isHidden = true
button.alpha = 0
}
}
@objc private func openDropdown(_ sender: UIButton) {
print("sender: \(String(describing: sender))")
optionsStack.arrangedSubviews.forEach { (button) in
UIView.animate(withDuration: 0.7) {
button.isHidden = !button.isHidden
button.alpha = button.alpha == 0 ? 1 : 0
self.view.layoutIfNeeded()
}
}
}
@objc private func onclick(_ sender: UIButton) {
let title = sender.titleLabel!.text
print(title as Any)
main.setTitle(title, for: .normal)
optionsStack.arrangedSubviews.forEach { (button) in
UIView.animate(withDuration: 0.7) {
button.isHidden = true
button.alpha = 0
}
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
以下是ViewController中对象的代码和创建
let grade = UIButton(frame: CGRect(x: 50, y: 300, width: 80, height: 30))
grade.layer.borderWidth = 1
grade.setTitle("Grade", for: .normal)
grade.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
grade.setTitleColor(UIColor.black, for: .normal)
let gradeDP = DropDownMenu(main: main)
gradeDP.buttonTitles = ["Title 1", "Title 2", "Title 3"]
gradeDP.color = UIColor.gray
gradeDP.target = self
gradeDP.titleColor = UIColor.white
gradeDP.view = view
view.addSubview(grade)
gradeDP.createDropDownMenu()
createDropDownMenu()函数中的第一个print语句打印
按钮目标?:[AnyHashable()],self.Target:Optional()
在mightknow的帮助下编辑之后,我想出了这个类。它没有任何针对main按钮的onclick操作
class DropDownMenu: UIStackView {
var options: [String]! = [] // Labels for all of the options
var titleButton: UIButton! = UIButton() // The Main Title Button
init(options: [String]) {
self.options = options
let mainFrame = titleButton.frame
super.init(frame: CGRect(x: mainFrame.minX, y: mainFrame.maxY, width: mainFrame.width, height: mainFrame.height * CGFloat(options.count)))
var y: CGFloat = 0
for title in self.options {
let button = UIButton(frame: CGRect(x: 0, y: y, width: self.frame.width, height: mainFrame.height))
button.setTitle(title, for: .normal)
button.setTitleColor(titleButton.titleLabel?.textColor, for: .normal)
button.backgroundColor = titleButton.backgroundColor
button.addTarget(self, action: #selector(dropDownOptionClicked(_:)), for: .touchUpInside)
button.isHidden = true
button.alpha = 0
self.addArrangedSubview(button)
y += 1
}
}
@objc func openDropDown(_ sender: UIButton) {
print("Open DropDownMenu")
for button in self.arrangedSubviews {
UIView.animate(withDuration: 0.7) {
button.isHidden = !button.isHidden
button.alpha = button.alpha == 0 ? 1 : 0
self.layoutIfNeeded()
self.superview?.layoutIfNeeded()
}
}
}
@objc private func dropDownOptionClicked(_ sender: UIButton) {
print(sender.titleLabel?.text as Any)
}
init() {
super.init(frame: CGRect.zero)
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
而我的ViewController是
let dp = DropDownMenu(options: ["Label 1", "Label 2", "Label 3"])
let titleButton = UIButton(frame: CGRect(x: 100, y: 300, width: 180, height: 40))
titleButton.backgroundColor = UIColor.white
titleButton.setTitle("DropDownMenu", for: .normal)
titleButton.setTitleColor(UIColor.black, for: .normal)
titleButton.layer.borderWidth = 2
titleButton.addTarget(self, action: #selector(dp.openDropDown(_:)), for: .touchUpInside)
dp.titleButton = titleButton
错误
按钮目标?:[AnyHashable()],self.Target:Optional()
仍然出现,我不知道为什么。您将目标设置为
UIViewController
,而您调用的方法实际上是下拉菜单
类的方法。您需要做的是将目标设置为self
,而不是target
属性:
main.addTarget(self, action: #selector(DropDownMenu.openDropdown(_:)), for: .touchUpInside)
编辑:作为对您评论的回应,下面是我用来测试它的代码。我做了一些布局/颜色选择,只是为了让自己清楚,但这很有效:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let main = UIButton(frame: CGRect(x: 0, y: 100, width: 80, height: 30))
main.layer.borderWidth = 1
main.setTitle("Grade", for: .normal)
main.titleLabel?.font = UIFont.boldSystemFont(ofSize: 20)
main.setTitleColor(UIColor.black, for: .normal)
let gradeDP = DropDownMenu(main: main)
gradeDP.buttonTitles = ["Title 1", "Title 2", "Title 3"]
gradeDP.color = UIColor.gray
gradeDP.target = self
gradeDP.titleColor = UIColor.white
gradeDP.view = UIView()
self.view.addSubview(gradeDP)
let b = self.view.bounds
gradeDP.frame = CGRect(x: b.minX, y: b.minY, width: b.width, height: b.height/2)
gradeDP.backgroundColor = UIColor.purple
gradeDP.target = self
gradeDP.addSubview(gradeDP.main)
gradeDP.createDropDownMenu()
}}
至于您的代码,我假设您在问题的第二部分中添加的代码在ViewController的viewDidLoad()
方法中,并且用于初始化下拉菜单的main
变量是ViewController的一个实例变量,因为我没有在范围内的其他任何地方看到它。如果是这样的话,肯定有一些问题。它们是:
实际上,您从未将gradeDP
添加到视图层次结构中。如果这是行gradeDP.view=view
应该做的,那就不是了。该代码实际执行的操作是将gradeDP
的view
属性设置为对ViewController的view
属性的引用。而且,除非您的DropDownMenu类中有未包含的代码,否则您实际上并没有将该引用用于任何事情。因此,您可以完全删除该行以及下拉菜单
类中的视图
属性。如果您试图将ViewController的视图设置为gradeDP
,则该代码将为self.view=gradeDP
,但我不建议这样做。UIViewController
的view
属性用于某些特殊功能,可能不应该太麻烦。您可能希望添加gradeDP
作为子视图,就像我在上面的代码中所做的那样
您创建的grade
按钮不被下拉菜单使用。我猜您是想用它来初始化,而不是main
变量(这超出了代码的范围),如下所示:
class DropDownMenu : UIView {
var dropdownOptions : [String] = []
private var titleButton : UIButton = UIButton()
private var optionsStack : UIStackView = UIStackView()
private var optionsButtons : [UIButton] = []
@objc private func openDropdown(_ sender: UIButton) {
// Add code to make dropdown options appear. There are multiple ways of doing this. For instance, the optionsButtons could be hidden and then unhidden when it's clicked, or they could be created only once the button is clicked.
}
@objc private func selectedOption(_ sender: UIButton) {
// Code here for when option is selected
}
init(options: [String]) {
self.dropdownOptions = options
super.init(frame: CGRect.zero)
// Customize all of your subviews here, and add them to your DropDownMenu (as subviews)
// Add openDropdown(_:) target to self.titleButton
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
let gradeDP=下拉菜单(主:年级)
简而言之,除非您在其他地方没有共享代码,否则您上面的代码所做的就是创建一个标记为“Grade”的UIButton,它是可见的,但实际上没有做任何事情(并且不是您的下拉菜单的一部分),以及一个实际上不可见的下拉菜单,但会有一个调用openDropdown(:)的main
按钮
如果是。我猜这不是它的工作原理。不过,希望我上面提供的代码能帮助您达到您想要的目的。至于重建类以使其正常工作的建议,您可能需要从以下内容开始:
class DropDownMenu : UIView {
var dropdownOptions : [String] = []
private var titleButton : UIButton = UIButton()
private var optionsStack : UIStackView = UIStackView()
private var optionsButtons : [UIButton] = []
@objc private func openDropdown(_ sender: UIButton) {
// Add code to make dropdown options appear. There are multiple ways of doing this. For instance, the optionsButtons could be hidden and then unhidden when it's clicked, or they could be created only once the button is clicked.
}
@objc private func selectedOption(_ sender: UIButton) {
// Code here for when option is selected
}
init(options: [String]) {
self.dropdownOptions = options
super.init(frame: CGRect.zero)
// Customize all of your subviews here, and add them to your DropDownMenu (as subviews)
// Add openDropdown(_:) target to self.titleButton
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
为类的原始版本编写的许多代码都可以放在函数中。另外,原始版本中有很多不必要的代码。例如,一旦修复了原始错误问题,target
变量就不再使用,view
变量已过时,createDropDownMenu()
函数是不必要的,因为所有这些代码都可以放在init(选项:)或openDropdown(:)函数中
然后,如果您选择使用该模板构建类,您将在ViewController的viewDidLoad()
方法中使用以下代码实现它:
let dropdown = DropDownMenu(titles: ["Title 1", "Title 2", "Title 3"])
self.view.addSubview(dropdown)
// Follow that with layout code that ensures it's the proper size and in the proper location
我希望结合我的评论有意义,有帮助,并且不会太过势不可挡。我建议您启动一个新的空项目(或目标),构建类并将其添加到ViewController中,而不包含任何其他内容。这是一个很好的方法来隔离它,检查并确保一切看起来都正常。如果您需要关于如何构建类的其他建议,您可以尝试将DropDownMenu设置为UIStackView
(而不是UIView
)的子类,主按钮和所有选项按钮都排列在子视图中。这实际上可能更简单,因为如果您愿意的话,它有点省去了中间人,打开/关闭下拉列表时需要做的就是从.arrangedSubviews
属性中添加/删除视图
同样重要的是,如果视图需要将信息(例如选择了哪个选项)传递回ViewController,请确保对ViewController的引用标记为弱
,这样就不会创建保留循环
最后一点,如果您对没有快速修复原始类的方法感到失望,并希望继续尝试,那么可能会有一些方法拼凑出一个解决方案(如我第一个答案中的代码,它确实有效…),但最终可能只会导致更多问题。所以,祝你一切顺利。我终于明白了!目标必须是下拉菜单
titleButton.addTarget(dp, action: #selector(dp.openDropDown(_:)), for: .touchUpInside)
下面是代码的其余部分
let titleButton = UIButton(frame: CGRect(x: 50, y: 290, width: 100, height: 40))
titleButton.backgroundColor = UIColor.white
titleButton.setTitle("Grade", for: .normal)
titleButton.setTitleColor(UIColor.black, for: .normal)
titleButton.layer.borderWidth = 2
titleButton.layer.cornerRadius = 10
let dp = DropDownMenu(options: ["1", "Freshman", "Sophomore", "Junior", "Senior", "College"])
dp.titleButton = titleButton
dp.target = self
dp.borderWidth = 2
dp.spacing = 5
dp.cornerRadius = 10
dp.bgColor = UIColor.white
将其添加到子视图并创建它。。