Locate method requestEntities(completionHandler:)
, and replace its implementation with the following:
func requestEntities(completionHandler: @escaping (Error?) -> Void) {
// Only request the first 20 values. If you want to modify the requested entities, you can do it here.
espmContainerOffline.open { error in
guard error == nil else {
return;
}
self.isStoreOpened = true
self.espmContainerOffline.download { error in
guard error == nil else {
let query = DataQuery().selectAll().top(20)
self.espmContainerOffline.fetchProducts(matching: query) { products, error in
guard let products = products else {
completionHandler(error!)
self.closeOfflineStore()
return
}
self.entities = products
completionHandler(nil)
self.closeOfflineStore()
}
return
}
let query = DataQuery().selectAll().top(20)
self.espmContainer.fetchProducts(matching: query) { products, error in
guard let products = products else {
completionHandler(error!)
self.closeOfflineStore()
return
}
self.entities = products
completionHandler(nil)
self.closeOfflineStore()
}
}
}
}
The code above looks a bit more complex compared to the original implementation of the method. This is because the requestEntities
method now also takes care of the opening of the store, downloading of the store and closing the store, each with their error handlers and fallbacks.
In addition, a method or function generally should perform only one single task (the “single responsibility” principle, the first and most important principle of the SOLID object-oriented design guidelines), in this case, execute the request. But to get a better understanding of the flow of the code, it is chosen to combine the above multiple responsibilities into one method.
.
Below this modified method, add the following method:
func closeOfflineStore() {
if isStoreOpened {
do {
try espmContainerOffline.close()
isStoreOpened = false
} catch {
logger.error("Offline Store closing failed")
}
}
logger.info("Offline Store closed")
}
This is used to close the store after each store operation.
In short, the requestEntities(completionHandler:)
method tries to open the offline store first, and then try to perform a download of the data. If no download is possible, chances are the app is offline, and the espmContainerOffline
is queried to retrieve the data. If the download is successful, the app is online, and the online espmContainer
is queried instead.
In a real-world scenario, you would not code it this way because there could be other reasons why the download fails. You would rather download data in the background, and not triggered by a navigation.