2012-08-23 40 views
2

我需要將圖像從NSDocumentDirectory讀取到多個uiimageview異步,因此它不會阻止用戶界面。 我知道我可以在後臺使用執行選擇器來加載一個uiimage,但是我怎樣才能將它與動態uiimageview相關聯?來自異步文檔的圖像

回答

4

一個方便的方法是使用塊,這樣的:

[self loadFullImageAt:imagePath completion:^(UIIMage * image){ 
    self.imageView.image = image; 
}]; 

你想要在加載圖像數據(因爲UIImage否則加載圖像數據的延遲 - 當你第一次訪問它)。在仍然處於後臺線程中的情況下解壓縮圖像也是一個好主意,所以當我們第一次使用圖像時,主線程不需要這樣做。

- (void)loadFullImageAt:(NSString *)imageFilePath completion:(MBLoaderCompletion)completion { 
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ 
     NSData *imageData = [NSData dataWithContentsOfFile:imageFilePath]; 
     UIImage *image = nil; 
     if (imageData) { 
      image = [[[UIImage alloc] initWithData:imageData] decodedImage]; 
     } 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      completion(image); 
     }); 
    }); 
} 

回調被定義爲:

typedef void (^MBLoaderCompletion)(UIImage *image); 

下面是一個UIImage類別實現該解壓縮的代碼:

的UIImage + Decode.h

#import <UIKit/UIKit.h> 


@interface UIImage (Decode) 

- (UIImage *)decodedImage; 

@end 

的UIImage +十二月ode.m

#import "UIImage+Decode.h" 


@implementation UIImage (Decode) 

- (UIImage *)decodedImage { 
    CGImageRef imageRef = self.CGImage; 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef context = CGBitmapContextCreate(NULL, 
               CGImageGetWidth(imageRef), 
               CGImageGetHeight(imageRef), 
               8, 
               // Just always return width * 4 will be enough 
               CGImageGetWidth(imageRef) * 4, 
               // System only supports RGB, set explicitly 
               colorSpace, 
               // Makes system don't need to do extra conversion when displayed. 
               kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little); 
    CGColorSpaceRelease(colorSpace); 
    if (!context) return nil; 

    CGRect rect = (CGRect){CGPointZero,{CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)}}; 
    CGContextDrawImage(context, rect, imageRef); 
    CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 

    UIImage *decompressedImage = [[UIImage alloc] initWithCGImage:decompressedImageRef scale:self.scale orientation:self.imageOrientation]; 
    CGImageRelease(decompressedImageRef); 
    return decompressedImage; 
} 

@end 

此處提供的樣本代碼假設我們使用ARC

+0

真棒回答。謝謝! –

+0

這是一個很好的答案。我們可以修改它以添加取消機制 –

1

你可以使用NSThread/dispatch隊列來創建線程,這些線程可以創建你的UIImageView -s並在其中加載圖像。

2

當你說「動態」的UIImageView,這些在UIScrollView上以編程方式創建?在UITableView? samfisher在基本問題上是完全正確的,但是細節有所不同,這取決於你創建UIImageView的方式(例如,如果UITableView,你需要確保單元格仍然可見並且沒有出列;如果是UIScrollView,如果圖像在屏幕上仍然可見(尤其是如果圖像很大或很多)),則可能只想加載UIImageView。

但基本的想法是,你可以這樣做:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 

    UIImage *image = [self getTheImage]; 

    // ok, now that you have the image, dispatch the update of the UI back to the main queue 

    dispatch_async(dispatch_get_main_queue(), ^{ 

     // if the image view is still visible, update it 

    }); 

}); 

請注意,您調用的一些背景隊列或線圖像的檢索,但要確保更新UI回主線!

如果您要更新滾動視圖,則可能需要檢查視圖是否仍然可見,如預計的herehere。如果你正在更新一個tableview,可能像this這樣的東西檢查單元格是否仍然可見。這一切都取決於你想要做什麼。