1

[UIImage imageNamed:]从包中加载文件时会做很多聪明的事情,比如缓存以防止UIImage同一图像的多个实例,查找@2x 和 ~ipad 后缀,以及scale正确设置属性。从文档目录(用 a 指定)加载图像时,我希望能够做同样的事情NSURL。我环顾四周,但在文档中找不到任何内容,我错过了什么吗?

我目前正在自己​​实现这个(整个shebang,带有缓存等),但我讨厌复制框架代码。我希望在完成之前得到答案,但如果没有,我会发布代码。

4

2 回答 2

1

这是我想出的最好的东西。这并不理想,因为它在框架中复制了行为(可能存在细微的不一致),但它可以实现我们想要的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:——至少对于最常见的情况。也许有很多不同的图像格式和一些我不知道的其他修饰符 - 代码应该很容易修改以支持它。

于 2012-06-17T02:58:19.270 回答
0

我认为这应该可以解决问题,这是检查屏幕比例的简单测试。

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 加载时应该如何处理视网膜/普通图像?

希望能帮助到你

于 2012-06-17T01:32:31.790 回答