tumblrarchive / tmcache Goto Github PK
View Code? Open in Web Editor NEWFast parallel object cache for iOS and OS X.
License: Apache License 2.0
Fast parallel object cache for iOS and OS X.
License: Apache License 2.0
Sometime, I need to clean the disk cache regarding specific rules (not time or size based)
By example, I would like to encode the cache key with attributes, iterate through the cache elements and remove some elements based on the key (encoded) attributes..
Do you think it is doable ?
Any other alternative to iterated the cache elements ?
I would be nice to call a generic "cleanCache" method interface where each developer could implement his own policy..
"@warning Access is protected for the duration of the block, but to maintain safe disk access do not access this fileURL after the block has ended. Do all work on the ."
I don't understand this warning. I presume this is because you want to enforce that it's done on the same queue as everything else, but why is this necessary? Isn't the file manager thread safe? Shouldn't I always be able to read files from different threads?
This is related to the next issue I'm about to post about the synchronous methods. I'll link it after I post.
Thanks for your help.
Really great work @jstn, very much appreciated, thanks for sharing. I think that a cost limit would be useful for the in-memory cache just as well as the disk cache. Was the omission a design choice?
I noticed this issue when trying to cache a number of images at the same time in my own project and was able to recreate it in a sample project by simply requesting lots of object lookups in quick succession:
for (int i=1; i<=100; i++)
{
[[TMCache sharedCache] objectForKey:[NSString stringWithFormat:@"key %d",i]
block:^(TMCache *cache, NSString *key, id object) {
NSLog(@"completed %@",key);
}];
}
I would expect the above to output:
completed key 1
completed key 2
completed key 3
…
completed key 100
but it generally drops out after 1 or 2, or sometimes doesn't respond at all.
By switching:
_queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_CONCURRENT);
in TMCache.m:33 with:
_queue = dispatch_queue_create([queueName UTF8String], DISPATCH_QUEUE_PRIORITY_DEFAULT);
I was able to get the cache responding as expected but this may have other side effects that I am unaware of. Any thoughts?
for build_docs and the podspec
run this test case failed:
- (void)testMemoryWarningBlock
Is it planned to add policies for cache (disk and memory) cleaning ?
It would be very useful especially for images memory caching..
I do not know any good library managing that :(
If I'm not mistaken, when I set an ageLimit, TMCache trims cache by age and repeat the operation every "ageLimit" using dispatch_after.
If I set an ageLimit of 10 sec on t=0, insert an object on t=5, that object keeps in cache for 15 sec.
I think this is not the expected behavior.
Problem becomes worse when ageLimit becomes larger.
Forgive my pool english.
I know that elements stored in TMCache is thread safe. But, is there a way to ensure that objects returned by TMCache is thread safe, such as array or dictionary.
Just like this :
I get a array from TMCache in thread A, and then in thread B, I remove an object from the array while it was traversing the array in thread A. Then I get a crash.
I wish you can understand my express, my English is pool.
can you please add an expire life time for the caching object
Hey,
I have a problem with the library.
Sometimes the completion block of objectForKey is never called.
It seems that the dispatch_async doesn't work in TMDiskCache.
Edit: Seems like there's a compatibility issue with the latest version of Parse, which requires Bolts.
It says on the readme that we can see the docs on cocoadocs.org, but browsing to http://cocoadocs.org/docsets/TMCache/ produces a 404
error.
Hi - I've noticed 2.0 is released on cocoapods. Being a major version number, I assumed it would contain breaking changes. However - I don't see any changes (or mention) in the changelog? Also, at https://github.com/tumblr/TMCache/releases it still lists 1.2.3 as the "latest release" ?
When [TMCache objectForKey:block:] fails to find an object in memory, it falls back to the disk. If it finds the object on disk, it sets the object in memory. This makes sense.
However, if this is happening at the same time a new object is being set for the same key, there's a race to set the object in memory because [TMCache setObject:forKey:block:] sets the memory and disk caches in parallel.
Essentially, if calls to [TMCache objectForKey:block:] and [TMCache setObject:forKey:block:] are made in parallel, there's a chance the underlying calls land in this order:
Until the memory cache is blown away, it will subsequently return the wrong value. This sample code reproduces the issue (it's a race, so obviously it won't repro every time):
TMCache* cache = [TMCache sharedCache];
[cache removeAllObjects];
[cache setObject:@"old" forKey:@"key"];
[cache.memoryCache removeAllObjects];
[cache objectForKey:@"key" block:^(TMCache* cache, NSString* key, id object) {
NSLog(@"get %@", object);
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[cache setObject:@"new" forKey:@"key" block:^(TMCache* cache, NSString* key, id object) {
NSLog(@"set %@", object);
NSLog(@"get2 %@", [cache objectForKey:@"key"]);
}];
});
I expect that this issue manifests extremely rarely, but I figured it's worth pointing out anyway.
TMDiskCache.m line 331 (latest version)
Fatal Exception NSInvalidArgumentException
*** -[NSKeyedUnarchiver initForReadingWithData:]: incomprehensible archive (0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30)
The only thing I know about this crash is that object was an image downloaded from web. (though dozens of similar objects just work)
Submit a spec for commit '89c70886dd74e9b4c799cc075014043d3de56f19'
I want to be use it for 4.x compatible, So I want to make sure which apis below iOS 5.0 has been used?
I have a question about cost limit in TMMemoryCache.
I set the cost limit, but when I called setObject from TMCache, the cost of object always was zero. Then the memory always was in increasing
Can anyone help me?
TMMemoryCahe Code
I am writing a library to combine different cached responses so it will need to do multiple cache requests per method. So, I wanted to go to another thread just once, run all my cache blocks and then return. It's pretty important that this library is fast.
But, the synchronous methods in TMCache all seem to actually run in a queue. Is there a good reason for this? Why don't they just run on the thread they were called on? I don't want to wait for other cache requests to be completed, I want the data ASAP.
It seems like this is maybe to run everything on the same thread, but what in this library is not thread safe?
Thanks.
i want sound from DAC
After taking a look in the code it seems a "+" needs to be removed by "-"
before:
self.byteCount = _byteCount + [byteSize unsignedIntegerValue]; // atomic
should be:
self.byteCount = _byteCount - [byteSize unsignedIntegerValue]; // atomic
A api to check if the object is present in the cache will be a great enhancement in this project.
I was thinking of adding a bloom filter to add this functionality. Need feedback if this is already present in some other way.
Hi, i did like this
[[TMCache sharedCache] setObject:Image
forKey:@"ImageKey"
block:^(TMCache *cache, NSString *key, UIImage *storedImage){}];
But, when i remove application from memory,
and re run application
[[TMCache sharedCache] objectForKey:@"ImageKey" ^(TMCache *cache, NSString *key, UIImage *storedImage) {
NSLog(@"%@",storedImage)
}];
returns Null.
I changed all properties: Max limit of bytes
RT
I'm using the cache to store images into cache (memory and disk)
My app needs to store 35 "small" images and after restarting the app, not all the images are coming from the disk cache...
Where could be the issue ? I have not added any configuration for time or size limit...
Current cocoapods version does not include the new initWithName: rootPath:
method -- please update
I'm confused with memory issues in 2.0.
If I don't implement this
[[NSNotificationCenter defaultCenter] addObserver:memoryCache
selector:@selector(handleMemoryWarning)
name:UIApplicationDidReceiveMemoryWarningNotification
object:[UIApplication sharedApplication]];
[[NSNotificationCenter defaultCenter] addObserver:memoryCache
selector:@selector(handleApplicationBackgrounding)
name:UIApplicationDidEnterBackgroundNotification
object:[UIApplication sharedApplication]];
TMCache will not release memory, although received Memory Warning Notification, right?
A simple example:
self.myDiskCache = [[TMDiskCache alloc] initWithName:@"myDiskCache"];
UIImage *myImg = .....; // 5MB
// call cache multiple times
dispatch_async(self.mySerialQueue, ^{
for (int i=0; i<10; i++) {
[self.myDiskCache setObject:myImg forKey:@"myKey" block:^(TMDiskCache *cache, NSString *key, id<NSCoding> object, NSURL *fileURL) {
NSLog(@"%f MB", cache.byteCount/pow(2., 20.));
}];
}
});
The expectation outputs is "5 MB" for all.
But the chain is 5 MB, 10 MB, ... 50 MB.
I'm loading some images asynchronously in a table view while scrolling.
This starts too many threads on some machines, only in some cases.
Dispatch Thread Soft Limit Reached: 64 (too many dispatch threads blocked in synchronous operations)
Dispatch Thread Hard Limit Reached: 512 (too many dispatch threads blocked in synchronous operations)
I cannot control the amount of concurrent threads, since everything is done using GCD
, without heavily modifying TMCache
.
Any ideas on how to resolve this?
I fill the cache with some images, I restart the app and I call the following code:
NSLog(@"%lu", (unsigned long)[TMCache sharedCache].diskCache.byteCount);
The logs is displaying 0 !!!
If I'm correct this method should return the number of bytes used on the disk used to save my images (35)...and it should not be 0...
It will be nice if we can be able to define the maximum memory usable by in-memory cache mechanism.
In the 1.2.0 release:
- (void)setObject:(id <NSCoding>)object forKey:(NSString *)key block:(TMDiskCacheObjectBlock)block
NSNumber *diskFileSize = [values objectForKey:NSURLTotalFileAllocatedSizeKey];
if (diskFileSize) {
[strongSelf->_sizes setObject:diskFileSize forKey:key];
strongSelf.byteCount = strongSelf->_byteCount + [diskFileSize unsignedIntegerValue]; // atomic
}
Should be changed to something like:
NSNumber *diskFileSize = [values objectForKey:NSURLTotalFileAllocatedSizeKey];
if (diskFileSize) {
NSNumber *oldEntry = [strongSelf->_sizes objectForKey:key];
if (oldEntry && [oldEntry isKindOfClass:NSNumber.class]){
strongSelf.byteCount = strongSelf->_byteCount - [oldEntry unsignedIntegerValue];
}
[strongSelf->_sizes setObject:diskFileSize forKey:key];
strongSelf.byteCount = strongSelf->_byteCount + [diskFileSize unsignedIntegerValue]; // atomic
}
i am not good in english . if i have wrong grammar,please forgive me..
Care to update the changelog for what's new on 1.2.2 and 1.2.1? ;-)
I cache NSData in the diskcache like this:
[[[TMCache sharedCache] diskCache] setObject:cachedData forKey:cacheKey block:^(TMDiskCache *cache, NSString *key, id object, NSURL *fileURL) {}];
And read back like this:
tempData = (NSData *)[[[TMCache sharedCache] diskCache] objectForKey:cacheKey];
The thing is tempData is never freed, and Instruments shows that NSKeyedUnarchiver will call NSData's InitWithCoder which calls an unknown function to allocate memory.
I then tried to define a class like below:
// the .h file
@interface HPCachedData : NSObject
@Property NSString *key;
@Property NSData *value;
@EnD
// the .m file
(id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if (!self) {
return nil;
}
self.key = [decoder decodeObjectForKey:@"key"];
self.value = [decoder decodeObjectForKey:@"value"];
return self;
}
(void)encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.key forKey:@"key"];
[encoder encodeObject:self.value forKey:@"value"];
}
The the memory is still not freed.
Another issue is in both cases, Instruments show 32 bytes leaks in NSConcreateMutableData.
What did I do wrong?
Thanks!
right now it's only possible by date
There's a few already, but they're far from complete.
So if you try to store a file keyed by something like file://localhost/Users/peyton/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/DA12CB50-EA95-479D-BC14-7A01A68914B3/Documents/CameraCache/9EE8E76D-41A9-4226-974A-38D298F8971A-48969-00000C866AB57336.gif
, TMDiskCache will fail silently. After URL encoding, the filename is waaay too long.
Inside <sys/syslimits.h>
, there's NAME_MAX
, the maximum length of the last component of a path, and PATH_MAX
the absolute limit on path length.
I leave it to you to decide what to do.
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.