2012-06-17 74 views
1

[UIImage imageNamed:]在從包中加載文件時會做很多聰明的事情,如緩存以防止同一圖像的多個UIImage實例,尋找@ 2x和〜ipad後綴,並正確設置scale屬性。我想從文檔目錄加載圖像時執行同樣的操作(用NSURL指定)。我環顧四周,但找不到文檔中的任何內容,有沒有我錯過的東西?如何從具有imageNamed行爲(@ 2x,〜ipad等變體)的NSURL加載圖像

我目前正在實現這個(整個shebang,緩存等),但我討厭重複框架代碼。我希望在完成之前得到答案,但如果沒有,我會發布代碼。

+1

這可能有些用處:http://blog.mro.name/2010/11/high-res-uiimage-remote-load/ –

+0

這不會做我想要的行爲 - 即檢查哪些文件存在如果它們不存在,則回落到其他的緩存中。無論如何,我最終寫了自己的一個(代碼張貼在答案中)。 – jhabbott

回答

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: - 至少對於最常見的情況。也許有不同的圖像格式和其他修飾符的加載我不知道 - 代碼應該很容易修改以支持。

0

我認爲這應該做你的詭計,這是一個簡單的測試來檢查屏幕的規模。

UIImage *image; 
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] && [[UIScreen mainScreen] scale] == 2){ 
    // @2x 
    NSURL *imageURL = [NSURL URLWithString:@"http://www.example.com/images/[email protected]"]; 
    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]; 

已經在這裏找到答案 How should retina/normal images be handled when loading from URL?

希望它有助於

+1

謝謝Rahul,但這是一個不同的問題。閱讀imageNamed:如何工作並理解它如何緩存圖像,以及它如何查找@ 2x,〜ipad後綴,如果它們不存在,則回退到非後綴文件。然後重新閱讀我的問題,你就會明白。 :) – jhabbott

相關問題