[UIImage imageNamed:]
从包中加载文件时会做很多聪明的事情,比如缓存以防止UIImage
同一图像的多个实例,查找@2x 和 ~ipad 后缀,以及scale
正确设置属性。从文档目录(用 a 指定)加载图像时,我希望能够做同样的事情NSURL
。我环顾四周,但在文档中找不到任何内容,我错过了什么吗?
我目前正在自己实现这个(整个shebang,带有缓存等),但我讨厌复制框架代码。我希望在完成之前得到答案,但如果没有,我会发布代码。
这是我想出的最好的东西。这并不理想,因为它在框架中复制了行为(可能存在细微的不一致),但它可以实现我们想要的imageNamed:
.
+ (UIImage*)imageNamed:(NSString*)name relativeToURL:(NSURL*)rootURL
{
// Make sure the URL is a file URL
if(![rootURL isFileURL])
{
NSString* reason = [NSString stringWithFormat:@"%@ only supports file URLs at this time.", NSStringFromSelector(_cmd)];
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil];
}
// Check the cache first, using the raw url/name as the key
NSCache* cache = objc_getAssociatedObject([UIApplication sharedApplication].delegate, @"imageCache");
// If cache doesn't exist image will be nil - cache is created later only if everything else goes ok
NSURL* cacheKey = [rootURL URLByAppendingPathComponent:name];
UIImage* image = [cache objectForKey:cacheKey];
if(image != nil)
{
// Return the cached image
return image;
}
// Various suffixes to try in preference order
NSString* scaleSuffix[] =
{
@"@2x",
@""
};
CGFloat scaleValues[] =
{
2.0f,
1.0f
};
NSString* deviceSuffix[] =
{
([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) ? @"~ipad" : @"~iphone",
@""
};
NSString* formatSuffix[] =
{
@"png"
};
NSURL* imageURL = nil;
CGFloat imageScale = 0.0f;
// Iterate through scale suffixes...
NSInteger ss, ssStart, ssEnd, ssInc;
if([UIScreen mainScreen].scale == 2.0f)
{
// ...forwards
ssStart = 0;
ssInc = 1;
}
else
{
// ...backwards
ssStart = (sizeof(scaleSuffix) / sizeof(NSString*)) - 1;
ssInc = -1;
}
ssEnd = ssStart + (ssInc * (sizeof(scaleSuffix) / sizeof(NSString*)));
for(ss = ssStart; (imageURL == nil) && (ss != ssEnd); ss += ssInc)
{
// Iterate through devices suffixes
NSInteger ds;
for(ds = 0; (imageURL == nil) && (ds < (sizeof(deviceSuffix) / sizeof(NSString*))); ds++)
{
// Iterate through format suffixes
NSInteger fs;
for(fs = 0; fs < (sizeof(formatSuffix) / sizeof(NSString*)); fs++)
{
// Add all of the suffixes to the URL and test if it exists
NSString* nameXX = [name stringByAppendingFormat:@"%@%@.%@", scaleSuffix[ss], deviceSuffix[ds], formatSuffix[fs]];
NSURL* testURL = [rootURL URLByAppendingPathComponent:nameXX];
NSLog(@"testing if image exists: %@", testURL);
if([testURL checkResourceIsReachableAndReturnError:nil])
{
imageURL = testURL;
imageScale = scaleValues[ss];
break;
}
}
}
}
// If a suitable file was found...
if(imageURL != nil)
{
// ...load and cache the image
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:imageURL]];
image = [UIImage imageWithCGImage:image.CGImage scale:imageScale orientation:UIImageOrientationUp];
NSLog(@"Image loaded, with scale: %f", image.scale);
if(cache == nil)
{
cache = [NSCache new];
objc_setAssociatedObject([UIApplication sharedApplication].delegate, @"imageCache", cache, OBJC_ASSOCIATION_RETAIN);
}
[cache setObject:image forKey:cacheKey];
}
return image;
}
如果您发现任何问题,请告诉我。据我所知,语义是这样的imageNamed:
——至少对于最常见的情况。也许有很多不同的图像格式和一些我不知道的其他修饰符 - 代码应该很容易修改以支持它。
我认为这应该可以解决问题,这是检查屏幕比例的简单测试。
UIImage *image;
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2){
// @2x
NSURL *imageURL = [NSURL URLWithString:@"http://www.example.com/images/yourImage@2x.png"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
} else {
// @1x
NSURL *imageURL = [NSURL URLWithString:@"http://www.example.com/images/yourImage.png"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
}
UIImageView *yourImageView = [[UIImageView alloc] initWithImage:image];
这里已经回答了 从 URL 加载时应该如何处理视网膜/普通图像?
希望能帮助到你