Best way to consolidate and store user input data in each viewController - ios

class NameViewController: UIViewController {
var name: String?
override func viewDidLoad() {
super.viewDidLoad()
}
}
class AgeViewController: UIViewController {
var age: Int?
override func viewDidLoad() {
super.viewDidLoad()
}
}
class SaveViewController: UIViewController {
#IBAction func sendData(_ sender: Any) {
let entity = Person(name: name, age: age) // 'name'is NameViewController's name Value.
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
struct Person {
let name: String
let age: Int
}
NameViewController -> AgeViewController -> SaveViewController
I am implementing a screen with the above function as a simple example.
What's the best way to combine all the data to create an entity from the last screen?
not using Userdefaults and singleton..

Related

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
}

Delegate function does not get called

I have two ViewControllers and I'm trying to set one as the other's delegate. This is what I have:
ViewController One:
protocol storeChosenDelegate {
func getPopularProductsFor(store id: String)
}
class PopularStoresVC: UIViewController {
//MARK: - Properties
var delegate: storeChosenDelegate?
private let storesView = PopularStoresView()
private let STORE_CELL = "storeCell"
fileprivate var currentStore: Int = 0 {
didSet {
delegate?.getPopularProductsFor(store: "THIS IS WORKING NOW.")
}
}
}
And this is what I have in ViewController Two:
//MARK: - Properties
private let PRODUCT_CELL = "productCell"
private var popularStores = PopularStoresVC()
//MARK: - Initializers
override func viewDidLoad() {
super.viewDidLoad()
popularStores.delegate = self
setupProductsCollection()
}
extension PopularProductsVC: storeChosenDelegate {
func getPopularProductsFor(store id: String) {
//TODO: Show all popular products for the store's id we got.
print("Got store \(id)")
}
}
It seems that the didSet is getting called, and I do set the Second VC as the delegate, but the function just does not getting called. I have no errors or warnings related to that so I don't really understand why this is not working.

Protocol implementation method not calling in Swift

I am using Xcode 10.3. I have protocol which method is not calling. What is wrong?
My first view controller with protocol:
protocol MyProtocol: class {
func doGetUpdateInfo(valu1:String,value2:String);
}
class Class_A : UIViewController{
weak var myprotocolDelegate:MyProtocol? = nil;
override func viewDidLoad() {
super.viewDidLoad()
myprotocolDelegate?.doGetUpdateInfo(account_no:value1, account_title: value2)
}
}
My second view controller
class Class_B: UIViewController,UpdateBeneficiaryProtocol {
var class_a = Class_A()
override func viewDidLoad() {
super.viewDidLoad()
class_a.myprotocolDelegate = self;
}
func doGetUpdateInfo(value1: String, value2: String) {
print("not calling****")
}
}
What is the wrong with it?
Please see the below example. you are creating a new class for A but so it will not be called. you need to provide a reference for the current class
protocol MyProtocol: class {
func doGetUpdateInfo(valu1:String,value2:String);
}
class Class_A : UIViewController{
weak var myprotocolDelegate:MyProtocol? = nil;
override func viewDidLoad() {
super.viewDidLoad()
myprotocolDelegate?.doGetUpdateInfo(account_no:value1, account_title: value2)
}
func navigateToClassB() {
let classb = Class_B()
classb.class_a = self
self.navigationController?.pushViewcontroller(classb, animated:true)
}
}
And class b should be
class Class_B: UIViewController,UpdateBeneficiaryProtocol {
var class_a : Class_A?
override func viewDidLoad() {
super.viewDidLoad()
class_a.myprotocolDelegate = self;
}
func doGetUpdateInfo(value1: String, value2: String) {
print("not calling****")
}
}
Push controller Class_b as per display in method navigateToClassB.
If you face still issue comment here I will assist you.

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

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
}
}

Why I cannot set the labels with the data passed from one UIViewController to another (printing the data in console works) in Swift?

In my app I have an embedded UIViewController inside a container. In my story board I added a touch event to this viewcontroller and I called the segue: fullRequestSegue
Then in the code of that UIViewController I wrote:
class RequestDetails: UIViewController, ShowRequestDetailsFromMap {
var fullRequestDetails: FullRequestFromMap?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "fullRequestSegue"){
fullRequestDetails?.changeEventDescr(self.descr, username: "adam", number: "12", created_at: self.created_at, photo: self.photo)
fullRequestDetails = segue.destinationViewController as? FullRequestFromMap
fullRequestDetails!.showRequestDetails = self
}
}
}
Then in my class FullRequestFromMap I have:
protocol ShowRequestDetailsFromMap {
func changeEventDescr(text:String)
}
class FullRequestFromMap: UIViewController{
#IBOutlet weak var userNumber: UILabel!
var showRequestDetails:ShowRequestDetailsFromMap?
override func viewDidLoad() {
super.viewDidLoad()
}
func changeEventDescr(description: String, username: String, number: String, created_at: NSDate, photo: String) {
print(username)
print(description)
print(number)
print(created_at)
print(photo) //that works fine, I see all valid data in the console
userNumber.text = number //doesn't work, I see empty label instead of filled with passed data, the same problem is with other labels
}
What is the problem here?
The problem is when the method changeEventDescr is called the userNumber label is not initialized. You are trying to assign to a nil object.
Create a string variable in your FullRequestFromMap class and store text in it and in your viewDidLoad method you have to assign the text to userNumber label.
class FullRequestFromMap: UIViewController {
#IBOutlet weak var userNumber: UILabel!
var showRequestDetails:ShowRequestDetailsFromMap?
var userNumberLabelText:String = "Default Value"
override func viewDidLoad() {
super.viewDidLoad()
userNumber.text = userNumberLabelText
}
func changeEventDescr(description: String, username: String, number: String, created_at: NSDate, photo: String) {
print(username)
print(description)
print(number)
print(created_at)
print(photo)
userNumberLabelText = number // Here you set the class variable, not the label it self
}
}
class RequestDetails: UIViewController {
......
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "fullRequestSegue") {
fullRequestDetails = segue.destinationViewController as? FullRequestFromMap
// Option 1: You can directly assign it
fullRequestDetails?.userNumberLabelText = "12"
// Option 2: You can call your method
fullRequestDetails?.changeEventDescr(self.descr, username: "adam", number: "12", created_at: self.created_at, photo: self.photo)
}
}
}

Resources