Simply I have one segue of kind Show from FirstViewController to the SecondViewController.
I call it on iPad and iPhone from two places of my FirstViewController. It is ok, but in one case I need to present SecondViewController as a .Popover.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let secondViewController = segue.destinationViewController as? SecondViewController {
if let cell = sender as? UITableViewCell, indexPath = tableView.indexPathForCell(cell) {
let student = fetchedResultsController.objectAtIndexPath(indexPath) as! Student
secondViewController.schoolClass = schoolClass
secondViewController.student = student
} else {
secondViewController.modalPresentationStyle = .Popover
secondViewController.schoolClass = schoolClass
let popoverPresentationController = studentFormViewController.popoverPresentationController
popoverPresentationController!.delegate = self
popoverPresentationController?.permittedArrowDirections = .Up
popoverPresentationController?.barButtonItem = addStudentBarButtonItem
}
}
}
It doesnt work.
Any ideas how to override kind of segue from storyboard in code?
You should use custom segues:
implement custom segue by subclassing UIStoryboardSegue class and override prepare() method. (In prepare() method you implement all required behaviour (controllers animation, presentation and so on depending on your case);
Change you segue type from push to custom in the interface builder, and pick your implementation in class property (like on image below)
Best regards!
Related
I have been struggling to implement an example of protocol and delegate.
My MainVC has a Modal Segue to a CategoryVC but the CategoryVC sends the user to a DetailVC.
I need to set the MainVC as the delegate for the DetailVC, but all of the examples I can find set the MainVC as the delegate of the DetailVC when the MainVC instantiates the DetailVC.
My DetailVC is not instantiated by the MainVC.
I want to accomplish
detailVC.delegate = self
But because I'm using Interface Builder Modal Segues, I don't know how to refer to the object.
Edit:
MainVC has an image being edited and the functionality to add overlays
CategoryVC has categories of overlays
DetailVC has a UICollectionView showing all of the overlays to choose from
I want DetailVC to pass to MainVC which overlay to add to the image
So the sequence goes MainVC (modal segue) -> CategoryVC (Modal segue) -> DetailVC
It sounds like CategoryVC needs to relay the info about mainVC to DetailVC.
You could give CategoryVC a property theMainVC that it would use to remember the MainVC.
So in MainVC's prepareForSegue:
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let theCategoryVC = segue.destination as? CategoryVC {
theCategoryVC.theMainVC = self
}
}
Then in your CategoryVC:
var theMainVC: MainVC?
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let theDetailVC = segue.destination as? DetailVC {
theDetailVC.delegate = theMainVC
}
}
There are many solutions to your current problem
1- Chain delegate
protocol MYDataSender {
func myDele(str:String)
}
class MainVC:UIViewController,MYDataSender{
func myDele(str:String) { print(str) }
}
when present CategoryVC
let cat = ///
cat.delegate = self // if you don't use self.present(vc ,,, then it would be inside prepareForSegue
class CategoryVC:UIViewController{
var delegate:MYDataSender!
}
when present DetailsVC
let det = //
det.delegete = delegate // rhs is CategoryVC'sdelegete = MainVC , if you don't use self.present(vc ,,, then it would be inside prepareForSegue
class DetailsVC:UIViewController{
var delegate:MYDataSender!
func send() {
delegate.myDele(str:"sendToMain")
}
}
2- NotificationCenter // the easiest
3- Shared singleton
4- Store Data
I have 12 ViewControllers. My code gives a random segue to one of these ViewControllers (1-12)
let segues = ["View1", "View2", "View3", "View4", "View5", "View6", "View7", "View8", "View9", "View10", "View11", "View12"]
let index = Int(arc4random_uniform(UInt32(segues.count)))
let segueName = segues[index]
self.performSegueWithIdentifier(segueName, sender: self)
.
Now, I want to change a variable in the random ViewController that has been chosen (var firstSegue = false) but I can't figure out how?
.
Could someone change this into something that will work?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as UIViewController
destinationVC.firstSegue = true
}
Make a protocol with the firstSegue property and extend that to all of your view controllers. Then use as? TheProtocolYouMade instead of as UIViewController
Or use a common sub-class.
EDIT: sample code
Make a protocol with the firstSegue property
protocol P {
var firstSegue: Bool { get set }
}
extend that to all of your view controllers.
extension YOURViewController1: P {
}
It is assumed that YOURViewController1 has a var firstSegue: Bool in it. Now that property is how YOURViewController1 conforms to protocol P. Do this for all view controllers that have that property.
Now you can write this code
if let asP = segue.destinationViewController as? P {
// you can access asP.firstSegue here
}
As this controller has property that's not from standard UIViewController, than it's some custom controller, so you can cast it and than fill this value. As well you can use KVC - which is not really safe solution.
I'm trying to pass Realm data from Custom cell to Detail TableView Controller
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTask" {
let nextViewController = segue.destinationViewController as! TaskViewTableViewController
let indexPath : NSIndexPath = self.tableView?.indexPathForSelectedRow as NSIndexPath!
let task = tasks![indexPath.row]
nextViewController.name = task.name
nextViewController.notes = task.notes
nextViewController.date = task.date
nextViewController.timeLength = task.timeLength
}
}
I'm getting error
Could not cast value of type 'Taskio.TaskListTableViewController'
(0x10001f028) to 'Taskio.TaskViewTableViewController' (0x10001f280).
Also tried
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "viewTask" {
let nav = segue.destinationViewController as! UINavigationController
let nextViewController = segue.destinationViewController as! TaskViewTableViewController
let indexPath : NSIndexPath = self.tableView?.indexPathForSelectedRow as NSIndexPath!
let task = tasks![indexPath.row]
nextViewController.name = task.name
nextViewController.notes = task.notes
nextViewController.date = task.date
nextViewController.timeLength = task.timeLength
}
}
and also
let nextViewController : TaskViewTableViewController = segue.destinationViewController as! TaskViewTableViewController
EDIT
Forgot to put class name into storyboard of tableViewController. It's working
For me the problem was i forgot to put class name in storyboard
It seems that your destinationViewController is not of the type that you are expecting. You will need to check the segue to make sure it's pointing to the correct controller. If it is, you'll need to revisit your controller class hierarchy.
Are TaskListTableViewController and TaskViewTableViewController part of the same class hierarchy? Per the Swift docs on typecasting, you can only downcast from TaskListTableViewController to TaskViewTableViewController if your List view is a subclass of your Task view. It is not enough that both are simply subclasses of UITableViewController.
In other words, if your class hierarchy looks like this, you will not be able to downcast from the List view to the Task view:
----> TaskListTableViewController
/
UITableViewController
\
----> TaskViewTableViewController
But if your hierarchy looks like this, you will be able to downcast from one to the other:
UITableViewController -> TaskListTableViewController -> TaskViewTableViewController
Regarding your second attempt at casting to UINavigationController, the navigation controller is not related to UITableViewController at all, so it cannot be type casted to that class either.
You can check out the inheritance hierarchy for UINavigationController and UITableViewController. One needs to be a subclass of the other for any type casting to work. You'll see that is not the case.
If I understand from the error message, you are attempting to cast a TaskListTableViewController to TaskViewTableViewController.
The destination is a TaskListTableViewController so you have to treat it like one.
let nextViewController = segue.destinationViewController as! TaskListTableViewController
I'm a beginner. I am doing a popover when a button is pressed which then instantiates another view controller where the user can select from 5 choices. I want to be able to save the sender.tag of the button from the first view controller (where code snippet below came from) and pass it to the second where I can save them together to Parse. I'm not using a segue so I can't pass it that way. Thanks in advance!
func showPopover(sender: UIButton) {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("SelectionViewController")
vc!.modalPresentationStyle = .Popover
vc!.preferredContentSize = CGSizeMake(150, 30)
if let presentationController = vc!.popoverPresentationController {
presentationController.delegate = self
presentationController.permittedArrowDirections = .Up
presentationController.sourceView = self.view
presentationController.sourceRect = sender.frame
self.presentViewController(vc!, animated: true, completion: nil)
}
}
The easiest way would be to declare a variable var myVariable = Int() outside of either view controller class. Then, inside of your main VC and before you instantiate the popover, save the tag to the variable. You'll be able to use it inside the popover.
You could just use a segue (why aren't you?)
You put a property for the tag in the popover and set it in the first view controller, inside
func prepareForSegue(_ segue: NSStoryboardSegue, sender sender: AnyObject?).
To perform the segue, you just use
func performSegueWithIdentifier(_ identifier: String, sender sender: AnyObject?)
, inside your function
func showPopover(sender: UIButton)
If you don't want to use a segue you can simply cast the controller you get from instantiateViewControllerWithIdentifier() to your subclass.
Swift 2.0
func showPopover(sender: UIButton) {
guard let vc = self.storyboard?.instantiateViewControllerWithIdentifier("SelectionViewController") as? MYViewController
} else {
print("This is not the view controller you were looking for..."
return
}
vc.myVariableName = sender.tag
...
}
This is a totally dumb question I am sure. I have a viewcontroller that is inside a navigation controller that is inside a TabBarController. Apple says this is the right way to implement that setup. However, how can I prepareForSeque to that complex and send data to the first ViewController.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "presentActionItems" {
println("preparing")
let tabBarController:actionItemsTabController = segue.destinationViewController as! actionItemsTabController
let navigationController = ???
let viewController = ???
viewController.givenURL = actionItemsURL
}
}
I am sure this is an easy question, can I have some help.
Try this in your TabController's viewDidLoad after passing it your data
let firstViewController : UIViewController = self.viewControllers.objectAtIndex(0).topViewController;
firstViewController.this = self.this;
firstViewController.that = self.that;