Ввод информации между ViewControllers программно

uitextfield
swift
uilabel

#1

Storyboard-ы созданы программно.
Есть TabBarController c 2-мя ViewController-ами: VC1 и VC2.
Нужно, чтобы по окончании ввода textField в VC2 - в VC1 label появился введенный текст( без переходов).

<
protocol TextFieldDataDelegate: class {
func saveText(_ text: String)
}

class VC1: UIViewController, TextFieldDataDelegate {
private let label: UILabel!
let vc2 = VC2()

override func viewDidLoad() {
   		 super.viewDidLoad()
  		  vc2.delegate = self
}

func saveText(_ text: String) {
	label.text = text
}

}

class VC2: UIViewController, UITextFieldDelegate {
weak var delegate: TextFieldDataDelegate?
private let textField: UITextField!

    override func viewDidLoad() {
   		 super.viewDidLoad()
  		  textField.delegate = self
}

    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
             self.view.endEditing(true)
    }

func textFieldDidEndEditing(_ textField: UITextField) {
   	 guard textField.text != "", textField == textField, delegate != nil else { return }
   	 self.delegate?.saveText(textField.text!)  
}

}
/>


#2

Может я ошибаюсь, но вы вызываете не тот метод у делегата. Он везде называется saveText, а там что-то совсем иное


#3

не в этом дело( скопипастила неправильно. Сейчас поправлю.


#4

Я бы посоветовал вам сравнить vc2 на стороне vc1 и на самом vc2 (self), это один и тот же контроллер или нет, вполне возможна ошибка логики и создания нескольких экземпляров класса.


#5

и проверить есть ли в данный момент что-то в делегате:
self.delegate?.saveText(textField.text!) или он nil ???


#6
class ViewController: UIViewController, TextFieldDataDelegate {

    let label = UILabel(frame: CGRect(x: 0, y: 200, width: 600, height: 80))
    let btn = UIButton(frame: CGRect(x: 0, y: 280, width: 600, height: 80))
    let vc = SecondVC()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        label.backgroundColor = .red
        view.addSubview(label)
        view.addSubview(btn)
        vc.delegate = self
        
        btn.backgroundColor = .green
        btn.addTarget(self, action: #selector(toV), for: .touchUpInside)
        
    }

    @objc func toV() {
        navigationController?.pushViewController(vc, animated: true)
    }
    
    
    func saveText(_ text: String) {
        label.text = text
    }
    

}

protocol TextFieldDataDelegate: class {
    func saveText(_ text: String)
}

class SecondVC: UIViewController, UITextFieldDelegate {
    
    weak var delegate: TextFieldDataDelegate?
    let textField = UITextField()
    
    init() {
        super.init(nibName: nil, bundle: nil)
        textField.frame = CGRect(x: 0, y: 100, width: 600, height: 80)
        textField.delegate = self
        textField.backgroundColor = .lightGray
        view.backgroundColor = .white
        view.addSubview(textField)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
 
    override func viewDidLoad() {
        super.viewDidLoad()
        textField.becomeFirstResponder()
    }
    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        view.endEditing(true)
    }
    
    func textFieldDidEndEditing(_ textField: UITextField) {
        self.delegate?.saveText(textField.text ?? "")
        self.navigationController?.popViewController(animated: true)
    }
    
    
}

#7

он действительно nil! но почему, пока не разобралась


#8

через btn понятно, но у меня в дизайне этого баттона нет, то есть надпись в первом контроллере должна появится как только закончится ввод инфо в текстфилде во втором контроллере. не понимаю, возможно ли это технически, третий день рою интернет на эту тему, везде по баттону как раз должна появляться введенная информация, причем параллельно с переходом на первый контроллер, чего у меня быть не должно(перехода)


#9

Потому что вы создаёте VC2 внутри первого, но ко второй вкладке табБара этот VC2 не имеет никакого отношения.

Самый прямой способ - назначать делегатом первый VC в том месте, где вы конфигурируете два ваших контроллера для TabBarController’a.


#10

Смотрите, Вам нужно получить VC2 в VC1 а не создавать его. Так tabBar сам инициализирует VC2.
Попробуйте в VC1 во viewDidLoad сделать:
vc = self.tabBarController!.viewControllers![1] as! SecondVC

Все должно отработать. Только сделайте это более красиво потом без опционалов.


#11

Было бы хорошо получить ссылку на проект на Гит и собрать его, посмотреть что в нем поправить.


#12

Простите, а причем тут кнопка?!))
Она нужно только для пуша)


#13

#14
class BaseTabBarController: UITabBarController {
 
    override func viewDidLoad() {
        super.viewDidLoad()

        let homeVC = HomeViewController()
        let settingsVC = SettingsViewController()
        settingsVC.delegate = homeVC
        
        viewControllers = [
            createController(viewController: homeVC, title: "Home", imageName: ""),
            createController(viewController: settingsVC, title: "Settings", imageName: "")
        ]
    }

    func createController(viewController: UIViewController, title: String, imageName: String) -> UIViewController {

        viewController.title = title
        viewController.tabBarItem.image = UIImage(named: imageName)
        return viewController
    }
}

#15

Спасибо огромное! Всё теперь показывает)


#16

Кстати, в данном случае лучше наверно использовать что-то другое, по типу нотификашен центра))

Эт мое мнение, могу ошибаться)


#17

Думаю что нет. Зачем вещать наблюдателя, если через делегата и так все сообщается в случае изменения. Нотификейшены лучше меньше использовать.


#18

ну не знаю))

Я вот не особо люблю делегаты, по-моему от них много лишнего кода, проще колбеки с енумом))

Нотификейшены тоже не особо использую, просто кажется что это было более хорошем решением))