Reputation: 13
I had programmatically created some UIButtons in UIStackView. The StackView is an subView of original view controller.
How could I present another view controller by click button?
I had try control drag to create segue from original to destination controller and try to use self.performSegue(withIdentifier: "showMealTable", sender: self) for navigate.
But it throw error at runtime said "..has no segue with identifier 'showMealTable''".
It's my StackView class
@IBDesignable class TimeLineHeadControl: UIStackView {
//MARK: Properties
private let timeLineControllerInstance = TimeLineController()
....
button.addTarget(self.timeLineControllerInstance, action: #selector(TimeLineController.breakfastButtonTapped(button:)), for: .touchUpInside)
....
}
And my original view controller
class TimeLineController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//self.performSegue(withIdentifier: "showMealTable", sender: self)
}
...
@objc func breakfastButtonTapped(button: UIButton) {
print("at Time Line Controller")
self.performSegue(withIdentifier: "showMealTable", sender: self)
}
...
}
Upvotes: 1
Views: 3376
Reputation: 271660
Let's talk about the reasons for the error first.
Here:
private let timeLineControllerInstance = TimeLineController()
This VC you created with the above line is not the same VC that you are seeing in your app. This is another brand new instance of TimeLineController
, not initialised through the storyboard. Therefore, it does not have the segue.
You need to actually set the VC that is currently presented as timeLineControllerInstance
.
However, either way, you are violating MVC principles. TimeLineHeadControl
is a view. Views should not be dependent on controllers. Views can send out messages (target-action/delegates) and controllers can choose to listen to these. Controllers choose what views to control, not the other way round.
You should really call addTarget
in the view controller,
// in viewDidLoad
yourStackView.button.addTarget(self, action: #selector(breakfastButtonTapped(button:)), for: .touchUpInside)
or create a TimeLineHeadControlDelegate
and use the delegate pattern.
Upvotes: 1
Reputation: 203
you can do this by using code...
@objc func breakfastButtonTapped(button: UIButton) {
print("at Time Line Controller")
let vc = self.storyBoard.instantiateViewController(withIdentifier: "yourVCidentifier") as! YourVC
self.present(vc,animated: true, completion: nil)
}
if you want to do that with segue.. give storyBoard segue identifier to your segue and than call perform segue.
Upvotes: 0
Reputation: 888
By definition, a segue can't really exist independently of a storyboard. Even if you see the name of the class: UIStoryboardSegue. You cannot create segue programmatically but what you can do is set up the segue in storyboard and then have a function on that button and use the function to perform the action.
Moreover, you can even achieve this without using a segue. You can create a method in your common view controller (base class) that will transition to a new view controller. In your case, base class can be MealViewController and new view controller can be MealTableViewController.
- (IBAction)pushNewViewController
{
NewViewController *newVC = [[NewViewController alloc] init];
// do any setup you need for newVC like passing data.
[self presentModalViewController:newVC animated:YES];
}
Now you can call this method when the appropriate button is clicked.
Upvotes: 0