Protocol function sends the value back to the first VC but does not set it to the variables - ios

I am learning IOS, and I have three view controllers A, B and C, and I can access C from B and B from A, then I send back data using this delegate method from C to A then I want to use these received data in A, and finally update the text in the textView of VC A, but it always updates the textView using the default values not the received ones.
class A
protocol isAbleToReceiveData{
func pass(book: String, chapter: Int)
}
class AViewController: UIViewController, isAbleToReceiveData{
var verses: [DBTVerse] = []
var text: String = ""
var currentBook: String = "Test"
var currentChapter: Int = 1
#IBOutlet weak var TextView: UITextView!
func pass(book: String, chapter: Int) {
self.currentBook = book
self.currentChapter = chapter
print(currentBook, currentChapter)
// current output is ok "the received data"
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
getVerses(book: self.currentBook, Chapter: NSNumber(value: self.currentChapter))
print(currentBook, currentChapter)
// current output "test" "1" while it should be the received data
}
func data(verses: [DBTVerse]) {
for verse in verses{
if let chapter: Int = verse.verseId?.intValue{
text.append(String(chapter))
text.append(verse.verseText)
}
}
updateData(text: text)
}
func updateData(text: String){
if let textView = self.versesTextView {
textView.text = text
textView.setNeedsDisplay()
}
}
func getVerses(book: String, Chapter: NSNumber) {
DBT.getTextVerse(withDamId: "ARBWTCO1ET", book: book, chapter: Chapter, verseStart: nil, verseEnd: nil, success: { (verse) in
if let verse = verse {
self.verses = verse as! [DBTVerse]
self.data(verses: self.verses)
}
}) { (error) in
if let error = error {
print("Error \(error)")
}
}
}
}
class C
class CTableViewController: UITableViewController {
var currentBook: String = ""
var chapters: [DBTChapter] = []
var AVC = AViewController()
var delegate: isAbleToReceiveData?
override func viewDidLoad() {
super.viewDidLoad()
self.delegate = AVC
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let selectedChapter = Int(chapters[indexPath.row].chapterId) {
doDismiss(book: currentBook, chapter: selectedChapter)
}
}
func doDismiss(book: String, chapter: Int) {
if let delegate = self.delegate{
delegate.pass(book: book, chapter: chapter)
}
// Use presentingViewController twice to go back two levels and call
// dismissViewController to dismiss both viewControllers.
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil)
}
So in general A receives the data but it does not override it to the variable so I can use it later or in the viewWillAppear.

You have to tell to next Viewcontroller who is it delegate like so if you are in A VC ande B goes trhow a segue then add in A viewController
class AViewController: UIViewController, isAbleToReceiveData{
//all class details
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToClassB"{
let vc = segue.destination as! bViewController
vc.delegate = self
}
}
in class B then you have a new property like c with
class b: UIVIewcontroller{
var delegate: isAbleToReceiveData?
So in the func to segue to next viewController c VC add this func
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToClassC"{
let vc = segue.destination as! CTableViewController
vc.delegate = self.delegate
}
}

Related

How can I pass dictionary from one view controller class to another?SWIFT

I am trying to make a list of users and their passwords in one view controller, save that information in a dictionary, and send that dictionary to another view controller which asks the user to input their username/password combination to authorize the log in. (the key is the username and the value is the password). Is there a way I can send the dictionary from SecondVC to the FirstVC?
First View Controller
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var Username: UITextField!
#IBOutlet weak var Verification: UILabel!
#IBOutlet weak var Password: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
Username.delegate = self
Password.delegate = self
}
var usersDict = [String : String]()
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let des = segue.destination as? AccountViewController {
des.usersDict = usersDict
}
}
#IBAction func Authorization(_ sender: Any) {
for ( key , value ) in usersDict{
let v = key.count
var start = 0
if start <= v{
if Username.text == key{
if Password.text == value{
Verification.text = "Looks Good"
}
}
else{
start += 1
}
}
else{
Verification.text = "Yikes"
}
}
}
}
Second View Controller
class AccountViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var CreateUsername: UITextField!
#IBOutlet weak var CreatePassword: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
CreateUsername.delegate = self
CreatePassword.delegate = self
// Do any additional setup after loading the view.
}
var usersDict = [ String : String ]()
#IBAction func MakeANewAccount(_ sender: Any) {
usersDict[CreateUsername.text!] = CreatePassword.text!
}
}
I have made there dictionary, but it will only send in the beginning and won't update after creating the original account. (dictionary it is sending is empty)
With a segue add this method inside ViewController
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let des = segue.destination as? AccountViewController {
des.usersDict = yourDicHere
}
}
Here's a general pattern for making a controller work with data from some object it creates, in this case a second controller.
Try applying it to your situation and let me know if you run into problems.
protocol Processor {
func process(_ dict: [String : String])
}
class FirstController: UIViewController, Processor {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = segue.destination as? SecondController {
controller.delegate = self
} else {
print("Unexpected view controller \(segue.destination)")
}
}
func process(_ dict: [String : String]) {
}
}
class SecondController: UIViewController {
var delegate: Processor?
func someWork() {
if let processor = delegate {
processor.process(["Name" : "Pwd"])
} else {
print("Delegate not assigned")
}
}
}

use popToRootViewController and pass Data

I'm applying for a junior developer position and I've got a very specific task, that already took me 3 days to complete. Sounds easy - pass data to rootViewController.
That's what I've done:
1)
private func userDefaultsToRootController() {
let input = textField.text!
defaults.set(input, forKey: "SavedLabel")
navigationController?.popViewController(animated: true)
}
private func segueToRootViewController() {
let destinationVC = MainScreen1()
let input = textField.text!
if input == "" { self.navigationController?.popToRootViewController(animated: true) }
destinationVC.input = input
navigationController?.pushViewController(destinationVC, animated: true)
}
private func popToNavigationController() {
let input = textField.text!
if let rootVC = navigationController?.viewControllers.first as? MainScreen1 {
rootVC.input = input
}
navigationController?.popToRootViewController(animated: true)
}
I've used CoreData
But here is the difficult part - I've got an email, that all these methods are not good enough and I need to use delegate and closure. I've done delegation and closures before, but when I popToRootViewController delegate method passes nil. Could you at least point where to find info about this?
** ADDED **
There are 2 View Controllers: Initial and Second one.
That's what I have in the Initial View Controller:
var secondVC = MainScreen2()
override func viewDidLoad() {
super.viewDidLoad()
secondVC.delegate = self
}
That's how I push SecondViewController
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
navigationController?.pushViewController(nextViewController, animated: true)
}
In SecondViewController I've got this protocol
protocol PassData {
func transferData(text: String)
}
Also a delegate:
var delegate: PassData?
This is how I go back to initial view controller
#objc private func buttonTapped(_ sender: CustomButton) {
if let input = textField.text {
print(input)
self.delegate?.transferData(text: input)
self.navigationController?.popToRootViewController(animated: true)
}
}
Back to the Initial view controller where I've implemented delegate method
extension MainScreen1: PassData {
func transferData(text: String) {
print("delegate called")
label.text = text
}
}
Delegate doesn't get called.
BASED ON YOUR EDIT:
You must set the delegate in buttonTapped
#objc private func buttonTapped(_ sender: CustomButton) {
let nextViewController = MainScreen2()
nextViewController.delegate = self // HERE WHERE YOU SET THE DELEGATE
navigationController?.pushViewController(nextViewController, animated: true)
}
You can delete the second instance and your code in viewDidLoad. That's not the instance you push.
This should point you in the right direction to use delegation and completion handler.
protocol YourDelegateName {
func passData(data:YourDataType)
}
class SecondViewController: UIViewController {
var delegate: YourDelegateName?
func passDataFromSecondViewController(){
YourCoreDataClass.shared.getCoreData { (yourStringsArray) in
self.delegate?.passData(data: yourStringsArray)
self.navigationController?.popToRootViewController(animated: true)
}
}
class InitialViewController: UIViewController, YourDelegateName {
override func viewDidLoad() {
super.viewDidLoad()
// or whenever you instantiate your SecondViewController
let secondViewController = SecondViewController()
secondViewController.delegate = self //VERY IMPORTANT, MANY MISS THIS
self.navigationController?.pushViewController(createVC, animated: true)
}
func passData(data:YourDataType){
//user your data
}
}
class YourCoreDataClass: NSObject {
static let shared = YourCoreDataClass()
func getCoreData (completion: ([String]) -> ()){
........... your code
let yourStringsArray = [String]() // let's use as example an array of strings
//when you got the data your want to pass
completion(yourStringsArray)
}
}

Changing Label text on main controller after modal closed swift macOS

I am using delegates to get a string value from my modal. When the modal closes I am trying to update Label text using that string. However, I am getting error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. I am not sure how to fix this. I think it's happening because the view is not yet active.
import Cocoa
class ViewControllerA: NSViewController, SomeDelegate {
#IBOutlet weak var msgLabel: NSTextField!
var s: String = "";
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func setDetails(s: String) {
self.user = s;
print("Notified", self.s) // <-- prints: Notified hello again
msgLabel.stringValue = self.s <-- DOESN'T WORK
}
func showModal() -> Void {
msgLabel.stringValue = "hello" // <--- WORKS
let cbvc: NSViewController = {
return self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! NSViewController
}()
self.presentAsModalWindow(cbvc);
}
#IBAction func onBtn(_ sender: Any) {
self.showModal();
}
}
protocol SomeDelegate {
func setDetails(s: String)
}
class ViewControllerB: NSViewController {
#IBOutlet weak var textF: NSTextField!
var delegate: SomeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let vc = ViewControllerA()
self.delegate = vc
}
#IBAction func onBtn(_ sender: Any) {
DispatchQueue.main.async {
self.delegate?.setDetails(s: self.textF.stringValue)
self.dismiss("ControllerAVC")
}
}
}
You have a number of problems.
In ViewControllerB.viewDidLoad you are assigning a new instance of ViewControllerA to the delegate property. Don't do that. Your viewDidLoad method should look like this:
override func viewDidLoad() {
super.viewDidLoad()
}
In the showModal method ViewControllerA should assign itself as the delegate on ViewControllerB before ViewControllerB it is presented.
func showModal() -> Void {
let cbvc: NSViewController = {
let vc = self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! ViewControllerB
vc.delegate = self
return vc
}()
self.presentAsModalWindow(cbvc);
}
In the setDetails method just assign the string to your text field directly:
func setDetails(s: String) {
msgLabel.stringValue = s
}

TextField unloads value when navigating in Swift

I have two ViewControllers, each with one TextField to get user input number and two buttons to calculate and navigate.
The instance of TextField in the SecondVC is created by user when filling the TextFields and it exists and it is shown in the View
The problem is: when you leave the SecondView Controller after creating the object - Cell and you come back to it later, it is set back to cero, which is not the instance - Cell value
class MainViewController: UIViewController {
#IBOutlet weak var A3TextField: UITextField!
#IBAction func calc(_ sender: Any) {
let A3 = Cell(name: "A3", sheet: "", value: Double(A3TextField.text!)!)
print(A3)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
}
class SecondViewController: UIViewController {
#IBOutlet weak var B3TextField: UITextField!
#IBAction func calc2(_ sender: Any) {
let B3 = Cell(name: "B3", sheet: "", value: Double(B3TextField.text!)!)
print(B3)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
struct Cell {
var name: String = ""
var sheet: String = ""
var value: Double = 0
init(name: String, sheet: String, value: Double) {
self.name = name
self.sheet = sheet
self.value = value
}
}
When controller pop or push ,their temporary property value or object can not be save to other controller,even in itself controller ,when push and back ,their are the init value,if you want save value when page switching,suggest these solution:
1. Pass throw the attribute values(one => two)
OneViewController:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let twoVC = storyboard.instantiateViewController(withIdentifier: "TwoViewControllerID") as! twoViewController
twoVC.myStr="Controller one to controller two!"
self.present(twoVC, animated: true, completion: nil)
TwoViewController
var myStr=String()
override func viewDidLoad() {
super.viewDidLoad()
print("get value:\(myStr)"
}
2, use NSUerDfault to save and get
SetValue:
let userDefault = UserDefaults.standard
userDefault.set(name, forKey: "name")
userDefault.synchronize()
GetValue:
let userDefault = UserDefaults.standard
let name = userDefault.object(forKey: "name") as? String
3,storybord pass value(one => two)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let theSegue=segue.destination as! twoViewController theSegue.myStr="other pass way" }
4,deleagte pass value(two => one)
based don back to front page
TwoViewController:
//(1)create a delegate before class
protocol FTVCdelegte : NSObjectProtocol{
//define method
// one method
func change(title:String)
//two method
func ChangeColoer (Coloer:UIColor)
//three method
func ChangSucces(YON:Bool)
}
//(2)create delegate object。
var delegate_zsj:FTVCdelegte?
//(3)click back button
#IBAction func backBtnAction(_ sender: UIButton) {
delegate_zsj?.change(title: "main page")
delegate_zsj?.ChangeColoer(Coloer: UIColor.red)
delegate_zsj?.ChangSucces(YON: true)
self.navigationController?.popViewController(animated: true)
}
OneViewController
//(4)inherit delegate:
class SecondViewController: UIViewController,FTVCdelegte,ChangeBtnDelege{
...
//(5)imple delegate method
func change(title: String) { self.title = title }
func ChangeColoer(Coloer: UIColor) { self.view.backgroundColor = Coloer }
func ChangSucces(YON: Bool) { print(YON) }
//(6)when pop page use
#IBAction func tiaozhuanBtnAction(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let oneVC = storyboard.instantiateViewController(withIdentifier: "OneViewControllerID") as! oneViewController
oneVC.delegate_zsj = self
self.navigationController?.pushViewController(oneVC, animated: true)
}
5,block pass value(two => one)
based don back to front page
TwoViewController:
//(1)define a block method:
var bbchange:((_ title:String,_ myColor:UIColor)->Void)?
//(2)back to front page:
#IBAction func backBtnAction(_ sender: UIButton) {
bbchange?("document",UIColor.green)
self.navigationController?.popViewController(animated: true)
}
OneViewController
//(3)next page invoke block method
#IBAction func tiaozhuanBtnAction(_ sender: Any) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let threeVC = storyboard.instantiateViewController(withIdentifier: "twoViewControllerID") as! twoViewController
twoVC.bbchange=
{
( title:String,myColor:UIColor) in
self.title=title
self.view.backgroundColor=myColor
}
self.navigationController?.pushViewController(twoVC, animated: true)
}

Issue in Delegate while passing data back to ViewController

I'm having a problem passing array data back from one view controller ("VC2") to another ("VC1"). I do everything by the rules. I made a proper protocol in VC1.
But unfortunately I could not get the data back.
This is my code:
VC2
protocol RecivedData {
func dataRecived(nameArray: [String] , priceArray: [String])
}
var popUpdelegate : RecivedData?
#IBAction func nextBtnTapped(_ sender: UIButton) {
print("Hello")
let namedata = itemNameArr
let namePrice = itemPriceArr
self.popUpdelegate?.dataRecived(nameArray: namedata, priceArray: namePrice)
print(namedata)
print(namePrice)
self.view.removeFromSuperview()
}
VC1
class HomeVC: UIViewController , RecivedData {
func dataRecived(nameArray: [String], priceArray: [String]) {
itemNameArr += nameArray
itemPriceArr += priceArray
print(itemNameArr, itemPriceArr)
print ("This is HomeVC")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "sendSegue"{
let secondVC: AddOnItemPopUpVC = segue.destination as! AddOnItemPopUpVC
secondVC.popUpdelegate = self
}
}
}
Replace your code with this
protocol RecivedData : class {
func dataRecived(nameArray: [String] , priceArray: [String])
}
And
weak var popUpdelegate : RecivedData?
Now it will start working.
Make sure there will be no typo in segue name.

Resources