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
Related
I want to pass data from ViewController1 to ViewController2. ViewController2 is embedded within a Navigation Controller (because I have a Segmented Control that corresponds to 3 Child View Controllers). My segue is directly from ViewController1 to the Navigation Controller.
I tried the following in ViewController1:
ViewController2().testID = "test value"
With the following in ViewController2:
var testID = ""
However testID does not update when I run print(testID) in ViewController2.
What is recommended for passing data from ViewController1 to ViewController2? Any help/advice is much appreciated!
You can pass the value by overriding the prepare(for segue:) function in ViewController1
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination
guard let destination = segue.destination as? UINavigationController else {
return
}
guard let finalDestination = destination.viewControllers.first as? ViewController2 else {
return
}
finalDestination.testID = "Test Value"
}
NSUserDefaults will always work.
I am trying to push some data back to the previous view controller ( Let's call this AViewController ) from my current one ( Let's call this BViewController )
however, when I use performSegue method it shows me the AViewController I wanted but makes the tab bar controller at the botton of the screen disappear (iirc this is because it creates a new "view" with the performSegue method?)
but when I use the dismiss method no data is passed back (neither in the completion with self.performSegue)
So how do I push my data back to AViewController while still have my tab bar controller at the bottom?
Here's my code
// Push data to AViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var aViewController = segue.destination as? AViewController
if routineReps.isEmpty == false {
for i in 0...routineReps.count-1 {
routineViewController?.workOutNameArray.append(routineNames[i])
routineViewController?.workOutSetsArray.append(routineSets[i])
routineViewController?.workOutRepsArray.append(routineReps[i])
}
}
}
// Button Action to push data back to previous viewcontroller
#IBAction func completeAddingWorkoutButton(_ sender: UIButton) {
self.performSegue(withIdentifier: "addWorkoutsForTodaySegue", sender: self)
}
As mentioned you can use Delegates or NSNotificationCenter or Singleton Patterm
Scenario is you navigate from Class A to Class B and now want to pass data from Class B to A while you come back to Class A, you want to have that passed data
Class A -> Navigates -> Class B
<- Sends Data back
Delegate -
Define a protocol in Class B
Class BViewController
#objc
protocol ClassBDelegate {
func passingSomeValue(val : String)
}
class BViewController{
weak var delegate : ClassBDelegate! //define a variable of the protocol
func passValueWhenFromThisMethod(){
let someString = "this value will get passed"
delegate.passingSomeValue(someString)
self.navigationController?.popViewController(animated: true)
}
}
Class AViewController
class AViewController{
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let segue.identifier = "segueidentifierforgoingtoclassBVC"{
var classBVC = segue.destinationViewController as! BViewController
classBVC.delegate = self
}
}
}
extension AViewController : ClassBDelegate{
func passingSomeValue(val : String){
print("Got this value from Class B: \(val)")
}
}
use delegate to pass data to previous ViewController following the method given in link below:
Passing data back from view controllers Xcode
I want to segue from a view container within "H" that is presented using the navigation controller connected to the Split View Controller. How can I accomplish this? I have tried regular performSegueWithIdentifier using locally linked storyboard ID's but that removes the top navigation bar. I want to retain the top navigation bar and execute the segue as if it was done using the master navigation controller (rows that select which view controller is being presented in the detail view).
Any help is greatly appreciated!
Here is an example of how to perform a segue from an embedded ViewController.
ViewController.swift
import UIKit
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
class ViewController: UIViewController, SegueHandler {
func segueToNext(identifier: String) {
self.performSegueWithIdentifier(identifier, sender: self)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destinationViewController as! HViewController
dvc.delegate = self
}
}
}
HViewController.swift
import UIKit
class HViewController: UIViewController {
weak var delegate: SegueHandler?
#IBAction func pressH(sender: UIButton) {
delegate?.segueToNext("GoToGreen")
}
}
Setup:
Use delegation to have the HViewController tell its embedding viewController to perform the segue.
Create a protocol called SegueHandler which just describes a class that implements the method segueToNext(identifier: String).
protocol SegueHandler: class {
func segueToNext(identifier: String)
}
Make your viewController implement this protocol by adding it to the class declaration line:
class ViewController: UIViewController, SegueHandler {
and by implementing the required function.
Add a delegate property to HViewController:
weak var delegate: SegueHandler?
Click on the embed segue arrow between ViewController and HViewController. Give it the identifier "EmbedH" in the Attributes Inspector.
Create a show segue between ViewController and the GreenViewController by Control dragging from the viewController icon at the top of ViewController to the GreenViewController. Name this segue "GoToGreen" in the Attributes Inspector.
In prepareForSegue for ViewController, when the "EmbedH" segue happens, set the delegate property of HViewController to self (ViewController).
When the user clicks the H button in the HViewController, call delegate?.segueToNext("GoToGreen") to trigger the segue in ViewController.
Here it is running in the simulator:
I was needing exactly what #vacawama proposed here, though I couldn't reproduce that, I tried exactly your steps but self.delegate?.segueToNext("GoToGreen") got called but neither the protocol itself nor the container view controller. After an entire day searching about this approach I realized the problem was with the swift version. Just replace this:
func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
for this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "EmbedH" {
let dvc = segue.destination as! HViewController
dvc.delegate = self
}
}
Other detail I was missing was about the embedded segue. Be sure to connect the container View to the HViewController, not the View Controller itself, otherwise the Embed option for segue won't appear.
I know this is Duplicate Question, but i didn't find the solution for my problem. I have two controllers. HomeViewcontroller's variable of "myValue"'s value can't be set by using ViewController class.I don't know the issue here but code is working without error.But when i print "myValue" it shows nil.Destination view controller is not the controller that i want to set variable value. Destination view controller is a tab bar controller, so i want to set the variable value of first tab bar and second tab bar view controllers. This is my code :-
import UIKit
class ViewController: UIViewController {
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if(segue.identifier == "gotoHome") {
println("1111")
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var viewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
viewController.myValue = 8888
}
}
}
this is the other view controller
import UIKit
class HomeViewController: UIViewController {
var myValue: Int!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
println(myValue)
}
}
You don't need to instantiate the viewcontroller, as it is already been done, you just need to fetch the viewcontroller for the current segue operation, so your code should look like below
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if(segue.identifier == "gotoHome") {
println("1111")
let controller = segue.destinationViewController as! UITabBarController
let homeController = controller.selectedViewController as !HomeViewController
homeController.myValue = 8888
}
}
Hope it helps.
Change to :
let viewController = segue.destinationViewController as! HomeViewController
You're printing the value of myValue in viewDidLoad which is called when you're instantiating it from your storyboard. You're setting myValue after creating your instance. Try to print myValue in viewWillAppear for example, then it should be set.
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.