0

Best practice for storing temporary data during session? I have an app that allows me to register a customer in a medical service, inserting biometrical and personal data (name, weight, personal measures etch.) once the data are saved, you go to other pages, where you can perform some operation using the data. Only at the very end of this path (after 3-4 controllers), I save the Customer in local database via Realm.

during register phase, I need to store this "TempUser"'s data, with can be accessed from multiple controllers.

I think I could use singletons, but not sure IF and HOW

I fund this but not sure which solution fits better.

my idea:

class AppSession {
    
    static var shared = AppSession()
    
    private init() {}
    
    var currentPatient: Patient?
    
}

class Patient {
    
    let shared = Patient()
    
    private init() {}
    
    var name: String? = ""
    var weight: Double = 0.0
}

and in my textfield delegate:

AppSession.shared.currentPatient?.name = data //text from textfield

otherwise, using Patient as a struct, not a class

biggreentree
  • 1,633
  • 3
  • 20
  • 35

1 Answers1

0

It is hard to tell what solution fits for every individual case. It really depends how broadly the data is used in your app. Is it common to every part or just some specific ViewControllers ? How many times it is retrieved and updated ? Also it depends on the architecture pattern you are using and many more factors. So in short, your solution using a singleton pattern may be valid, but can't tell for sure without having a deep look at your project. ​If you decide to stick with your solution, you can omit the AppSession class and directly access your Patient.

class Patient {
    static let shared = Patient()

    var name: String? = ""
    var weight: Double = 0.0
}

And update it:

Patient.shared.name = ""

Even though your solution using a singleton pattern may be valid as mentioned above, you should also consider the user point of view: Do you want the user to be able to continue the flow even after the app was killed ? If yes, than you should save the data after every step(So maybe to KeyChain as what you describe is kind of sensitive data). Or a better solution is to store the data on the server side, which gives the user the flexibility to continue even on an other device(maybe android).

But you can say, that you really do not care about KeyChain neither communicating with a server, and want to do it locally. In this case personally I would pass the data between the controllers, and avoid Singletons. Let's take your Patient object and create a protocol which will require every UIViewController that conforms to it to have a stored property of Patient.

struct Patient {
    var name: String? = ""
    var weight: Double = 0.0
}

protocol MyOnboardingProtocol: class {
    var data: Patient { get set }
}

With the MyOnboardingProtocol you will mark every controller which will require to hold the Patient data. In this way you will force the ViewControllers to hold the Patient object, and will know for the first glance if your ViewController belongs to the "Onboarding" flow.

In your first UIViewController, where your flow begins, you will initialise your Patient object(maybe also make some update on it from user input), and pass along for the next UIViewController:

class MyFirstViewController: UIViewController, MyOnboardingProtocol {
    var data: Patient = Patient()

    func nextViewController() {
        let viewController = MySecondViewController(data: data)
        navigationController?.pushViewController(viewController, animated: true)
    }
}

For every other UIViewController down the road you will pass the updated object into the init:

class MySecondViewController: UIViewController, MyOnboardingProtocol {
    var data: Patient

    init(data: Patient) {
        self.data = data
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
    }
}

But as I mentioned before, what I described is just one way of doing it. It will really depend on your individual case and business logic. As I want to keep my answer short, I encourage you to discover the topic a bit more, there has been many great articles about this topic.

πter
  • 1,899
  • 2
  • 9
  • 23
  • thank for your help, your solution using protocol is very interesting, but no issue about Struct being value type? I'm afraid that there could be some issue about objects being copied instead passed. – biggreentree Mar 09 '21 at 14:54
  • well, you can use also a `class` for that, so the reference is passed. It will save you some pain, for example when navigating back in the flow, if you use `struct` you would need to pass the current object back to the previous `UIViewController`. So use `class` if that suits you more. I am just personally used to use `structs` whenever I can. But it is just a personal preference. – πter Mar 09 '21 at 15:11
  • thanks!. last question, you code in second controller crashes due to // fatalError("init(coder:) has not been implemented"), is t it so since my controller is in storyboard? – biggreentree Mar 09 '21 at 16:14
  • Yes. That's because of the storyboard. You can just remove both of the init methods, make the `data: Patient` either optional (`?`) or implicitly unwrapped (`!`), and when making a segue, assign the data to the ViewController `viewController?.data = data` – πter Mar 09 '21 at 16:43