![](/img/trans.png)
[英]How to load image asynchronously using UIImageView+AFNetworking in ios
[英]How to asynchronously load an image in an UIImageView?
我有一個帶有 UIImageView 子視圖的 UIView。 我需要在不阻塞 UI 的情況下在 UIImageView 中加載圖像。 阻塞調用似乎是: UIImage imageNamed:
。 這是我認為解決此問題的方法:
-(void)updateImageViewContent {
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
dispatch_sync(dispatch_get_main_queue(), ^{
[[self imageView] setImage:img];
});
});
}
圖像很小(150x100)。
但是,加載圖像時 UI 仍然被阻止。 我錯過了什么?
這是一個展示此行為的小代碼示例:
基於 UIImageView 創建一個新類,將其用戶交互設置為 YES,在 UIView 中添加兩個實例,並實現其 touchesBegan 方法,如下所示:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (self.tag == 1) {
self.backgroundColor= [UIColor redColor];
}
else {
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
});
[UIView animateWithDuration:0.25 animations:
^(){[self setFrame:CGRectInset(self.frame, 50, 50)];}];
}
}
將標簽 1 分配給這些 imageView 之一。
當您從加載圖像的視圖開始幾乎同時點擊兩個視圖時,究竟會發生什么? UI 是否因為等待[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
返回 ? 如果是這樣,我該如何異步執行此操作?
使用長按然后拖動以在黑色方塊周圍繪制一個矩形。 據我了解他的回答,理論上白色選擇矩形不應該在第一次加載圖像時被阻止,但實際上是這樣。
項目中包含兩張圖片(一張小的:woodenTile.jpg,一張大的:bois.jpg)。 結果與兩者相同。
我真的不明白這與我在第一次加載圖像時仍然遇到的 UI 被阻塞的問題有什么關系,但是 PNG 圖像在不阻塞 UI 的情況下解碼,而 JPG 圖像確實阻塞了 UI。
UI的阻塞從這里開始..
.. 到此結束。
NSURL * url = [ [NSBundle mainBundle]URLForResource:@"bois" withExtension:@"jpg"];
NSURLRequest * request = [NSURLRequest requestWithURL:url];
[self.imageView setImageWithURLRequest:request
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
NSLog(@"success: %@", NSStringFromCGSize([image size]));
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
NSLog(@"failure: %@", response);
}];
// this code works. Used to test that url is valid. But it's blocking the UI as expected.
if (false)
if (url) {
[self.imageView setImage: [UIImage imageWithData:[NSData dataWithContentsOfURL:url]]]; }
大多數時候,它會記錄: success: {512, 512}
它還偶爾記錄: success: {0, 0}
有時: failure: <NSURLResponse: 0x146c0000> { URL: file:///var/mobile/Appl...
但圖像從未改變。
問題是UIImage
實際上並沒有讀取和解碼圖像,直到它第一次實際使用/繪制。 要在后台線程上強制執行此工作,您必須在執行主線程-setImage:
之前在后台線程上使用/繪制圖像-setImage:
。 這對我有用:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
// Make a trivial (1x1) graphics context, and draw the image into it
UIGraphicsBeginImageContext(CGSizeMake(1,1));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, 1, 1), [img CGImage]);
UIGraphicsEndImageContext();
// Now the image will have been loaded and decoded and is ready to rock for the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
[[self imageView] setImage: img];
});
});
編輯:用戶界面沒有阻止。 您已經專門設置它以使用UILongPressGestureRecognizer
,默認情況下,在執行任何操作之前等待半秒鍾。 主線程仍在處理事件,但在GR超時之前不會發生任何事情。 如果你這樣做:
longpress.minimumPressDuration = 0.01;
......你會注意到它變得更加快捷。 這里的圖像加載不是問題。
編輯2:我看過代碼,發布到github,在iPad 2上運行,我根本沒有得到你描述的打嗝。 事實上,它非常順利。 以下是在CoreAnimation工具中運行代碼的屏幕截圖:
正如您在頂部圖表中看到的那樣,FPS最高可達~60FPS並在整個手勢中保持不變。 在底部的圖表中,您可以看到大約16s的blip,這是圖像首次加載的位置,但您可以看到幀速率沒有下降。 僅從視覺檢查,我看到選擇層相交,並且在第一個交叉點和圖像外觀之間存在一個小但可觀察到的延遲。 據我所知,后台加載代碼正在按預期執行。
我希望我能幫助你更多,但我只是沒有看到問題。
您可以使用AFNetworking庫,通過導入類別
“UIImageView + AFNetworking.m”並使用如下方法:
[YourImageView setImageWithURL:[NSURL URLWithString:@"http://image_to_download_from_serrver.jpg"]
placeholderImage:[UIImage imageNamed:@"static_local_image.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
//ON success perform
}
failure:NULL];
希望這可以幫助 。
我的應用程序有一個非常類似的問題,我必須下載大量圖像,並且我的UI不斷更新。 以下是解決我的問題的簡單教程鏈接:
這是好方法:
-(void)updateImageViewContent {
dispatch_async(dispatch_get_main_queue(), ^{
UIImage * img = [UIImage imageNamed:@"background.jpg"];
[[self imageView] setImage:img];
});
}
為什么不使用像AsyncImageView這樣的第三方庫? 使用它,您所要做的就是聲明您的AsyncImageView對象並傳遞您要加載的url或圖像。 在圖像加載期間將顯示活動指示器,並且不會阻止UI。
- (void)touchesBegan:在主線程中調用。 通過調用dispatch_async(dispatch_get_main_queue),您只需將塊放入隊列中。 當隊列准備好時(即系統結束並處理您的觸摸),此塊將由GCD處理。 這就是為什么你不能看到你的woodenTile被加載並分配給self.image,直到你釋放你的手指並讓GCD處理所有在主隊列中排隊的塊。
更換:
dispatch_async(dispatch_get_main_queue(), ^{
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
});
通過:
[self setImage:[UIImage imageNamed:@"woodenTile.jpg"]];
應該解決你的問題...至少對於展示它的代碼。
考慮使用SDWebImage :它不僅可以在后台下載和緩存圖像,還可以加載和渲染它。
我已經在tableview中使用了它,結果很好,即使在下載之后也有很慢的加載速度。
https://github.com/nicklockwood/FXImageView
這是一個可以處理后台加載的圖像視圖。
用法
FXImageView *imageView = [[FXImageView alloc] initWithFrame:CGRectMake(0, 0, 100.0f, 150.0f)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.asynchronous = YES;
//show placeholder
imageView.processedImage = [UIImage imageNamed:@"placeholder.png"];
//set image with URL. FXImageView will then download and process the image
[imageView setImageWithContentsOfURL:url];
要獲取文件的URL,您可能會發現以下內容:
在應用程序中使用AFNetwork時,您無需使用任何塊來加載映像,因為AFNetwork為其提供了解決方案。 如下:
#import "UIImageView+AFNetworking.h"
和
Use **setImageWithURL** function of AFNetwork....
謝謝
我實現它的一種方法是以下:(雖然我不知道它是否是最好的一個)
首先,我使用串行異步或並行隊列創建隊列
queue = dispatch_queue_create("com.myapp.imageProcessingQueue", DISPATCH_QUEUE_SERIAL);**
or
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);
**
您可能會發現哪種更適合您的需求。
然后:
dispatch_async( queue, ^{
// Load UImage from URL
// by using ImageWithContentsOfUrl or
UIImage *imagename = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
// Then to set the image it must be done on the main thread
dispatch_sync( dispatch_get_main_queue(), ^{
[page_cover setImage: imagename];
imagename = nil;
});
});
iOS 15 中的UIImage
引入了一組方法,用於在后台線程上異步解碼圖像和創建縮略圖
func prepareForDisplay(completionHandler: (UIImage?) -> Void)
異步解碼圖像並提供新圖像以在視圖和動畫中顯示。
func prepareThumbnail(of: CGSize, completionHandler: (UIImage?) -> Void)
在后台線程上異步創建指定大小的縮略圖。
如果您需要更多地控制您希望解碼發生的位置,例如特定隊列,您還可以使用一組類似的同步API:
func prepareForDisplay() -> UIImage?
func 准備Thumbnail(of: CGSize) -> UIImage?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.