Reputation: 1460
I have a method called selectionDidFinish(controller:)
in a delegate to dismiss the viewController the delegate presented. The presented controller, which adopts my Dismissable
protocol, has a UIBarButtonItem
with an action attached to it that should call the selectionDidFinish(controller:)
method but it's giving me the "Argument of '#selector' does not 'refer' to an initializer or method" error.
The error is in this presented UIViewController
:
class FormulaInfoViewController: UIViewController, Dismissable {
weak var dismissalDelegate: DismissalDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Xcode doesn't like this selector
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(dismissalDelegate?.selectionDidFinish(self)))
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I've confirmed that the dismissalDelegate
is getting set properly to FormulasTableViewController
so I can't understand why it can't see dismissalDelegate?.selectionDidFinish(self))
.
The relevant code of my presenting UIViewController
is:
class FormulasTableViewController: UITableViewController, DismissalDelegate {
let formulas: [CalculationFormula] = [
CalculationFormula.epley,
CalculationFormula.baechle,
CalculationFormula.brzychi,
CalculationFormula.lander,
CalculationFormula.lombardi,
CalculationFormula.mayhewEtAl,
CalculationFormula.oConnerEtAl]
override func viewDidLoad() {
super.viewDidLoad()
let liftInfoImage = UIImage(named: "info_icon")
let liftInfoButton = UIBarButtonItem(image: liftInfoImage, style: .Plain, target: self, action: #selector(self.segueToFormulaInfo(_:)))
self.navigationItem.rightBarButtonItem = liftInfoButton
}
func selectionDidFinish(controller: UIViewController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let nav = segue.destinationViewController as! UINavigationController
let vc = nav.topViewController as! Dismissable
vc.dismissalDelegate = self
}
func segueToFormulaInfo(sender: UIButton) {
performSegueWithIdentifier("segueToFormulaInfo", sender: self)
}
}
I've done all kinds of research on how to use #selector
and I thought this post had all the answers, but it doesn't.
I've tried this Dismissable protocol with and without exposing it to @objc
:
@objc protocol Dismissable: class {
weak var dismissalDelegate: DismissalDelegate? {
get set }
}
And I've also tried it with my DismissalDelegate protocol:
@objc protocol DismissalDelegate : class {
func selectionDidFinish(controller: UIViewController)
}
extension DismissalDelegate where Self: UIViewController {
func selectionDidFinish(viewController: UIViewController) {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
I can't expose my protocol extension to @objc
- is that why this doesn't work? Is my #selector
really the problem here? Does it have something to do with my protocols?
EDIT: Final fix
Based on the accepted answer, I added a function to do the dismissal:
func dismiss() {
dismissalDelegate?.selectionDidFinish(self)
}
and then called the selector like this:
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(dismiss))
Upvotes: 1
Views: 5346
Reputation: 114846
You can't have the action
parameter specify an arbitrary expression. It needs to invoke a specific selector - a class and function in that class.
You will need to create a function in your class that invokes the delegate method:
class FormulaInfoViewController: UIViewController, Dismissable {
weak var dismissalDelegate: DismissalDelegate?
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Done", style: .Plain, target: self, action: #selector(FormulaInfoViewController.selectionDidFinish)
}
@objc func selectionDidFinish() {
self.dismissalDelegate?.selectionDidFinish(self)
}
}
Upvotes: 3