spring-media / carlos Goto Github PK
View Code? Open in Web Editor NEWA simple but flexible cache
License: MIT License
A simple but flexible cache
License: MIT License
First mvp would be to have some queue on the network fetcher where the requests are dispatched, and the queue could have a given maxNumberOfConcurrentOperations
. To do so, though, Request
objects should be NSOperation
s and this would complicate things. Another way is to have a generic RequestCapper
class that takes a number and a cache and "counts" the number of ongoing requests decrementing it only when onSuccess
or onFailure
is called. This should work on all CacheLevel
s and doesn't require any change in a specific CacheLevel
like the NetworkFetcher
.
Document more classes in the codebase so that the automatic documentation generated by CocoaPods is more pleasant to browse
If, instead of using a list of CacheLevels, we use a composition of CacheLevels, where each takes a type and outputs another (not necessarily different) type, we could have both a generic cache that stores whatever type (not only NSData), but more than that we could have an integrated transformation mechanism that lets single levels manipulate data depending on their internal details.
The closure will be called in both success and failure cases, either without any parameter or with 2 optional parameters error
and result
It would be nice to add some public functions or maybe one helper class with a couple of methods on it, to create the most common caches (e.g. Memory -> Disk -> Network)
This way one doesn't have to always write the boilerplate code for simple usages
The CacheRequest should be a generic protocol with the following functions:
public protocol CacheRequest {
typealias KeyType
typealias OutputType
func cancel()
func onFailure(NSError? -> Void)
func onSuccess(OutputType -> Void)
}
this way we could get rid of the success and failure parameters passed to all the basic caches and composition/transformation operators, and just use the request object instead.
Moreover, we would get free support to canceling requests (for example expensive network requests), and easier support to request pooling.
BasicCache (✓)
CacheRequest (✓)
Composition (✓)
Conditioning (✓)
Pooling (✓)
DiskCache (✓)
MemoryCache (✓)
NetworkCache (next release)
Extensions (✓)
Memory warning (✓)
Key transformation (✓)
Value transformation (✓)
OneWayTransformer (✓)
TwoWayTransformer (✓)
The main entry-point Cache could internally keep a pool of ongoing requests so to avoid double requests and group them instead.
By having an explicit error type, users can use custom enumerations when notifying errors instead of wrapping their raw values in NSError
instances.
I just read the README.md and like the detailed documentation. I only have two questions left:
Is it possible to setup a playground that imports a Framework? Otherwise, just import all the Carlos files.
But it would be nice to have a simple playground where one can create caches, levels and see how the operators, functions and closures work together
In README.md, mention the work contains classes based and adapted from the HanekeSwift repository.
In LICENSE or NOTICES, include the Apache 2.0 license HanekeSwift uses
As we have key and value transformations, we should probably allow error transformations to make it possible to combine several cache levels
Similar to value transformers, introduce "output transformers", that transform values of one type to values of the same type but apply some logic on top (for example resize images, sanitize strings, etc). These transformers can be chained to CacheLevels and will affect the data that will be returned by get requests, but not the data that will be saved on set requests, as it happens for normal value transformers.
(Long-term, Carlos will just be a special case of a generic async computation composition library)
I think adding support for the watchos 2 would be very helpful
Ideally there would be a class, an operator and some protocol extension that let the user specify on which queue the requests should be dispatched.
use protocol extensions instead of global functions everywhere
The SwitchCache
level is an object that takes 2 equivalent caches (same key, same value) and a condition closure that takes the key and has to return either one cache or the other. This way one could setup two different cache "lanes" and choose the lane depending on the key or some external condition.
Basic idea is that every CacheLevel
has its own logger reference. Logger
is a protocol with a log
function.
Breakdown would be:
public enum LogLevel {
case Debug, Info, Warning, Error, Fatal, None
}
public protocol Logger {
func log(message: String, level: LogLevel)
}
and then
public protocol CacheLevel {
[...]
func setLogger(logger: Logger)
}
Then one can call setLogger
on whatever CacheLevel
(for example the top-most, that will set the logger to all its managed cache levels, or whichever you need to).
This way every cache can throw specific errors without using NSErrors and without the need for error transformers
To do this, we need a key transformation block first
All specific caches (Pool, RequestCapper, Basic, etc) should subclass this class so that creating complex cache levels doesn't result in an unreadable inferred type.
Transformers should be able to return optional values, so that if they fail the cache level will be skipped and the get/set will be treated as a failure.
It would be great if the user could directly return literal values when implementing get
when creating custom levels or fetch closures.
To do this, CacheRequest
has to extend *LiteralConvertible (String, Integer, etc.).
Question: is it possible to do it for a generic class?
In case it is, implement and update README.md
An infix operator would do the trick, but then we'd have to find a good one. Otherwise, I was thinking at a fake cache level result of a pooled() free function that, combined with the usual >>> composition operator, would actually call the pooled(_) function, through an overloading of the >>> operator. But that's also quite weird.
Other options?
Just as Haneke does, we could be more flexible and cache UIImage values or even custom types that can be encoded and decoded to NSData.
Things to show:
Right now NetworkFetcher has set, clear and onMemoryWarning methods that are no-ops. Maybe we could make the NetworkFetcher a fetch closure instead of a full-blown cache level.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.