1

In my work, I came across the fact that I often need to store some properties as long as the application is running and so that I can access them from different files and classes.

Here's one example. I authorize a user in Google Drive and I need to save this user to a variable in order to refer to him in another class. I declare global constant over the class, but I'm not sure if this is a good practice. If I declare this variable inside a class and access it through an instance of the class, my application does not work.

public var googleUser: GIDGoogleUser?

class MyViewController: UIViewController {
    ...
    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
              withError error: Error!) {
    googleUser = user //Here I save user to googleUser property
    }
    ...
}

class GoogleDriveService {
    ...
    private lazy var driveService: GTLRDriveService = {
        let service = GTLRDriveService()
        if let user = googleUser { //Here I use googleUser property
            service.authorizer = user.authentication.fetcherAuthorizer()
        }
        service.shouldFetchNextPages = true
        service.isRetryEnabled = true
        
        return service
    }()

    //Then I use the driveService property in some methods like fetchFileList, download and other, which I call from different View Controllers referring to an instance of the GoogleDriveService class
    ...
}
gcharita
  • 7,729
  • 3
  • 20
  • 37
  • 1
    You can use UserDefaults to write and read the value(s), another option if the values are immutable is to use a singleton class or if they are mutable to use local notifications so any interested class subscribes to any changes of the value(s) – Joakim Danielson Sep 16 '20 at 11:22
  • What is "the entire life cycle of the application"? – Roman Ryzhiy Sep 16 '20 at 11:32
  • @Roman Ryzhiy I want to store this property from the moment it's filled with a value until the end of the application work, the next time the application is launched, this property will be retrieved again. I'm satisfied with how it works now, it's convenient for me to access the property directly, but I want to know if this is a good practice or is it better not to do so. If this is bad practice, how should I do it? – VyacheslavBakinkskiy Sep 16 '20 at 11:37
  • @VyacheslavBakinkskiy https://stackoverflow.com/questions/31203241/how-can-i-use-userdefaults-in-swift – Roman Ryzhiy Sep 16 '20 at 11:39
  • @Roman Ryzhiy But in UserDefaults, this property will be stored as long as the application is installed on the device, or I will have to delete it from UserDefaults every time the application ends. I think this is too much. Is there really no simpler? – VyacheslavBakinkskiy Sep 16 '20 at 11:42
  • 1
    @VyacheslavBakinkskiy So you are talking about global variables and constants? Just declare it on the top level of any source file and use it anywhere in the app. – Roman Ryzhiy Sep 16 '20 at 11:44
  • @Roman Ryzhiy , that's what I do. If you've read my question carefully, then I'm asking if this is a good practice? If yes, then great, I will only be glad. – VyacheslavBakinkskiy Sep 16 '20 at 11:46
  • @VyacheslavBakinkskiy If you've studied Software Development carefully, "the entire life cycle of the application" means the period since the beginning of the app's development till it's uninstallation as out-of-dated. – Roman Ryzhiy Sep 16 '20 at 11:56
  • @Roman Ryzhiy Sorry, I'm still improving my English, I'll correct the question now. – VyacheslavBakinkskiy Sep 16 '20 at 12:00
  • You say “I declare public property over the class”. What do those words mean? Give an example. You do show some code but the only property is private. Show us what you do. – matt Sep 16 '20 at 12:05
  • @matt I have declared a property "public var googleUser: GIDGoogleUser?" above the class – VyacheslavBakinkskiy Sep 16 '20 at 12:07
  • 1
    Ok I see. That is not a property so it’s confusing. – matt Sep 16 '20 at 12:10
  • @matt Sorry, I corrected in the question. – VyacheslavBakinkskiy Sep 16 '20 at 12:13

1 Answers1

3

You can use a static variable of a struct to do this more elegant:

struct Repository {
    static var googleUser: String?
}

and access/set googleUser using the struct type:

Repository.googleUser = user

Or even better, use a singleton class like this:

class Repository {
    static let shared = Repository()
    var googleUser: String?
}

then you can use it directly:

Repository.shared.googleUser = user

or inject the singleton instance to whichever class want to use googleUser.

gcharita
  • 7,729
  • 3
  • 20
  • 37
  • This is a good solution, thanks. – VyacheslavBakinkskiy Sep 16 '20 at 12:05
  • If my project has several such variables, can I put them in one class? For example, the class GlobalVariables. Or is it better to use different classes? – VyacheslavBakinkskiy Sep 16 '20 at 12:16
  • 1
    @VyacheslavBakinkskiy you can use the first method (with the struct) and embed other structs inside it or you can use entirely different structs or classes. This is up to you. Whatever make more sense in your project. – gcharita Sep 16 '20 at 12:20
  • @VyacheslavBakinkskiy I just suggest the singleton approach for the only reason that can be used better with dependency injection. – gcharita Sep 16 '20 at 12:22