how to update label of other viewController in swift - ios

I'm trying to set UIbutton's text in firstVC as selectedCity variable when it selected in tableViewCell in SecondVC . I cannot use segue or tabBarController. Updated photo of ui
FirstVC
import UIKit
class homeView: UIViewController{
#IBOutlet weak var selectRegion: UIButton!
}
SecondVC
import UIKit
class selectCityPage: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var selectedCity: String!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
selectedCity = "Almaty"
}
if indexPath.row == 1{
selectedCity = "Усть-Каменогорск"
}
dismiss(animated: true, completion: nil)
// when this view controller is dismissed, uibutton's text in next viewcontroller should equal to selectedCity
}
}

You can use delegation. These are the required steps:
Create a delegate protocol that defines the messages sent to the delegate.
Create a delegate property in the delegating class to keep track of the delegate.
Adopt and implement the delegate protocol in the delegate class.
Call the delegate from the delegating object.
SecondVC
import UIKit
//1. Create a delegate protocol
protocol CitySelectionDelegate {
func pickCity(with selectedCity:String)
}
class SelectCityPage: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var tableView: UITableView!
var selectedCity: String!
//2. Create a delegate property in the delegating class
var delegate:CitySelectionDelegate?
//other stuff
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){
if indexPath.row == 0{
selectedCity = "Almaty"
}
if indexPath.row == 1{
selectedCity = "Усть-Каменогорск"
}
4. Call the delegate from the delegating object.
delegate?.pickCity(with: selectedCity) //call your delegate method
//dismiss(animated: true, completion: nil) when you dismiss is up to you
}
}
HomeViewController
UPDATE: Since you have another VC embedded inside a UINavigationController, both the Home and Select Region Page MUST conform to the delegate and you have to set the delegate inside prepareForSegue method.
// 3. Adopt and implement the delegate protocol
class HomeViewController: UIViewController, CitySelectionDelegate{
#IBOutlet weak var selectRegion: UIButton!
func pickCity(with selectedCity: String) {
self.selectRegion.text = selectedCity
}
/*please pay attention. In this case you must reference the
navigation controller first and the your can get the right
instance of the delegate variable inside your firstVC (I called
firstVC but in your case is Select Region Page*/
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// you MUST set the right identifier
if segue.identifier == "showFirst" {
if let navController = segue.destination as? UINavigationController {
if let firstVC = navController.topViewController as? FirstViewController{
firstVC.delegate = self
}
}
}
}
}
since you have another VC (embedded in a navigation controller), also this one must conform to the delegate like so:
class FirstViewController: UIViewController, CitySelectionDelegate {
var delegate: CitySelectionDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
func pickCity(with selectedCity: String){
// here you simply call the delegate method again and you dismiss the navigation controller
self.delegate?.pickCity(with: selectedCity)
self.navigationController?.dismiss(animated: true, completion: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "showSecond" {
if let controller = segue.destination as? SelectCityPage {
controller.delegate = self
}
}
}

you can use delegate or block or notification when secVC action to change the firstVC value you needed.
Or you set a property in secVC and pass the value in firstVC you want to change, So you can change value passed from firstVC in secVC.

Related

Send data from TableView (present modally) to ViewController inside textfield

In my HomeViewController I have a text field and a button. User can write a city or touch in this button to find a city. When button is touched, a CitiesTableView shows up by segue (present modally). When choose a city of the table list, I want to send this selected city to inside the text field in HomeViewController.
class HomeViewController: UIViewController{
#IBOutlet weak var tfSearchCity: UITextField!
//Button with Segue to present Modally CitiesTableViewController
var cities = [Cities]()
}
// Protocol to receive data
extension HomeViewController: CitieFinderDelegate{
func addCity(city: Cities){
tfSearchCity.text = city.City
print(city)
}
}
}
I create a Protocol to pass data between views but is not working.
protocol CitieFinderDelegate {
func addCity(city: Cities)
}
// this TableView are presenting Modally
class CitiesTableViewController: UITableViewController {
var cities: [Cities] = []
var delegate: CitieFinderDelegate?
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Table view data source
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let city = cities[indexPath.row]
let findCity = Cities(UF: city.UF, City: city.City)
delegate?.addCity(city: findCity)
}
// MARK: - Action to close the view
#IBAction func close(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}}
It seems that the delegate hasn't been assigned to HomeViewController's instance.
Make sure you have the below code in your HomeViewController
override func prepare(for segue: UIStoryboardSegue, sender _: Any?) {
if segue.identifier == "segue identifier name",
let citiesViewController = segue.destination as? CitiesTableViewController {
// cities assigned
citiesViewController.delegate = self
}
}

Delegate function not being called iOS Swift

Here I am trying to pass value from one class LanguageSelectionTVC to another RegistrationVC by using a Protocol.
When I try and call the method self.delegate?.setSelectedLangauges(self.languagesSpokenArray) inside LanguageSelectionTVC it doesn't call the method setSelectedLangauges inside the class Registration VC could someone please suggest where I am going wrong ?
protocol LanguageSelectionTVCProtocol {
func setSelectedLangauges(_ valueSent: [String])
}
class LanguageSelectionTVC: UITableViewController {
var delegate : LanguageSelectionTVCProtocol? = nil
func saveAndClose() {
self.delegate?.setSelectedLangauges(self.languagesSpokenArray)
dismiss()
}
}
class RegistrationVC: UIViewController,
UITableViewDelegate,
UITableViewDataSource,
LanguageSelectionTVCProtocol{
func setSelectedLangauges(_ valueSent: [String]){
self.showLanguagesSpoken(valueSent)
}
}
Moving to LanguageSelectionTVC from RegistrationVC . The below tableView method is in my RegistrationVC
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let row = indexPath.row
let section = indexPath.section
let currentCell = tableView.cellForRow(at: indexPath) as! UITableViewCell
if section == 4 && row == 0 {
// The user has clicked on languages spoken cell
self.performSegue(withIdentifier: "LanguageSelectionTVC", sender: self)
}
}
You need to access LanguageSelectionTVC from preparForSegue to set delegate of it. So override the prepare(for:sender:) in your RegistrationVC.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "LanguageSelectionTVC" {
let vc = segue.destination as! LanguageSelectionTVC
vc.delegate = self
}
}
You need to set the delegate in RegistrationVC to LanguageSelectionTVC, for example you could set it when performing a segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let targetVC = segue.destination as! LanguageSelectionTVC
targetVC.delegate = self
}
You need to set delegate. can you please see below ready example for pass data between two view controller.
import UIKit
protocol SenderViewControllerDelegate
{
func messageData(str1:NSString)
}
class tableViewController: UIViewController, UITableViewDelegate,
UITableViewDataSource
{
var delegate: tableViewController?
override func viewDidLoad()
{
super.viewDidLoad()
self.delegate?.messageData(str1: “Hello world”)
}
}
receive data in below controller
import UIKit
class HomeViewController: UIViewController ,SenderViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
let objtableview = tableViewController(nibName: "tableViewController",bundle: nil)
objtableview.delegate = self
self.navigationController?.pushViewController(objtableview, animated: true)
}
func messageData(str1:NSString){
print(str1)
}
}

How to pass data between container view and main view controller properly

I'm dealing with following problem: On main VC I have a TableView, and on container view controller I have a textField. I want to add every text, I'm typing in container automatically appears as a new row on tableView in main VC
By now I'm using segue to send data from main VC to container. But what should I implement to do the same in a reverse order? I though of implementing delegate of main VC in my container view, but I have no idea how to do that properly. Or maybe there is exist more common solution.
Anyway, here is my code:
class MessageViewController: UIViewController {
var currentUser: User!
var containerViewController: InputTextViewController?
#IBOutlet weak var enterMessageView: UIView!
#IBOutlet weak var messageTableView: UITableView!
}
extension MessageViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "moveToInputText" {
let connectContainerViewController = segue.destination as? InputTextViewController
containerViewController = connectContainerViewController
containerViewController?.userSendMessageTo = currentUser
}
}
}
extension MessageViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentUser.mesaageHistory.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell") as! ChatMessageTableViewCell
let data = currentUser.mesaageHistory[indexPath.row]
cell.messageLabel.text = data.messageText
return cell
}
}
class InputTextViewController: UIViewController {
#IBOutlet weak var messageTextField: UITextField!
var userSendMessageTo: User!
weak var delegate = MessageViewController()
#IBAction func sendMessge(_ sender: Any) {
handleSend()
userSendMessageTo.mesaageHistory.append(message)
print(userSendMessageTo.mesaageHistory[0].messageText)
let row = userSendMessageTo.mesaageHistory.count - 1
let insertIndexPath = IndexPath(item: row, section: 0)
print(userSendMessageTo.mesaageHistory.count)
delegate?.messageTableView.beginUpdates()
delegate?.messageTableView.insertRows(at: [insertIndexPath], with: UITableViewRowAnimation.automatic)
delegate?.messageTableView.endUpdates()
}
}
Here's how to use the 'delegate' pattern properly
Protocol declaration & delegate member
protocol InputTextViewControllerDelegate: class {
func someFunc()
func anotherFunc()
}
class InputTextViewController: UIViewController {
weak var delegate: InputTextViewControllerDelegate?
}
Protocol implementation & setting the delegate property
extension MessageViewController, InputTextViewControllerDelegate {
// MARK: InputTextViewControllerDelegate
//
func someFunc()
{
}
func anotherFunc()
{
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "moveToInputText" {
let connectContainerViewController = segue.destination as? InputTextViewController
containerViewController = connectContainerViewController
containerViewController
}
}
}

Swift / how to call delegate with popViewController

I have read this thread (and similar others) from bottom to top, but it doesn't fit my needs at all.
I have a UIViewController inside UIPageViewController within a UINavigationController. Navigating to a 2nd ViewController. Navigating to a 3rd ViewController and want to pop back to 2nd ViewController delivering data.
My code currently:
protocol PassClubDelegate {
func passClub(passedClub: Club)
}
class My3rdVC: UIViewController {
var clubs: [Club] = []
var passClubDelegate: PassClubDelegate?
....
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let club = clubs[indexPath.row]
self.passClubDelegate?.passClub(club)
navigationController?.popViewControllerAnimated(true)
}
My 2nd VC:
class My2ndVC: UIViewController, PassClubDelegate {
var club = Club()
func passClub(passedClub: Club) {
SpeedLog.print("passClub called \(passedClub)")
club = passedClub
}
passClub is not called. I'm sure it's because I didn't set the delegate to the My2ndVC, but how would I do that? All the solutions I have found wanting me to use a) segue or b) instantiate a My2ndVC new, what doesn't make any sense since it's still in memory and I want to pop back to go back in hierarchy. What am I missing? What are my possibilities? Help is very appreciated.
PS: I'm not using any segues. My3rdVC is called by:
let vc = stb.instantiateViewControllerWithIdentifier("My3rdVC") as! My3rdVC
self.navigationController?.pushViewController(vc, animated: true)
You can set the delegate of My3rdVC in the prepareForSegue method of My2ndVC.
class My2ndVC: UIViewController, PassClubDelegate {
...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue(segue, sender: sender)
switch segue.destinationController {
case let controller as My3rdVC:
controller.passClubDelegate = self
}
}
}
This is assuming you have created a segue in your storyboard that pushes My3rdVC from My2ndVC onto the navigation controller stack, which I'm assuming you have. So just try simply pasting this prepareForSegue method into My2ndVC and see if it works.
UPDATE
let vc = stb.instantiateViewControllerWithIdentifier("My3rdVC") as! My3rdVC
vc.passClubDelegate = self
navigationController?.pushViewController(vc, animated: true)
When pop one VC to another you can pass data using protocol by declare delegate variable as static. Here in the following example we pop SecondVC to FirstVC and we pass a string.
class FirstVC: UIViewController,getDataDelegateProtocol {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
SecondVC.delegate = self
}
func getData(tempStr: String) {
label.text = tempStr
}
#IBAction func buttonClick(_ sender: UIButton){
let nav = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as! SecondVC
self.navigationController?.pushViewController(nav, animated: true)
}
}
Another View Controller
protocol getDataDelegateProtocol{
func getData(tempStr: String)
}
class SecondVC: UIViewController {
#IBOutlet weak var label: UILabel!
static var delegate: getDataDelegateProtocol?
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonClick(_ sender: UIButton){
SecondVC.delegate?.getData(tempStr: "Received data from SecondVC")
self.navigationController?.popViewController(animated: true)
}
}

Get value from Modal View in Swift iOS

i'm trying to start writing Swift and i'm trying to get a value from a modal view controller with no luck.
I have two controllers, the ViewController and modalViewController.
In ViewController i have a UITableView and with a press of a button i open the modalViewController.
Then from a UITextField i pass the value.
I have implement a protocol with delegate and func but somewhere i'm missing something or had it wrong.
ViewController.swift
import UIKit
class ViewController: UIViewController,UITableViewDelegate,modalViewControllerDelegate{
#IBOutlet var table: UITableView!
var tableData = ["First Row","Second Row","Third Row"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func viewDidAppear(animated: Bool) {
table.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(table:UITableView?,numberOfRowsInSection section: Int) -> Int
{
return tableData.count
}
func tableView(table:UITableView?,cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell!
{
let cell:UITableViewCell = UITableViewCell(style:UITableViewCellStyle.Default,reuseIdentifier:"cell")
cell.textLabel?.text = tableData[indexPath.row]
return cell
}
func sendText(text: NSString) {
tableData.append(text)
} }
modalViewController.swift
import UIKit
protocol modalViewControllerDelegate {
func sendText(var text: NSString)
}
class modalViewController: UIViewController{
let delegate: modalViewControllerDelegate?
#IBOutlet var textField: UITextField?
#IBAction func cancelButton(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func saveButton(sender: AnyObject) {
delegate?.sendText(self.textField!.text)
dismissViewControllerAnimated(true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
}
}
I have no errors in the code, the delegate is not working, it's always nil.
Thanks.
You have to assign the delegate in your first view controller.
Also, you have to change let delegate: modalViewControllerDelegate? to a var, or else you can't change it.
Right now your delegate is empty.
It's unclear how you're accessing ModalViewController. If you're using segues:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "modalViewControllerSegue" {
var destination = segue.destinationViewController as CategoryViewController
destination.delegate = self
}
}
Or if you're doing it programmatically:
var modalViewController = ModalViewController(parameters)
modalViewController.delegate = self
presentViewController(modalViewController, animated: true, completion: nil)
Storyboard identifier:
let destination = UIStoryboard.mainStoryboard().instantiateViewControllerWithIdentifier("ModalViewController") as ModalViewController
delegate = self
showViewController(destination, sender: nil)
EDIT:
If you want to access ModalViewController by selecting a cell you need the tableView: didSelectRowAtIndexPath method:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("modalViewControllerSegue", sender: self)
}
Using this, you'll need the method prepareForSegue to set the delegate.
You have to set your modalViewController's delegate property before presenting it. If you're using segues, you can do this in prepareForSegue(_:).
Also, class names should begin with uppercase letters (modalViewController should be ModalViewController). Only instances should begin with lowercase letters.
Another option, instead of using delegation, is to use an unwind segue. Here's a tutorial: http://www.cocoanetics.com/2014/04/unwinding/
In your case, in your presenting view controller you could have the method:
func returnFromModalView(segue: UIStoryboardSegue) {
// This is called when returning from the modal view controller.
if let modalVC = segue.sourceViewController as? ModalViewController
where segue.identifier == "mySegueID" {
let text = modalVC.textField.text
// Now do stuff with the text.
}
}
And then just link up everything in the Interface Builder as shown in the tutorial.

Resources