Lama
Lama

Reputation: 255

Globally save and access received data

I'm trying to get some data from the server and use it globally in the app..

I mean for example, I'm using following code to get data from service:

struct Service : Decodable{
    let id: Int
    let name, description: String
    let createdAt: String?
    let updatedAt: String?
}

func makeGetCall() {
    let todoEndpoint: String = "http://web.src01.view.beta.is.sa/public/api/services"
    guard let url = URL(string: todoEndpoint) else {
        print("Error: cannot create URL")
        return
    }
    let urlRequest = URLRequest(url: url)

    let config = URLSessionConfiguration.default
    let session = URLSession(configuration: config)

    let task = session.dataTask(with: urlRequest) {
        (data, response, error) in
        guard error == nil else {
            print("error calling GET on /public/api/services")
            print(error!)
            return
        }
        guard let responseData = data else {
            print("Error: did not receive data")
            return
        }
        do {

            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase
            let todos = try decoder.decode([Service].self, from: responseData)
            for todo in todos{
                print(todo.name)
            }

        } catch  {
            print("error trying to convert data to JSON")
            return
        }
    }
    task.resume()
}

This code is located and called in HomeViewController and i'm getting data which i want.

But i want to access and use this data in another viewcontroller and in whole app...

How i can do it? How can i make the received data from the function is saved globally and how to use it in another viewcontroller?

Can someone tell me how i can do this?

Upvotes: 0

Views: 42

Answers (1)

Matic Oblak
Matic Oblak

Reputation: 16774

For such cases we usually use static data. They may be served as singleton or just a static property. In your case a static property for cached data may be nice. We can put static properties in extension so adding following may be nice:

// MARK: - Fetching Data
extension Service {

    private static var cachedServices: [Service]?

    static func fetchServices(_ completion: (_ services: [Service]) -> Void?) {
        if let cachedServices = cachedServices {
            completion(cachedServices)
        } else {
            makeGetCall { services in
                let newServices = services ?? []
                self.cachedServices = newServices
                completion(newServices)
            }
        }
    }

}

Now the usage from everywhere is calling

Service.fetchServices { services in
}

and this call may be asynchronous or not, depending if data is already loaded.

If you need to access them synchronous and you are sure data is already loaded then simply add another method in extension:

static func getCachedData() -> [Service] {
    return cachedServices ?? []
}

This method will return instantly but array will be empty if no data was received yet. But anywhere you can call Service.getCachedData()

This cache is now only preserved until your app terminates. If you want to preserve them longer then all you need to do is add the logic to save and load data into file or user defaults. The logic for that would be something like:

private static var cachedServices: [Service]? {
    didSet {
        self.saveServicesToFile(cachedServices)
    }
}

static func fetchServices(_ completion: (_ services: [Service]) -> Void?) 
{
    if let cachedServices = cachedServices {
        completion(cachedServices)
    } else if let saved = self.loadFromFile() {
        self.cachedServices = saved
        completion(saved)
    }else {
        makeGetCall { services in
            let newServices = services ?? []
            self.cachedServices = newServices
            completion(newServices)
        }
    }
}

Upvotes: 1

Related Questions