Pass data with segue without displaying screen - ios

I'm trying to achieve passing of data using segue, but without displaying the screen. There are two view controllers in my project and I will name them FirstViewController and SecondViewController.
On FirstViewController, I am using Show Adaptive Segue to pass data using performSegueWithIdentifier. The prepareForSegue method will be called, and recognising the identifier I've set to display SecondViewController.
However, the problem is I do not want to display SecondViewController. There are other things that my users may want to do before heading for SecondViewController.
I'm new to iOS programming, and I only know passing of data with segue. Please do share with me if there are methods to pass data apart from segue.
EDIT: To further elaborate my question. I'm working with TabBarController, and both View Controllers are accessible on the Tab bar. So when I am on SecondViewController with some data already "segue-ed" over from FirstViewController, I can head back to FirstViewController to add more data. At SecondViewController with UIRefreshControl I need the updated data.

If you do the segue in code you can do what you want in a following way
1) Instantiate view controller from the story board
let storyboard: UIStoryboard = UIStoryboard(name: "SecondViewController", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("set_it_in_IB") as! SecondViewController
2) Set the properties you need to set as the view controller is already instantiated
vc.someProperty = "asd"
3) Segue!
viewController.presentViewController(viewControllerToPresent: UIViewController, animated: Bool, completion: (() -> Void)?)
Hope that helps!

From your user's perspective, they would not know whether the data is being updated before they segue or not, so it is probably fine to just pass the data with the prepareFoSegue function.
Otherwise, you could try setting a notification to the viewDidLoad on your FirstViewControllerand SecondViewController by
NSNotificationCenter.defaultCenter().addObserver(self, selector: nil, name: updateSecondVCNotification, object: nil)
and posting the notification from the FirstViewController whenever the data needs to be updated using the
NSNotificationCenter.defaultCenter().postNotificationName(updateSecondVCNotification, object: self)
Then on second view controller set the the selector of the addObserver to a string of the name of whatever function you want it to do like "reloadNewData"
func reloadNewData() {
tableView.reloadData()
}
Does this help? Don't forget to set the updateSecondVCNotification as a global string constant at the top of your FirstViewController. Learn more about NSNotificationCenter at https://www.andrewcbancroft.com/2014/10/08/fundamentals-of-nsnotificationcenter-in-swift/
Woo! Notifications! \(^▽^)/

I'm not sure if that would work for you, but you could simply keep the data in memory of your FirstViewController for the time during which the user is still interacting and giving feedback and once it's done, send all the data to the SecondViewController through the segue.

Related

Swift 4, load next ViewController

In my app I have two View Controllers embedded in Navigation Controller. And I want to have an option to get data from the SecondVC while only the FirstVC is opened. So it's like I don't want a user to see (or at least interact) with the SecondVC.
The point is
So user just taps on the button on the FirstVC (without opening SecondVC before) and I can get access to the data on the SecondVC.
How can I get data from the next view controller (SecondVC) in a navigation controller without opening it? Or at least not letting user to interact with it.
For now my only ideas are:
To push segue when user taps a button, get it into memory, load data and then dismiss it. But that doesn't look good when view controllers change so fast.
To present next view controller modally offscreen, get data and dismiss it. So the user won't even see that another view controller opened.
Edit:
I need to get access not just to method or smth. I need to get to the #IBOutlet. To the subclass of UIView (working with CorePlot) to be exactly
You should never call loadView() directly.
Instantiate your UIViewController and then call loadViewIfNeeded().
Calling this method loads the view controller’s view from its storyboard file, or creates the view as needed based on the established rules.
EDIT:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// make sure that the value is an optional so that you can unset it later. This one is optional because we use optional casting (with as?)
var vc = storyboard.instantiateViewController(withIdentifier: "secondVC") as? SecondViewController
vc?.loadViewIfNeeded()
// use the vc
// later unset vc variable
vc = nil
for this, you must call your 2ed View controller with 'modalPresent' and background of 2edVC must clear. Then get your data from 2ed VC. with no change. for more information about modalPresent there is the link.
Solution:
You can create a function for it or just insert in viewDidLoad() etc.
Don't forget to change StoryboardID for the chosen view controller (it can be done in your storyboard file in Identity inspector).
// You need to get to your Storyboard and instantiate the needed View Controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
var graphVC = storyboard.instantiateViewController(withIdentifier: "graphVCID") as? graphVC
// Then call loadViewIfNeeded (don't call loadView()) to load #IBOutlet's etc
graphVC?.loadViewIfNeeded()
// My outlets are loaded with data when these functions are called
graphVC?.viewDidLoad()
graphVC?.viewWillAppear(false)
// Unset the reference to VC
graphVC = nil

SWIFT 3: Segue with navigation controller

I'm trying to send some values from one viewcontroller to another. (all embedded in NavigationController). I could make segue with normals viewcontrollers so in general I understand a segue idea. I've to do that in two different ways and got two different problems.
First way, segue does right but "two times". I mean after segue (which I want) there is another segue to same controller but without navigation controller and without data I would send. The "back" button on last viewcontroller is returning to AlmostViewController.
Here's code:
Second way, Nothing happened,
ErorCould not cast value of type 'RevisionApp.AlmostViewController'
(0x1055d58c0) to 'UINavigationController' (0x107669f18).
Here's code:
For the first Problem, When using embedded in navigation controller you have don't have to create action function when the button is tapped. Navigation controller does it for you. So things you need to do :
Disconnect the function btnTapped from the button using storyBoard.
Delete or comment the function btnTapped(You don't need it).
Problem is line number 18. You are trying to cast AlmostViewController to a UINavigationController. Directly access like this,
let detailController = segue.destination as! AlmostViewController
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("ViewController2") as NextViewController
self.presentViewController(nextViewController, animated:true, completion:nil)

Make Segue programmatically in Swift

I have two VCs: VC1 and VC2.
In VC1, I have a finish button which I programmatically made and a result array I want to pass to VC2.
I know how to make Segue in Storyboard, but I cannot do that at this moment since the finish button is programmatically made.
If I want to pass result array using segue, is there a way to make the segue programmatically? If this is not possible, should I just present VC2 using presentViewController and set a delegate to pass the result array?
You can do it like proposed in this answer:
InstantiateViewControllerWithIdentifier.
Furthermore I am providing you the code from the linked answer rewritten in Swift because the answer in the link was originally written in Objective-C.
let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewController(withIdentifier: "identifier") as! SecondViewController
vc.resultsArray = self.resultsArray
EDIT:
Since this answer draws some attention I thought I provide you with another more failsafe way. In the above answer the application will crash if the ViewController with "identifier" is not of type SecondViewController. In Swift you can prevent this crash by using optional binding:
guard let vc = UIStoryboard(name:"Main", bundle:nil).instantiateViewControllerWithIdentifier("identifier") as? SecondViewController else {
print("Could not instantiate view controller with identifier of type SecondViewController")
return
}
vc.resultsArray = self.resultsArray
self.navigationController?.pushViewController(vc, animated:true)
This way the ViewController is pushed if it is of type SecondViewController. If can not be casted to SecondViewController a message is printed and the application remains on the current ViewController.
You can still create the segue in Interface Builder by dragging from VC1 to VC2 - just drag from/to the little yellow circle at the top of the VC. Give this segue a unique name in IB, and in your finish function you can call performSegueWithIdentifier:, pass in the name of your segue, and that's it. In the prepareForSegue method you can find out which segue is being performed by accessing segue.identifier, and if it's the segue in question you can get a pointer to segue.destinationViewController and pass your data on that way.

Dismissing ViewController Scenario

I am new to Swift programming. I am stuck in one scenario.
When my app loads, the first screen gets in ViewController1 user's latitude and longitude and then gets the data from a backend API and loads the data in a table view controller. This code of getting user's location and loading table view controller is in ViewDidLoad method. In this ViewController1, I have a button when tapped, I am presenting a view controller (Which is embedded in a navigation controller) modally. The following lines of code I am using to present this new ViewController (ViewController2).
let VC2 = self.storyboard?.instantiateViewControllerWithIdentifier("NewVC2") as! NewVC2
let navController = UINavigationController(rootViewController: VC2)
VC2.delegate = self
self.presentViewController(navController, animated: true, completion: nil)
When I close the ViewController2 by saying self.dismissViewController, it closes and when the control comes back to ViewController1, ViewDidLoad is executed again and all the code of invoking backend API and getting user's location is getting invoked.
So, for passing data back from ViewController2 on dismissing it, I used the delegate pattern. Created a protocol and defined a method in this protocol.
protocol ViewControllerClosedDelegate {
func isViewControllerClosed(closed: Bool);
}
defined the object of delegate in ViewController2.
var delegate: ViewControllerClosedDelegate! = nil
and added the following code while dismissing ViewController2.
delegate.isViewControllerClosed(true)
self.dismissViewControllerAnimated(true, completion: nil)
made the ViewController1 to implement this ViewControllerClosedDelegate and added the following function.
func isViewControllerClosed(closed: Bool) {
self.isFromClosedVC = closed
print(isFromClosedVC)
}
isFromClosedVC is a global variable defined ViewController1.
the value is printing correctly (true in this case) as being passed from ViewController2 when it is dismissed but when I try to print this in ViewDidLoad, it is being printed as false.
I thought of getting this value from ViewController2, and if it is true, not to execute the code to get users location and data from backend API.
Basically, I am trying to get the user's location and getting the data from backend API once and update my table view only on Swipe to refresh.
How do I achieve this? Please help.
Thank you.
Raj

Change view controller when user exits app

Hey I am trying to make it so whenever the user presses the home button and then try to returns to my app, they are returned to the initial view controller. Is there anything I can write into the app delegate to get this to work?
I have tried to call this function in the applicationDidBecomeActive function:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let VC = storyboard.instantiateViewControllerWithIdentifier("homeVC") as! UIViewController
self.window?.rootViewController?.presentViewController(VC, animated: true, completion: nil)
But i get an error saying the view is not in the hierarchy.
Any help will be appreciated!
You want to implement the applicationDidBecomeActive method of your App's delegate, and programmatically perform a segue or dismiss the current view controller, depending on the navigation setup.
Your users might not like forced navigation though. The general assumption is that they can resume where they left off.
Well, every time the app is closed applicationDidEnterBackground in your AppDelegate is called. You can use that to present your view controller.

Resources