Passing data and delegating between few ViewControllers using Coordinator-Pattern - ios

I'm trying to make simple navigation (using Coordinator) between few view controllers in single story board.
Error I faced is that delegate of AuthenticateErrorDelegate returned nil, that's why I can't #jump# to parent - Login Coordinator to handle my logic
Code:
import UIKit
protocol AuthenticateErrorDelegate: class {
func jump()
}
class AuthenticateErrorViewController: UIViewController {
weak var delegate: AuthenticateErrorDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func backToLogin(_ sender: Any) {
self.delegate?.jump(). //delegate return NIL %(
print("jump to AUTH VC")
}
}
andenter code here Coordinator:
import UIKit
protocol LoginCoordinatorDelegate: class {
func didFinishLogin()
func didErrorLogin()
func openAuthForm()
}
class LoginCoordinator: NSObject {
var navigationController: UINavigationController
var childCoordinators: [NSObject] = []
private var authenticateViewController: AuthenticateViewController
private var authenticateErrorViewController: AuthenticateErrorViewController
weak var delegate: LoginCoordinatorDelegate?
deinit {
print("Deallocating \(self.description)")
}
init(navigationController: UINavigationController) {
self.navigationController = navigationController
let storyboard = UIStoryboard(name: "Login", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "AuthenticateViewController") as! AuthenticateViewController
self.authenticateViewController = vc
let evc = storyboard.instantiateViewController(withIdentifier: "AuthenticateErrorViewController") as! AuthenticateErrorViewController
self.authenticateErrorViewController = evc
}
func start() {
authenticateViewController.name = "AUTH VC"
authenticateViewController.delegate = self
navigationController.setViewControllers([authenticateViewController], animated: true)
}
func end(){
authenticateViewController.delegate = self
navigationController.setViewControllers([authenticateErrorViewController], animated: true)
}
}
// MARK: Authentication Delegate
extension LoginCoordinator: AuthenticateDelegate, AuthenticateErrorDelegate {
func jump() {
delegate?.openAuthForm()
}
}
// MARK: UIViewController Extension
extension UIViewController {
func add(_ child: UIViewController) {
addChild(child)
view.addSubview(child.view)
child.didMove(toParent: self)
}
func remove() {
guard parent != nil else { return }
willMove(toParent: nil)
removeFromParent()
view.removeFromSuperview()
}
}
Calling of AuthenticateDelegate works fine:
import UIKit
protocol AuthenticateDelegate: class {
func authenticateUser(username: String)
}
class AuthenticateViewController: UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var usernameField: UITextField!
var name: String?
weak var delegate: AuthenticateDelegate?
override func viewDidLoad() {
super.viewDidLoad()
nameLabel.text = name ?? nameLabel.text
}
#IBAction func loginAction(_ sender: Any) {
guard let username = usernameField.text else { return }
delegate?.authenticateUser(username: username)
}
}
What I am doing wrong ?
Thanks in advance!

Related

why in don't pass value user.username to navigator

class SigninViewController: UIViewController {
#IBOutlet weak var usernameTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
var signinAPIManager: SigninAPIManager?
override func viewDidLoad() {
super.viewDidLoad()
setupView()
setupData()
}
private func setupData() {
setupServices()
}
private func setupView() {
setupTextFields()
}
private func setupTextFields() {
let textFields = [usernameTextField, passwordTextField]
textFields.forEach{ $0?.delegate = self }
}
#IBAction func signinButton(_ sender: Any) {
signinAPIManager?.signin(optionalUsername: usernameTextField.text,
optionalPassword: passwordTextField.text)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "SigninCompletedIdentifier"{
if segue.destination is HomeTableViewController{
let vc = segue.destination as? HomeTableViewController
vc?.textUser = "asds"
}
}
}
}
}
extension SigninViewController: SigninAPIManagerDelegate {
func didSigninCompletion(user: User) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondController = storyboard.instantiateViewController(withIdentifier: "secondary") as! HomeTableViewController
secondController.textUser = user.username
performSegue(withIdentifier: "SigninCompletedIdentifier", sender: self)
}
}
I want to pass user.username in extension SigninViewController to navigator withIdentifier: "SigninCompletedIdentifier"
Please try to print your object first:
print("SignInApiManager Object= ", signinAPIManager)
You'll find it nil as you haven't assigned any instance of SigninAPIManager.
Replace the following line of code:
Replace var signinAPIManager: SigninAPIManager? with var signinAPIManager: SigninAPIManager = SigninAPIManager()

Unwrapping the UILabel error while implementing Delegate and Protocols

Here I am getting error when unwrapping the del UIlabel
#IBOutlet weak var del: UILabel! // my label must change through protocol implementation
del.text = name // error here
Unexpectedly found nil while implicitly unwrapping an Optional value
ViewController.swift
class ViewController: UIViewController,DataPass {
#IBOutlet weak var del: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func seconeView(_ sender: UIButton) {
let selview = storyboard?.instantiateViewController(withIdentifier: "SecondViewController")as!SecondViewController
present(selview,animated: true,completion: nil)
}
func pass(name: String) {
del.text = name // error here Unexpectedly found nil while implicitly unwrapping an Optional value
}
}
SecondViewController.swift
protocol DataPass {
func pass(name:String)
}
class SecondViewController: UIViewController {
let delegate:DataPass! = ViewController()
let label = "Delegate"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func endView(_ sender: UIButton) {
if let del = delegate {
del.pass(name: label)
} else {
print("Delegate property is not set")
}
dismiss(animated: true, completion: nil)
}
}
There are few changes you need to do to make your delegate working:
In second controller make these changes:
protocol DataPass {
func pass(name:String)
}
class SecondViewController: UIViewController {
var delegate:DataPass?
let label = "Delegate"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func endView(_ sender: UIButton) {
if let del = delegate {
del.pass(name: label)
} else {
print("Delegate property is not set")
}
dismiss(animated: true, completion: nil)
}
}
and in first controller :
class ViewController: UIViewController,DataPass {
#IBOutlet weak var del: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func seconeView(_ sender: UIButton) {
let selview = storyboard?.instantiateViewController(withIdentifier: "SecondViewController")as!SecondViewController
selview.delegate = self
present(selview,animated: true,completion: nil)
}
func pass(name: String) {
del.text = name
}
}
Explanation:
In this line let delegate:DataPass! = ViewController() you are creating another instance for your delegate variable which doesn't hold any label. You need to assign your ViewController's instance while presenting the next controller to make it working.

Delegate returns nil and not being called

I have an overlay that I want to remove when a button is clicked thereby dismissing the ViewController. I have debugged and the delegate is currently returning nil. I'm not sure what I'm doing wrong here. Have I missed implementing something else? I have even tried out print statements but can't see anything.
protocol DismissOverlayDelegate: class {
func dismissOverlay(_ sender: PlayersViewController)
}
class PlayersViewController: UIViewController {
weak var delegate: DismissOverlayDelegate?
#IBAction func getStartedTapped(_ sender: UIButton) {
self.delegate?.dismissOverlay(self)
}
}
and in my ViewController where I implement the delegate method
class HomeViewController: UIViewController, DismissOverlayDelegate {
#IBOutlet weak var customOverlay: CustomOverlayView!
let playersViewController = PlayersViewController()
override func viewDidLoad() {
super.viewDidLoad()
self.playersViewController.delegate = self
}
func dismissOverlay(_ sender: PlayersViewController) {
self.customOverlay.removeFromView()
}
}
delegate = (DismissOverlayDelegate?) nil
The PlayersViewController is embedded into a UIPageViewController
class HomeViewController: UIPageViewController, UIPageViewControllerDataSource {
var pages = [UIViewController]()
override func viewDidLoad() {
super.viewDidLoad()
for storyboardIDs in ["playersVC1","playersVC2"] {
let viewController = self.storyboard?.instantiateViewController(withIdentifier: storyboardIDs)
self.pages.append(viewController!)
}
self.dataSource = self
self.setViewControllers([self.pages.first!], direction: .forward, animated: true)
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
let currentIndex = self.pages.firstIndex(of: viewController)!
if currentIndex > 0 {
return self.pages[currentIndex - 1]
}
return nil
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
let currentIndex = self.pages.firstIndex(of: viewController)!
if currentIndex < (self.pages.count - 1) {
return self.pages[currentIndex + 1]
}
return nil
}
}
It seems that PlayersViewController() is wrong.
You should use instantiateInitialViewController() or instantiateInitialViewController() when using StoryBoard.
https://developer.apple.com/documentation/uikit/uistoryboard/1616214-instantiateviewcontroller
https://developer.apple.com/documentation/uikit/uistoryboard/1616213-instantiateinitialviewcontroller
Let me explain you if you are using or want to use delegate for call or implement something there is root and you have to that on a right way. You are doing well no issue but the implementation of delegate is not properly your method can't accept that so try this:-
Your Home View Controller
class HomeViewController: UIViewController, DismissOverlayDelegate {
#IBOutlet weak var customOverlay: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
func dismissOverlay(_ sender: PlayersViewController) {
self.customOverlay.removeFromSuperview()
}
#IBAction func go(_ sender: UIButton) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PlayersViewController") as! PlayersViewController
vc.delegate = self
self.navigationController?.pushViewController(vc, animated: true);
}
}
this is your playground VC
protocol DismissOverlayDelegate: class {
func dismissOverlay(_ sender: PlayersViewController)
}
class PlayersViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
weak var delegate: DismissOverlayDelegate?
#IBAction func getStartedTapped(_ sender: UIButton) {
self.delegate?.dismissOverlay(self)
}
}
now hope you understand what you have to do...!

Cannot access data passed through delegate

I am trying to understand delegate and I don't get why it says that I have used unresolved identifier 'data'.
//This is my sendingVC
import UIKit
protocol TextFieldDelegate {
func userEnteredText(text: String)
}
class ViewController: UIViewController {
#IBOutlet weak var textField: UITextField!
var delegate: TextFieldDelegate? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func sendButton(_ sender: AnyObject) {
if delegate != nil {
if textField.text != nil {
let data = textField.text
delegate?.userEnteredText(text: data!)
}
}
}
}
The problem is with this code below for my receivingVC I am not able to accesss data variable which should be passed by the delegate.
//This is my receivingVC
import UIKit
class SecondViewController: UIViewController, TextFieldDelegate {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func userEnteredText(text: String) {
label.text = data // Use of unresolved identifier 'data'
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "sendSegue" {
let destVC: ViewController = segue.destination as! ViewController
destVC.delegate = self
}
}
}
Update your code:
func userEnteredText(text: String) {
label.text = text
}

Custom protocol delegate method not calling

I am trying to change lable of one view controller from another view controller using custom protocol but its delegate method is not being called
ViewController3 code:
when i click on close button it's delegate method is not being called in my ViewController2.
protocol ViewController3Delegate: class {
func changeLable(_ text: String)
}
class ViewController3: UIViewController {
weak var delegate: ViewController3Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btnCloseAction(_ sender: Any) {
delegate?.changeLable("fillter applied")
self.dismiss(animated: true, completion: nil)
}
}
ViewController2 code:
class ViewController2: UIViewController,ViewController3Delegate {
#IBOutlet weak var lblReport: UILabel!
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)
override func viewDidLoad() {
super.viewDidLoad()
VC3.delegate = self
}
func changeLable(_ text: String) {
print("delegate called")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Anybody knows where i am wrong, please suggest me some solution
You have not defined a delegate in your ViewController2 which will be used to the delegate in ViewController3 .
See This :
protocol ViewController3Delegate: class {
func changeLable(_ text: String)
}
class ViewController3: UIViewController {
weak var delegate: ViewController3Delegate?
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func btnCloseAction(_ sender: Any) {
if delgate !=nil {
delegate?.changeLable("fillter applied")
self.dismiss(animated: true, completion: nil)
}
}
}
And then in your ViewController2 class :
class ViewController2: UIViewController,ViewController3Delegate {
#IBOutlet weak var lblReport: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
func changeLable(_ text: String) {
print("delegate called")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if segue.identifier = "Yoursegueientifier"
{
let vc = segue.destination as! ViewController3
vc.delegate = self
}
}
}
Note : You have to define your segueidentifer name in your storyboard
You should first present ViewController3 from ViewController2 like this:
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)
VC3.delegate = self
self.presentViewController(VC3, animated: true, completion: nil)
Also, you can delete this line above viewDidLoad
let VC3 = ViewController3(nibName: "ViewController3", bundle: nil)

Resources