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
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()
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.
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...!
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
}
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)