Open Reedyuk opened 7 years ago
Actually, just to add. When i set the actual full path, then the observer works fine. So this maybe a feature request instead. The ability to wildcard add observers.
I created a quick fix for my code for now:
extension Configuration {
public mutating func listenToRequests() {
decorateRequests {
resource, request in
request.onFailure { _ in
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.resourceChanged(resource, event: .error)
}
}
request.onSuccess { _ in
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.resourceChanged(resource, event: .newData(.network))
}
}
return request
}
}
}
Then to use it,
service.configure {
$0.useNetworkActivityIndicator()
$0.listenToRequests()
}
There are many compelling reasons for this feature or something like it: automatic retry after reestablishing a lost connection, for example, or automatically polling resources while they’re in use.
It’s more complicated than just extending the domain of addObserver(…)
, however. Under Siesta’s memory rules, resources are retained as long as they’re observed — and if a resource is always observed, then it can never be deallocated.
We need a beast that’s slightly different from a ResourceObserver
that can:
That’s a big chunk of API design to bite off, so I’ve been deferring it. I’d prioritize it just after having a standard drop-in EntityCache
implementation. In the meantime, your decorator approach is a good workaround.
I've been looking at ways to cache some images in a way so that volatile views (observers) are likely, but not required, to find the image locally. This happens in the reuse (q.v.) of CollectionCells as the user scrolls back and forth; a cell scrolls out of view, gets reused, and the original request is dropped on the floor only to be re-requested when the users reverses the scrolling.
I'm thinking of creating a dedicated Service with an EntityCache that implements a "keep the most n recently used" (or such). This way a request for a particular image (URL) is likely to still be available if it is re-requested within a short time.
Thoughts?
I've been looking at ways to cache some images in a way so that volatile views (observers) are likely, but not required, to find the image locally. This happens in the reuse (q.v.) of CollectionCells as the user scrolls back and forth; a cell scrolls out of view, gets reused, and the original request is dropped on the floor only to be re-requested when the users reverses the scrolling.
This is exactly what Siesta is designed for as it stands, and the GithubBrowser example project contains code that demonstrates exactly what you describe (with table views, even).
This issue is about making an observer that can keep watching a resource as long as it is in use by others, but without causing it to be retained forever. For example, such an observer could say, “As long as anyone is using a ‘current temperature’ resource, keep refreshing it.”
Hi @pcantrell,
I would like to weigh in with another use case.
I'm currently trying to implement some kind of in-app debug/network monitor.
I'm trying to mimic something that sniffs on the network traffic (like Charles, https://www.charlesproxy.com does) but in a very Siesta-kind of way. I want to be able to track the used resources, responses and combine this with the data before transformation happens.
@Reedyuk's listenToRequests
extension was the first step. It let's me track all used resources and hook into their requests. But combining this with a custom transformer is fruitless.
// This no real implementation, just snippets
struct NetworkResourceState {
static var collected: [String: NetworkResourceState]
let rawData: Any?
let entity: Entity<Any>?
}
extension Configuration {
public mutating func sniffRequests() {
// I want to hook into the initial data before it passes the transformations,
// so I get the "cleanest" data possible
pipeline[.rawData].add(NetworkSniffer())
decorateRequests { resource, request in
// here I can track the resources and hook in into their requests
// I will save the needed data into memory using the resource's `absolutePath` as
// the key
var state = NetworkResourceState.collected[resource.url.absolutePath] ?? NetworkResourceState()
NetworkResourceState.collected[resource.url.absolutePath] = state
request.onCompletion { _ in
switch responseInfo.response {
case .success(let entity):
state?.latestData = entity
case .failure(_):
break
}
}
}
}
struct NetworkSniffer: ResponseTransformer {
func process(_ response: Siesta.Response) -> Siesta.Response {
switch response {
case .success(let entity):
// While I can easily get the response data in a very basic state here
// I have no chance to reference it to the request (OR resource) that
// ended in this response
...
case .failure(let error):
break
}
return response
}
}
Now if the response would e.g. include the absolute path of the initial resource/request I would be able to link these two steps together. But as it stand Siesta is too closed to be able to understand where things are coming from.
I totally understand the reasoning and I believe it's very good practice to have all these little parts be independent from each other as possible, but maybe there is a way to piggy-pack some introspection information in the chains so one could connect the dots easier?
PS: I could try to merge something like https://github.com/Kofktu/Sniffer and Siesta, but that's not really what I'm looking at (at least not right now). I would like to keep the flow in context of Siesta: Resources -> Responses, with the small issue to get to the rawest form of data as possible before Siesta's transformation chain does it's magic.
Hi Paul, I'm having a little trouble in adding an observer which is called upon All network requests made by a Siesta service object.
service.resource("*").addObserver(self)
Where self is adopting the resourceObserver protocol.I get the observer callback when i add and remove the observer but it doesn't seem to be latching onto my network requests.
Thoughts? I'm sure its something simple.