1

I am working on a project containing a "Create New Account" view controller with its accompanying Swift class called "CreateNewAccount." The user can place 4 input values into this view controller, a first name, last name, user name, and password. Upon clicking the "Create Account" button in this VC, the 4 input values are passed on to a Swift class (within the model layer of MVC, I believe) called UserInfoRetrieveModel where they are supposedly stored.

I would then like to pass these values to another Swift class (that is a model as well) called UserInfoModel, which will then delegate out the first name value to the text value of label located in a VC called "ThanksForJoining" (and its accompanying class).

I have figured out how to pass values from VC to model (CreateNewAccount to UserInfoRetrieveModel) and from model to VC (UserInfoModel to ThanksForJoining), but somewhere in my transference from model to model (UserInfoRetrieveModel to UserInfoModel) the values initially inputted into "CreateNewAccount," which I would like to pass over to the second model class UserInfoModel become nil.

Below is the code for CreateNewAccount, UserInfoRetrieve, UserInfo, and ThanksForJoining:

CreateNewAccount ->

import UIKit

class CreateNewAccount: UIViewController{

@IBOutlet weak var FNInput: UITextField!
@IBOutlet weak var LNInput: UITextField!
@IBOutlet weak var usernameInput: UITextField!
@IBOutlet weak var passwordInput: UITextField!

var uInfoRetrieve = UInfoRetrieveModel()

@IBAction func thanksForJoining(_ sender: Any) {
    uInfoRetrieve.firstName = FNInput.text!
    uInfoRetrieve.lastName = LNInput.text!
    uInfoRetrieve.userName = usernameInput.text!
    uInfoRetrieve.password = passwordInput.text!
    uInfoRetrieve.delegate = self
    uInfoRetrieve.retrieving()
}
override func viewDidLoad() {
    super.viewDidLoad()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
 }
}

extension CreateNewAccount: UInfoRetrieveModelDelegate{
    func credentialTransfer(data: String) {
      print(data)
  }
}

UserInfoRetrieve ->

import Foundation

protocol UInfoRetrieveModelDelegate: class {
  func credentialTransfer(data:String)
 }


class UInfoRetrieveModel: NSObject {

   weak var delegate: UInfoRetrieveModelDelegate?

     var firstName: String = ""
     var lastName: String = ""
     var userName: String = ""
     var password: String = ""

func retrieving(){


    delegate?.credentialTransfer(data: firstName)
    delegate?.credentialTransfer(data: lastName)
    delegate?.credentialTransfer(data: userName)
    delegate?.credentialTransfer(data: password)
    }

}

UserInfo ->

import Foundation

protocol UserInfoModelDelegate: class {
    func didReceiveDataUpdate(data: String)
   }

class UserInfoModel {
   weak var delegate: UserInfoModelDelegate?

   let uInfoRetrieve = UInfoRetrieveModel()

   func requestData() -> Array<String> {

    let firstName = uInfoRetrieve.firstName
    let lastName = uInfoRetrieve.lastName
    let userName = uInfoRetrieve.userName
    let password = uInfoRetrieve.password

    delegate?.didReceiveDataUpdate(data: firstName)
    delegate?.didReceiveDataUpdate(data: lastName)
    delegate?.didReceiveDataUpdate(data: userName)
    delegate?.didReceiveDataUpdate(data: password)
    let credentials = [firstName, lastName, userName, password] as [Any]
    return credentials as! Array<String>
  }
}  

ThanksForJoining ->

import UIKit

class ThanksForJoining: UIViewController {

   var userInfo = UserInfoModel()


  @IBOutlet weak var firstName: UILabel!

  override func viewDidLoad() {
    super.viewDidLoad()
    userInfo.delegate = self
    firstName.text = userInfo.requestData()[0]
    print("yo")
    print(userInfo.requestData()[0])
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
  }
}

extension ThanksForJoining: UserInfoModelDelegate {

   func didReceiveDataUpdate(data: String) {
      print(data)
   }
}
Swift Dev Journal
  • 19,282
  • 4
  • 56
  • 66
Elan Kainen
  • 57
  • 1
  • 9

1 Answers1

2

UserInfoModel and CreateNewAccount do both create a new instance of UInfoRetrieveModel. You have to connect them properly for them to pass on information.

Connecting properly means (in the simplest form) one constructs the other and sets itself as the delegate of the other, so UInfoRetrieveModel can pass on data. The constructing of a child model is usually done via a computed property.

Example

struct Account {
    let firstName: String, lastName: String
    let userName: String, password: String
}

extension UInfoRetrieveModelDelegate: class {
    createAccount(_ account: Account): Bool
}

extension UserInfoModel: UInfoRetrieveModelDelegate{
    func createAccount(_ account: Account) -> Bool {
        // Handling creation of account.
        return success == true
    }
    var newUInfoRetrieveModel: UInfoRetrieveModel {
        let helperModel = UInfoRetrieveModel(parent: self)
        helperModel.delegate = self
        return helperModel
    }
}

Explanation

Yes. You usually have a Model, your data, then have something that controls access to it to make changes on your model, manages how the model is stored, maybe syncing with a cloud-service, thats the ModelController which you pass around between ViewControllers, more/other controllers you usually use incase that makes things simpler. In your case you would probably pass createAccount(the call) on to a controller/viewController which is in charge of telling the modelController to create the account and then telling one of its views/viewControllers to display the modal/whatever.

The usual way to pass data to a higher level is to have for the viewController/controller a delegate it uses to communicate with higher up, the one “responsible for actions the ViewController/controller cannot do by itself”, eg pushing data up(creation calls, modification calls, deletion calls) if it makes no sense to give it a modelController since its not control of that part of the application, etc. In your case you can of course pass a modelController to each little viewController/view, but its usually more practical/simpler to only give it to the one controlling the part and let others communicate with that currently-that-part-controlling controller/viewController.

More partical here means that you may not want CreateAccountViewController to display the success dialog, but rather another, which CreateAccountViewController can then do not by itself since it’s not on the stack anymore.

Fabian
  • 5,040
  • 2
  • 23
  • 35
  • thanks for the insight, which class do I put this within, or does it get placed in its own swift file? – Elan Kainen Aug 24 '18 at 19:42
  • @ElanKainen That usually depends on how you do things. The simplest way to manage it is to have a `modelController` at hand, in your controller or in your viewController where you are creating the `CreateNewAccount`-vc. After its creation or in prepareForSegue you set on `CreateNewAccount` the `userInfoRetrieveModel` you got from your `UserInfoModel.newInfoRetrieveModel`, push `CreateNewAccountViewController` on the stack etc. I usually have a single `modelController` so it was just an idea how one may work with it to make things simple and usable. – Fabian Aug 24 '18 at 19:51
  • I am new to Swift and Xcode so thanks for bearing with me…in regards to the steps you just described and your reference to a single modelController, are you basically saying I can pass info created in CreateNewAccount to one model and then from there dish out that info from that model to other VC's instead of passing data between two models, a receiving model to an outputting model? – Elan Kainen Aug 24 '18 at 20:16
  • @ElanKainen It got a little long so I edited the answer instead of writing here. What I use is not necessarily MVC since I do not know what that means exactly. If you want to use canonic MVC you may way to read [How should a Model be structured in MVC](https://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc?rq=1), which is more language-agnostic though so you might have to adapt it to your needs and fill out the things unwritten. – Fabian Aug 24 '18 at 21:04