我正在开发一个 iOS 应用程序,它需要 SDWebImage 将图片永久缓存到手机上。
谢谢。
最佳答案
遗憾的是 SDWebImage 没有提供这样的能力 所以为了利用 SDWebImage 提供的高级缓存功能,我围绕它编写了一个包装器
基本上这个类管理一个后备永久缓存,所以如果在 SDWeb 图像缓存“磁盘和内存”中找不到请求的图像,它将在永久缓存中寻找它 如果找到永久缓存,它将被复制到 SDwebImage 缓存中,以便在以后的请求中使用其内存
使用这种方法,我设法像往常一样使用 SDWebImage 将图像设置为表格单元格 您还可以在需要时触发 clearImageCache 来清除永久缓存
.h文件
@interface CacheManager : NSObject
+ (CacheManager*)sharedManager;
// Images
- (BOOL) diskImageExistsForURL:(NSURL*) url;
- (void) downloadImage:(NSURL*) url completed:(void(^)(UIImage*))onComplete;
- (void) setImage:(NSURL*)url toImageView:(UIImageView*)iv completed:(void(^)(UIImage*))onComplete;
- (void) clearImageCache;
@end
.m 文件
#import "CacheManager.h"
#import <SDWebImage/UIImageView+WebCache.h>
#define CACH_IMAGES_FOLDER @"ImagesData"
@implementation CacheManager
static CacheManager *sharedManager = nil;
#pragma mark -
#pragma mark Singilton Init Methods
// init shared Cache singleton.
+ (CacheManager*)sharedManager{
@synchronized(self){
if ( !sharedManager ){
sharedManager = [[CacheManager alloc] init];
}
}
return sharedManager;
}
// Dealloc shared API singleton.
+ (id)alloc{
@synchronized( self ){
NSAssert(sharedManager == nil, @"Attempted to allocate a second instance of a singleton.");
return [super alloc];
}
return nil;
}
// Init the manager
- (id)init{
if ( self = [super init] ){}
return self;
}
/**
@returns YES if image found in the permanent cache or the cache managed by SDWebImage lib
*/
- (BOOL) diskImageExistsForURL:(NSURL*) url{
// look for image in the SDWebImage cache
SDWebImageManager *manager = [SDWebImageManager sharedManager];
if([manager diskImageExistsForURL:url])
return YES;
// look for image in the permanent cache
NSString *stringPath = url.path;
NSFileManager *fileManager = [NSFileManager defaultManager];
return [fileManager fileExistsAtPath:stringPath];
}
/**
get the image with specified remote url asynchronosly
first looks for the image in SDWeb cache to make use of the disk and memory cache provided by SDWebImage
if not found, looks for it in the permanent cache we are managing, finally if not found in either places
it will download it using SDWebImage and cache it.
*/
- (void) downloadImage:(NSURL*) url completed:(void(^)(UIImage*))onComplete{
NSString *localPath = [[self getLocalUrlForImageUrl:url] path];
NSFileManager *fileManager = [NSFileManager defaultManager];
// -1 look for image in SDWeb cache
SDWebImageManager *manager = [SDWebImageManager sharedManager];
if([manager diskImageExistsForURL:url]){
[manager downloadImageWithURL:url options:SDWebImageRetryFailed
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
onComplete(image);
// save the image to the perminant cache for later
// if not saved before
if(image){
if ([fileManager fileExistsAtPath:localPath]){
NSURL* localeUrl = [self getLocalUrlForImageUrl:url];
[self saveImage:image toCacheWithLocalPath:localeUrl];
}
}
}];
return;
}
// -2 look for the image in the permanent cache
if ([fileManager fileExistsAtPath:localPath]){
UIImage *img = [self getImageFromCache:url];
onComplete(img);
// save image back to the SDWeb image cache to make use of the memory cache
// provided by SDWebImage in later requests
[manager saveImageToCache:img forURL:url];
return;
}
// -3 download the image using SDWebImage lib
[manager downloadImageWithURL:url options:SDWebImageRetryFailed
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
onComplete(image);
// save the image to the permanent cache for later
if(image){
NSURL* localeUrl = [self getLocalUrlForImageUrl:url];
[self saveImage:image toCacheWithLocalPath:localeUrl];
}
}];
}
- (void) setImage:(NSURL*)url toImageView:(UIImageView*)iv completed:(void(^)(UIImage*))onComplete{
[self downloadImage:url completed:^(UIImage * downloadedImage) {
iv.image = downloadedImage;
onComplete(downloadedImage);
}];
}
/**
@param:imgUrl : local url of image to read
*/
- (UIImage*) getImageFromCache:(NSURL*)imgUrl{
return [UIImage imageWithData: [NSData dataWithContentsOfURL:imgUrl]];
}
/**
writes the suplied image to the local path provided
*/
-(void) saveImage:(UIImage*)img toCacheWithLocalPath:(NSURL*)localPath{
NSData * binaryImageData = UIImagePNGRepresentation(img);
[binaryImageData writeToFile:[localPath path] atomically:YES];
}
// Generate local image URL baesd on the name of the remote image
// this assumes the remote images already has unique names
- (NSURL*)getLocalUrlForImageUrl:(NSURL*)imgUrl{
// Saving an offline copy of the data.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSString *folderPath = [cachesDirectory stringByAppendingPathComponent:CACH_IMAGES_FOLDER];
BOOL isDir;
// create folder not exist
if (![fileManager fileExistsAtPath:folderPath isDirectory:&isDir]){
NSError *dirWriteError = nil;
if (![fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:&dirWriteError]){
NSLog(@"Error: failed to create folder!");
}
}
NSString *imgName = [[[imgUrl path] lastPathComponent] stringByDeletingPathExtension];
NSURL *cachesDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSCachesDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
NSString *pathString = [NSString stringWithFormat:@"%@/%@", CACH_IMAGES_FOLDER, imgName];
return [cachesDirectoryURL URLByAppendingPathComponent:pathString];
}
/**
removes the folder contating the cahced images,
the folder will be reacreated whenever a new image is being saved to the permanent cache
*/
-(void)clearImageCache{
// set the directory path
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSString *folderPath = [cachesDirectory stringByAppendingPathComponent:CACH_IMAGES_FOLDER];
BOOL isDir;
NSError *dirError = nil;
// folder exist
if ([fileManager fileExistsAtPath:folderPath isDirectory:&isDir]){
if (![fileManager removeItemAtPath:folderPath error:&dirError])
NSLog(@"Failed to remove folder");
}
}
@end
关于ios - 具有永久缓存的 sdwebimage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39642465/
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我试过重新启动apache,缓存的页面仍然出现,所以一定有一个文件夹在某个地方。我没有“公共(public)/缓存”,那么我还应该查看哪些其他地方?是否有一个URL标志也可以触发此效果? 最佳答案 您需要触摸一个文件才能清除phusion,例如:touch/webapps/mycook/tmp/restart.txt参见docs 关于ruby-如何在Ubuntu中清除RubyPhusionPassenger的缓存?,我们在StackOverflow上找到一个类似的问题:
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
尝试在我的RoR应用程序中实现计数器缓存列时出现错误Unknownkey(s):counter_cache。我在这个问题中实现了模型关联:Modelassociationquestion这是我的迁移:classAddVideoVotesCountToVideos0Video.reset_column_informationVideo.find(:all).eachdo|p|p.update_attributes:videos_votes_count,p.video_votes.lengthendenddefself.downremove_column:videos,:video_vot
我正在使用Rails3.1并在一个论坛上工作。我有一个名为Topic的模型,每个模型都有许多Post。当用户创建新主题时,他们也应该创建第一个Post。但是,我不确定如何以相同的形式执行此操作。这是我的代码:classTopic:destroyaccepts_nested_attributes_for:postsvalidates_presence_of:titleendclassPost...但这似乎不起作用。有什么想法吗?谢谢! 最佳答案 @Pablo的回答似乎有你需要的一切。但更具体地说...首先改变你View中的这一行对此#
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我从用户Hirolau那里找到了这段代码:defsum_to_n?(a,n)a.combination(2).find{|x,y|x+y==n}enda=[1,2,3,4,5]sum_to_n?(a,9)#=>[4,5]sum_to_n?(a,11)#=>nil我如何知道何时可以将两个参数发送到预定义方法(如find)?我不清楚,因为有时它不起作用。这是重新定义的东西吗? 最佳答案 如果您查看Enumerable#find的文档,您会发现它只接受一个block参数。您可以将它发送两次的原因是因为Ruby可以方便地让您根据它的“并行赋
RSpec似乎按顺序匹配方法接收的消息。我不确定如何使以下代码工作:allow(a).toreceive(:f)expect(a).toreceive(:f).with(2)a.f(1)a.f(2)a.f(3)我问的原因是a.f的一些调用是由我的代码的上层控制的,所以我不能对这些方法调用添加期望。 最佳答案 RSpecspy是测试这种情况的一种方式。要监视一个方法,用allowstub,除了方法名称之外没有任何约束,调用该方法,然后expect确切的方法调用。例如:allow(a).toreceive(:f)a.f(2)a.f(1)
我有一个模块stat存在于目录结构中:lib/stat_creator/stat/在lib/stat_creator/stat.rb中,我在lib/stat_creator/stat/目录中有我需要的文件,以及:moduleStatCreatormoduleStatendend当我使用该模块时,我将这些类称为StatCreator::Stat::Foo.new现在我想要一个存在于应用程序中的根Stat类。我在app/models中制作了我的Stat类,并在routes.rb中进行了设置。但是,如果我转到Rails控制台并尝试在应用程序/模型中使用Stat类,例如:Stat.by_use