prepareForSegue can't get the destination view controller on iOS 7 - ios

I have to write an iOS app that supports both iOS 7 and 8 and in this app I have two view controllers A and B with navigation controllers and a segue between them. When the segue activates, I have to fetch data from the view controller A to the view controller B. My code works perfectly on iOS 8 but not on iOS 7.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if segue.identifier == userDataSegue {
let navController = segue.destinationViewController as? UINavigationController
if let userDataTableViewController = navController?.topViewController as? UserDataTableViewController {
userDataTableViewController.userData = user
}
}
}
Do you know why does this happen and how can I fix it? I could "work around" the problem by saving stuff in NSUserDefaults and reading it in the vc B but that would make my code a mess.
I appreciate any help :D

Don't forget to create a public property userData in Second ViewController.
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)
{
if (segue.identifier == "segueTest") {
var svc = segue!.destinationViewController as secondViewController;
svc.userData = user
}
}

Related

Unable to pass data to View Controller embedded in nav bar

I am trying to do something this:
I want to pass some data to ApplicationsViewController which is embedded in nav bar, therefore I get the error: Could not cast value of type 'UINavigationController'
I am not able to understand how to implement the same. Help is much appreciated. Thank you.
The reason is you can't pass data directly to ApplicationViewController as InboxViewController segue's destination is UINavigationController.
So, first you need to access UINavigationController and after that ApplicationsViewController from the stack.
Try the code below:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToApplications" {
if let navigation = segue.destination as? UINavigationController, let applicationVC = navigation.topViewController as? ApplicationsViewController {
applicationVC.id = "RGB"
}
}
}
when pass data application view controller which is rootviewController of UINavigationController. you should give segue name of navigation controler and type cast as UINavigationController as destination viewcontroller.
Fetch rootviewController which is application View controller and assign value of id
Here is code how to assign value to Application ViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
if segue.identifier == "navigationSegue" { // segue of navigationVC
let navVc = segue.destination as! UINavigationController
let appVc = navVc.viewControllers.first as! ApplicationsViewController
appvc.id = "RGB"
}
}

Programmatic embed segue

I'm using a Page View Controller to implement an image carousel in my app. I have a container view in my parent view controller which has an embed segue to the Page View Controller. The problem I'm having is when I need to go off and fetch these images asynchronously and the segue happens before viewDidLoad gets the images.
My prepare for segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "startCarousel" {
let carouselPageViewController = segue.destination as! CarouselPageViewController
carouselPageViewController.images = carouselImages
}
}
in viewDidLoad:
GalleryManager.sharedInstance.getData = {
(data) in
// Assign images to instance property here ...
}
My thinking is that once I get the images that I programmatically start the segue myself. Or if I should be doing this a different way any advice would be much appreciated.
You can do something like, return false in shouldPerformSegue and initiate segue when data is loaded
i.e.
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
if identifier == "startCarousel" {
return (detail != nil)
}
return true
}
Then in viewDidLoad
GalleryManager.sharedInstance.getData = { [weak self]
(data) in
self?.performSegue(withIdentifier: "startCarousel", sender: nil)
}
No, you can't delay an embed segue. If you use an embed segue it fires as soon as the view controller is loaded.
You need to wait until the data loads and then call the setViewControllers(direction:animated:completion) to install the view controllers that you will use to display the data once the data is loaded.
Swift 3, Xcode 8
You can realize in this way:
set a reference to your page view controller in prepareForSegue in your masterViewController:
var myContainerViewController: UIPageViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier == "embedSegue" {
if let destination = segue.destination as? YourPageViewControllerClass {
self.myContainerViewController = destination
}
}
Define a function in your own pageViewController class:
func someFunction(){
//configure your image or swipe page
}
when you get the images, in your masterViewController call:
self.myContainerViewController?.someFunction()
you can't delay an embed segue.
you try to put button in view controller and then after view load set button click to set image...

UISplitViewController return from master to detail

Is it possible on iPhone via UISplitViewController to return from the master controller to the detail one? I have tried in master changing displayMode to PrimaryHidden, using showDetailViewController with splitViewController?.viewControllers[0], but nothing was able to show back the detail controller.
I would like to have both controllers without dismissing and reloading, because one includes a map and the second one preferences of map objects.
Lets say you have a button in the master view which when pressed will take you to detail view. Here is an example how that would go
#IBAction func buttonToGoToDetailView(sender: UIButton) {
performSegueWithIdentifier("segue id in storyboard", sender: nil)
}
// prpare for segua to detail view
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destination = segue.destinationViewController as? UIViewController
if let dvc = destination as? NameOfTheDetailViewController{
if segue.identifier = "segue id in storyboard" {
//use dvc to pass data to the detail if there is any
}
}
}

Push doesn't work after back button?

I'm working on an app that scans a barcode and segues into a new view controller after a scan is found. However, if the user clicks the back button (navigation controller, root view controller is a main menu, but is [probably] irrelevant), the view controller will not segue again. So it segues forward to view controller 3 the first time the app runs, but upon hitting "back" and returning to VC 2, it won't segue to VC 3 again. Is there something I'm missing? I do set the handler in viewDidLoad:
self.barcodesHandler = { barcodes in
if(self.handler_flag) {
var barcode = barcodes[0]
println("Barcode found: type=" + barcode.type + " value=" + barcode.stringValue)
self.bcode = barcode.stringValue
self.handler_flag=false
self.performSegueWithIdentifier("push", sender: nil)
}
}
And the segue:
override public func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let destinationVC = segue.destinationViewController as! SecondViewController
destinationVC.setText = bcode
}
Thanks so much!
self.performSegueWithIdentifier("push", sender: nil)
Instead of nil use self

Can't embed in navigation controller if I am passing data with prepareForSegue

I am working on a custom camera app where I present 3 viewControllers modally. At each segue, I pass data with prepareForSegue function. My problem is after the work with camera is finished, I need to show 2 more viewControllers which need to be inside a navigationController.
I have realized that If I don't pass any data, the navigation controller works fine. However, when I pass data, the app crashes on runtime. What is the right way of doing this?
Here is my prepare for segue function;
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "camera2Crop"{
let controller: CropViewController = segue.destinationViewController as CropViewController
controller.photoTaken = self.photoTaken
}
}
where photoTakenis an UIImage object. Moreover, here is the screenshot from my storyboard where I put the navigationController. I call the prepareForSeguefunction in CustomCameraViewController to segue to CropViewController.
EDIT: I have changed my prepareForSegue to the following code;
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "camera2Crop" {
let controller: CustomNavigationController = segue.destinationViewController as CustomNavigationController
controller.photoTaken = self.photoTaken
}
}
Now the app does not crash but I don't know how to send an object through Navigation Controller
let controller: CropViewController = segue.destinationViewController as CropViewController
Double check if segue.destinationViewController is actually the navigation view controller.
If it's the navigation controller, get CropViewController from it:
if segue.identifier == "camera2Crop" {
let navController = segue.destinationViewController as UINavigationController
let controller = navController.viewControllers[0] as CropViewController
controller.photoTaken = self.photoTaken
}
Note you don't have to subclass UINavigationController.

Resources