为什么我的 UIBarButtonItem 不调用我的自定义函数?

Why isn't my UIBarButtonItem calling my custom function?

我有一个 UIViewController 和一个 UIBarButtonItem 配置为调用我的自定义函数 func settingsTapped(sender: AnyObject?),我在其中放置了 performSegueWithIdentifier。我已经确定这个函数没有被调用,即使按钮确实有效并且 segue 仍然有效,因为它转到了正确的视图控制器。

第一个VC:

class CalculatorViewController: UIViewController {

  private let timeInterval = 0.016 //how frequently we change the displayed number
  private let animationLength = 0.3
  private var timer: NSTimer?
  private var counter: Int = 0
  private var max: Double = 0.0
  var startingPreferredUnits: String?
  @IBOutlet weak var weightLifted: UITextField!
  @IBOutlet weak var repetitions: UITextField!
  @IBOutlet weak var oneRepMax: UILabel!
  @IBOutlet weak var percentages: UITextView!
  @IBOutlet weak var units: UILabel! 

  override func viewDidLoad() {

    let settingsButton = UIBarButtonItem(title: "Settings", style: .Plain, target: self, action: #selector(settingsTapped(_:)))

    self.navigationItem.leftBarButtonItem = settingsButton

    super.viewDidLoad()
  }

 func settingsTapped(sender: AnyObject?) {
    startingPreferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
    print("In segue, units is \(startingPreferredUnits)") // never prints this caveman debugging 
    self.performSegueWithIdentifier("segueToSettings", sender: self)
  }
}

在故事板中,我在导航栏中放置了一个栏按钮项目:

我在“设置”栏按钮项和“设置”视图控制器之间创建了一个显示(例如推送)转场,并为该转场提供了“segueToSettings”标识符。当我触摸“设置”按钮时,它会显示“设置”视图控制器,但不会将我的穴居人调试行打印到控制台。

我还尝试在 CalculatorViewController 本身和 SettingsViewController 之间创建 segue(我认为这甚至可能是更好的方法)但是当我以这种方式设置它时,什么也没有发生当我触摸“设置”按钮时。

我已经尝试了我能在 SO 上找到的所有内容,但没有任何效果。我希望我不会在这个问题上获得愚蠢问题徽章。

更新 1:

我还在为这个问题苦苦挣扎。这是我学到并尝试过但没有用的其他东西。单击“设置”按钮通过执行从按钮到我在 Storyboard 中创建的“设置”页面的转场来工作。正如人们所预料的那样,它会在执行此操作之前调用 override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 。所以它完全忽略了 action: #selector(settingsTapped(_:)) 部分。另外,我可以在故事板中更改 segue 的标识符,这完全没有区别。它仍然有效。我什至可以删除标识符并且它有效。

我也试过添加另一个按钮(这次是 barButtonSystemItem 像这样:

 override func viewDidLoad() {
    super.viewDidLoad()

    let settingsButton = UIBarButtonItem(title: "Settings", style: .Plain, target: self, action: #selector(settingsTapped(_:)))

let saveButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(self.saveThisLift(_:)))

    self.navigationItem.leftBarButtonItem = settingsButton
    self.navigationItem.rightBarButtonItem = saveButton
  }  


  func saveThisLift(sender: UIBarButtonItem) {
    print("I'm in saveThisLift") // never prints
    let weight = weightLifted.text
    let reps = repetitions.text
    let maxAmount = oneRepMax.text
    let unitsText = units.description

    coreDataStack.saveLiftEvent(currentLiftName!, formula: currentFormulaName!, weight: weight!, repetitions: reps!, maxAmount: maxAmount!, unitsUsed: unitsText)
}

 func settingsTapped(sender: AnyObject?) {
        startingPreferredUnits = UserDefaultsManager.sharedInstance.preferredUnits
        print("In segue, units is \(startingPreferredUnits)") // never prints this caveman debugging 
        self.performSegueWithIdentifier("segueToSettings", sender: self)
      }

就像“设置”按钮一样,触摸它除了使其闪烁外什么也做不了。我应该指出,我通过故事板添加了条形按钮项目,我认为这是不必要的,因为我试图以编程方式添加它们。但是,如果没有它们,这两个按钮都不会出现。

经过更多的研究和更多的试验和错误,我已经弄明白了。我学到了很多东西,我会留在这里供将来遇到此问题的任何人使用。

在高层次上,尝试在情节提要中执行一些操作而在代码中执行一些操作很容易让人感到困惑。对我来说关键是:

  1. 我不是在处理 UINavigationController 及其开箱即用的根视图控制器,而是在处理 UIViewController。使用 UINavigationController,您不必做那么多。但是对于 UIViewController,我必须添加一个 UINavigationBar,并且我必须添加一个 single UINavigationItem。我通过将它们从对象库拖到我的故事板来做到这一点。
  2. 不要试图在 UINavigationBar 中放置 UILabel 来做我想做的事情,这是让他们调用自定义函数。相信我,这是行不通的,至少对我而言是这样。
  3. 搞清楚后需要加一个UINavigationItem,下一个啊哈!对我来说最重要的是我可以在其中放入 multiple UIBarButtonItems (注意:我在问题中的示例只显示了一个以保持简单,但我实际上添加了三个项)
  4. 拼图的神奇之处在于将我的代码连接到故事板。我只是从我的 UINavigationItem 按住 Ctrl 单击到我的视图控制器,并创建了一个名为 @IBOutlet weak var navItem: UINavigationItem!
  5. 的 @IBOutlet
  6. 我创建按钮并将它们添加到视图的代码像这样使用这个出口(简化):

_

class CalculatorViewController: UIViewController {

  @IBOutlet weak var navItem: UINavigationItem!

  override func viewDidLoad() {
    super.viewDidLoad()

    let settingsButton = UIBarButtonItem(title: "Settings", style: .Plain, target: self, action: #selector(self.segueToSettings(_:)))

    let viewLogButton = UIBarButtonItem(title: "Log", style: .Plain, target: self, action: #selector(self.segueToLog(_:)))

    let saveButton = UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: #selector(self.saveLift(_:)))

    self.navItem.leftBarButtonItem = settingsButton
    self.navItem.rightBarButtonItems = [saveButton, viewLogButton] 
  }

func saveLift(sender: AnyObject) {
    let weight = weightLifted.text
    let reps = repetitions.text
    let maxAmount = oneRepMax.text
    let unitsText = units.text

    coreDataStack.saveLiftEvent(currentLiftName!, formula: currentFormulaName!, weight: weight!, repetitions: reps!, maxAmount: maxAmount!, unitsUsed: unitsText!)

    performSegueWithIdentifier("segueToLog", sender: self)
  }
}

最后,当你创建那个@IBOutlet 时,不要将它命名为 navigationItem: UINavigationItem 因为这会让 Xcode 非常不高兴:

我在这上面耗费了很多时间。我希望这些信息可以帮助人们在将来避免这种情况。