Swift transit from vc to another vc - swift

ViewController has a label and a button for go to secondVC. And secondVC has a text field , label , button to write user-entered text in the text field on the label. When user press the back button of navigation bar, I want transit secondVC's label's text to ViewController's label's text. How can I do this ?
ViewController's code:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func goVC2(_ sender: Any) {
performSegue(withIdentifier: "toVC2", sender: nil)
}
}
secondVC's code:
import UIKit
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
resultLabel.text = nameField.text
}
}
I tried prepare for segue in ViewController and but it was error. And I searched on google for this but I couldn't find solution.

Use protocol for pass data from second VC to first VC. you need to create your own delegate method and call on dismiss with pass data, check below code :----
ViewController's code:
import UIKit
class ViewController: UIViewController, Delegate {
#IBOutlet weak var nameLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func save(str : String) {
self.nameLabel.text = str
}
#IBAction func goVC2(_ sender: Any) {
if let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "secondVC") as? secondVC {
vc.delegate = self
self.present(vc, animated: true, completion: nil)
}
}
}
secondVC's code:
import UIKit
protocol Delegate : AnyObject {
func save(str : String)
}
class secondVC: UIViewController {
#IBOutlet weak var nameField: UITextField!
#IBOutlet weak var resultLabel: UILabel!
weak var delegate : Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func saveClicked(_ sender: Any) {
if let del = self.delegate {
let txt = nameField.text
del.save(str: txt)
self.dismiss(animated: true, completion: nil)
}
}
}

Related

How to show containerview in viewcontroller in swift

I need to show containerview in viewcontroller, so i have taken one viewcontroller and designed and in that i have taken one containerview below to the buttons view
given containerview constraints: below to the buttonview
top = buttonview.bottom 10, leading, trailing, bottom = 0
there are two buttons indicates with green line.. initially i am in the "viewproposalvc" with red colour button.. here if i click gray colour button then i need to show containerview
here the viewproposalvc code:
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ContainerVC") as? ContainerVC
vc.serviceId = self.viewproposalData?.result?.posted_services?.id
self.navigationController?.pushViewController(vc!, animated: true)
}
#IBAction func redBtn(_ sender: Any) {
containerView.isHidden = true
postedServicesCall()
}
}
this is containervc code:
class ContainerVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
}
}
but here containervc not coming below to the buttonsview.. its coming in separate viewcontroller, why?
o/p of containervc: i dont want separate viewcontroller.. i need containervc to show below to the buttonsview of the viewproposalvc
first time i am working with container views, please do help
The reason why is because you are calling
self.navigationController?.pushViewController(vc!, animated: true)
ContainerView is just a generic UIView with an embedded segue, that is triggered from viewDidLoad of the hosted VC. If you need to do additional setup of that VC I suggest making an var on ViewProposalVC and making desired changes from there.
as in
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var secondaryController: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
self.secondaryController.serviceId = self.viewproposalData?.result?.posted_services?.id
}

Custom keyboard is crashing the app - Swift

I'm doing a test of a custom keyboard. This is what I need:
It has to have two UITextFields. Cannot be labels.
The keyboard is an embedded UIView.
The default keyboard should be disabled.
It cannot be a keyboard extension.
Not sure why the app is crashing. PS: Not all the keys are on the code yet. Here is an image of what I'm trying to do and the two View Controllers.
Edit: The error is: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
First ViewController:
import UIKit
class HomeVC: UIViewController, ButtonTapDelegate {
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
#IBOutlet var keyboardView: UIView!
var buttonPressed = [String]()
override func viewDidLoad() {
addKeyboard(view: keyboardView)
buttonPressed = [String]()
textField1.inputView = UIView()
textField2.inputView = UIView()
}
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
view.addSubview(keyboard.view)
addChild(keyboard)
}
func didTapButton(sender: UIButton) {
if sender.tag == 5 {
textField1.text?.append(contentsOf: " ")
} else if sender.tag == 6 {
textField1.text?.removeAll()
buttonPressed = [String]()
} else {
let val = sender.titleLabel?.text
textField1.text?.append(contentsOf: val!)
}
self.textField1.text = buttonPressed.joined(separator: "")
}
}
Here is the second View Controller:
import UIKit
protocol ButtonTapDelegate {
func didTapButton(sender: UIButton)
}
class KeyboardVC: UIViewController {
var delegate: ButtonTapDelegate!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttons(_ sender: UIButton) {
delegate.didTapButton(sender: sender)
print(sender)
}
}
var delegate: ButtonTapDelegate!
An implicitly unwrapped optional is essentially a promise that you're definitely going to give the variable a value before you try to access it. The problem in this case is that you haven't done that. Most likely, you want to do this in your first view controller:
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
keyboard.delegate = self // Now "delegate" will have a value before the function gets called
view.addSubview(keyboard.view)
addChild(keyboard)
}

Unable to perform segue from UIView connected to XIB

This is UIView file's owner of XIB
import UIKit
class sideBarContent: UIView {
#IBOutlet weak var userName: UILabel!
#IBOutlet var sideBarContentView: UIView!
let mapviewcontroller = MapViewController()
#IBAction func userProfile(_ sender: UIButton) {
mapviewcontroller.performSegueFromView(stringFromView: "userprofile")
}
Whereas inside my UIviewcontroller
class MapViewController: UIViewController
{
func performSegueFromView(stringFromView:String){
performSegue(withIdentifier: "\(stringFromView)", sender: nil)
}
}
It says that my segue identifier does not exist, please help, i'm quite lost. And i couldn't perform segue in UIView as well, and i tried to use storyboard ID method too, but the present(vc,animated:true,completion:nil) not showing up.
First things first, I think you should not access the view controller from your view. It is better to model the controller logic in the view controller rather than in the view.
That said, you can use a delegate pattern to implement your functionality.
import UIKit
class SideBarContent: UIView {
#IBOutlet weak var userName: UILabel!
#IBOutlet var sideBarContentView: UIView!
let delegate: SideBarContentDelegate? = nil
#IBAction func userProfile(_ sender: UIButton) {
self.delegate?.performSegueFromView(withIdentifier: "userprofile")
}
}
protocol SideBarContentDelegate {
func performSegueFromView(withIdentifier identifier: String)
}
class MapViewController: UIViewController, SideBarContentDelegate {
#IBOutlet private weak var sidebarView: SideBarContent!
override func viewDidLoad() {
super.viewDidLoad()
self.sidebarView.delegate = self
}
func performSegueFromView(withIdentifier identifier: String) {
self.performSegue(withIdentifier: identifier, sender: nil)
}
}
More info : https://stackoverflow.com/a/1340470/2603900

Text field is permanently in the second view controller upon segue

I have been working on an app that allows multiple text fields from the first view controller pass over to the second view controller upon pressing a button. However, the text fields are permanently in the second view controller when I only want them to be if the button is pressed. Here is the code for the first view controller! Any help is greatly appreciated.
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var textField1: UITextField!
#IBAction func buttonTwo(_ sender: Any) {
if textField1.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
#IBAction func buttonOne(_ sender: Any) {
if textField.text != "" {
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
var secondController = segue.destination as! SecondViewController
secondController.myString1 = textField1.text!
secondController.myString = textField.text!
}
}
Here is the code in the second view controller:
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var label1: UILabel!
var myString = String()
var myString1 = String()
override func viewDidLoad() {
super.viewDidLoad()
label.text = myString
label1.text = myString1
// Do any additional setup after loading the view.
}
}
Image of storyboard
This happens because, prepare for segue will be called every time you perform some segue action.
You should manage to have a bool variable that helps you track, if any button is clicked or not, if the segue is performed from the click of the button, then only you will have to set the text while preparing for segue.
here is your updated viewController
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var textField1: UITextField!
var isButtonClicked: Bool = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
/*reset isButtonClicked to false, when you back from second viewController */
isButtonClicked = false
}
#IBAction func buttonTwo(_ sender: Any) {
if textField1.text != "" {
isButtonClicked = true
performSegue(withIdentifier: "segue", sender: self)
}
}
#IBAction func buttonOne(_ sender: Any) {
if textField.text != "" {
isButtonClicked = true
performSegue(withIdentifier: "segue", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if isButtonClicked {
var secondController = segue.destination as! SecondViewController
secondController.myString1 = textField1.text!
secondController.myString = textField.text!
}
}
}
Try and share your results.

How can I pass data from a parent view controller to an embedded view controller in Swift?

I have a view controller embedded in another VC.
I would like to get the value of a variable from the main VC inside the embedded one. Specifically, I would like to change the text of label2 based on the value of label1.
I tried with "prepareForSegue", but it seems it's not triggered for embedded view controllers. I tried to isolate the problem in a test project:
Code for main VC:
class MyViewController: UIViewController {
#IBOutlet weak var label1: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
}
}
Code for embedded VC:
class EmbeddedVC: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Thanks for your help :)
A way to achiŠµve this is to get the child view controller instance in the parent's viewDidLoad. It appears that the parent's viewDidLoad: gets called after the child's viewDidLoad:, which means the label is already created in the child's view.
override func viewDidLoad() {
super.viewDidLoad()
if let childVC = self.childViewControllers.first as? ChildVC {
childVC.someLabel.text = "I'm here. Aye-aye."
}
}
First of all you can't set directly EmbeddedVC's lable2.text In prepareForSegue
because call sequence following below
MainVC's prepareForSeque this time EmbeddedVC's label2 is nil
EmbeddedVC's viewDidLoad called then label2 loaded
MainVC's viewDidLoad called then label1 loaded
so if you assign MainVC's label1.text to EmbeddedVC's label2.text in prepareForSeque
both label1 and label2 are nil so did not work
There are two way to solve this question
First Solution
MainViewController has EmbeddedVC and when MainVC's viewDidLoad called, assign label1.text to embeddedVC.label2.text
class MyViewController: UIViewController {
#IBOutlet weak var label1: UILabel!
var embeddedVC: EmbeddedViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
embeddedVC?.label2.text = label1.text
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let embeddedVC = segue.destination as? EmbeddedViewController {
self.embeddedVC = embeddedVC
}
}
}
class EmbeddedViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
}
Second Solution, use protocol and get MainVC's label text when viewWillAppear or viewDidAppear (later viewDidLoad called)
protocol EmbeddedVCDelegate: class {
func labelText() -> String?
}
class MyViewController: UIViewController, EmbeddedVCDelegate {
#IBOutlet weak var label1: UILabel!
// MARK: EmbeddedVCDelegate
func labelText() -> String? {
return label1.text
}
override func viewDidLoad() {
super.viewDidLoad()
label1.text = "Hello"
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let embeddedVC = segue.destination as? EmbeddedViewController {
embeddedVC.delegate = self
}
}
}
class EmbeddedViewController: UIViewController {
#IBOutlet weak var label2: UILabel!
weak var delegate: EmbeddedVCDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
label2.text = delegate?.labelText()
}
}
You should try to use prepareForSegue like this:
if segue.identifier == "identifier" {
guard let destinationViewController = segue.destination as? VC2 else { return }
destinationViewController.label2.text = mytext
}
Where the segue identifier you assign in storyboard