本文翻译来自:http://www.markj.net/iphone-asynchronous-table-image/

  在开发iPho ne&iPad应用时,利用UITable从指定的URL中加载图片是经常遇到的。如果采用单线程的同步加载显然不能满足用户的体验要求,所以我们需要利用多线程的方法在应用程序后台并行的去加载图片。但是多线程编程是比较难的,你需要考虑很多线程安全方面的问题。那怎样才能在避免多线程的情况下异步加载图片了?Cocoa提供了一个精彩的设计思维:

UIView heirachy + URL loading system + delegate design = 
                        multi-threaded image loading with no multi-threaded coding!

  怎么样才能鱼和熊掌兼得了?每一个iPhone应用程序都是一个多线程程序,或者至少是会同多线程iPhone操作系统一起运行。在合适的地方利用恰当的代理方法,你可以有效的利用iPhone已经为你免费提供的多线程实现,你自己不需要编写任何的多线程代码,这样就可以避免一些多线程方面的bug。iPhone应用程序是一个很大的事件循环(如图,可参考Cocoa programming for max os X)——当事件发生时将触发你编写的类的方法。当你使用URL加载系统的异步API时,iPhone将使用不同的线程而不是当前运行应用程序的事件循环(event loop)线程来加载URL对应的内容。当数据加载完成后,将通过event loop产生回调。

根据以上描述,在开发中就可以编写如下简单代码:
connection =[ [NSURLConnection alloc]
initWithRequest: request delegate:self];

-(void) connection:(NSURLConnection *)theConnection
didReceiveData:(NSData *)incrementalData

  需要注意的是,当数据从远程服务器返回时,其他正在进行下载的iPhone线程不能在你的方法正在调用的同时调用你的对象,它是把消息放入你的应用event loop中。假如它直接调用了你的应用程序,可能恰好你的应用程序正在运行UI代码或者其他一些事情,那么你就不得不去编写线程安全的代码。所以数据到达的调用是作为一个事件存在于event loop中。event loop中的事件是运行在一个单线程中,每次执行一个事件。利用这些,我们可以从Flickr那异步的加载图片而不需要我们自己编写线程安全的代码。更好的是,Cocoa的URL加载系统将并行的加载这些URL。

  但是,我们怎么在加载完图片后更新UITableViewCell了?UIImage是不可变,也就是说,当你加载完一个图片后就不能改变图片的数据了。值得庆幸的是苹果使得这项工作变得很简单。将UIView对象放入UITableViewCell中,而不是直接放入UIImage。开始时,你的View Object可以为空,或者它可以有一个虚假的图片在里面,或者你可以展示一些“something is happening”视图。当图片数据已经加载完全,创建一个UIImageView,设置图片,然后将它放入table cell中。

  作者把这些功能封装成了一个类(AsyncImageView),具体代码如下。使用很方便,只需如下几个步骤:

  1、alloc and initWithRect

  2、add it to a view, eg in a table cell's content view;

  3、send it the loadImageFromURL: message.

@interface AsyncImageView : UIView {
NSURLConnection* connection;
NSMutableData* data;
}
@end

@implementation AsyncImageView

- (void)loadImageFromURL:(NSURL*)url {
if (connection!=nil) { [connection release]; }
if (data!=nil) { [data release]; }
NSURLRequest* request = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
connection = [[NSURLConnection alloc]
initWithRequest:request delegate:self];
//TODO error handling, what if connection is nil?
}

- (void)connection:(NSURLConnection *)theConnection
didReceiveData:(NSData *)incrementalData {
if (data==nil) {
data =
[[NSMutableData alloc] initWithCapacity:2048];
}
[data appendData:incrementalData];
}

- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {

[connection release];
connection=nil;

if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}

UIImageView* imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];

imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight );

[self addSubview:imageView];
imageView.frame = self.bounds;
[imageView setNeedsLayout];
[self setNeedsLayout];
[data release];
data=nil;
}

- (UIImage*) image {
UIImageView* iv = [[self subviews] objectAtIndex:0];
return [iv image];
}

- (void)dealloc {
[connection cancel];
[connection release];
[data release];
[super dealloc];
}

@end

  利用上面封装的一个类,可以编写一个UITableViewCell使用例子。代码如下。The AsyncImageView gets tagged with 999, and when it gets recycled, that 999 tagged view gets fished out and removed. So only the cell is being recycled, not the AsyncImageView object. When its removed from the cells content view it also gets released, causing dealloc, which in turn cancels the url download (if its outstanding).

- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"ImageCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

if (cell == nil) {
cell = [[[UITableViewCell alloc]
initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]
autorelease];
} else {
AsyncImageView* oldImage = (AsyncImageView*)
[cell.contentView viewWithTag:999];
[oldImage removeFromSuperview];
}

CGRect frame;
frame.size.width=75; frame.size.height=75;
frame.origin.x=0; frame.origin.y=0;
AsyncImageView* asyncImage = [[[AsyncImageView alloc]
initWithFrame:frame] autorelease];
asyncImage.tag = 999;
NSURL* url = [imageDownload
thumbnailURLAtIndex:indexPath.row];
[asyncImage loadImageFromURL:url];

[cell.contentView addSubview:asyncImage];

return cell;
}

转载于:https://www.cnblogs.com/guxizhi/archive/2011/06/20/2085157.html

UITables With Downloaded Images - Easy Asynchronous Code UITable 异步加载图片相关推荐

  1. 使用VS Code 使用pygame加载不出图片;Python的pygame打不开图片,怎么解决?由于图片运行报错

    首先,我开始也是打不开的,因为我是先用的Pycham转过来使用的,然后使用了VS也使用以下的代码,注意是pygame.image.load()这段程序 ''' @Description: In Use ...

  2. 【翻译】基于 Create React App路由4.0的异步组件加载(Code Splitting)

    基于 Create React App路由4.0的异步组件加载 本文章是一个额外的篇章,它可以在你的React app中,帮助加快初始的加载组件时间.当然这个操作不是完全必要的,但如果你好奇的话,请随 ...

  3. Webpack的Code Splitting实现按需加载

    一. 什么是Code Splitting? 在最开始使用Webpack的时候, 都是将所有的js文件全部打包到一个build.js文件中(文件名取决与在webpack.config.js文件中outp ...

  4. macOS下加载动态库dylib报code signature invalid错误的解决办法

    一.现象描述 在macOS上搞开发也有一段时间了,也积攒了一定的经验.然而,今天在替换工程中的一个动态库时还是碰到了一个问题.原来工程中用的是一个静态库,调试时发现有问题就把它替换成了动态库.这本来没 ...

  5. vscode安装swift插件_使用 Webpack 优化 VS Code 插件加载性能

    Webpack 这一 JS 模块打包神器相信大家都不陌生了.由于 VS Code 插件大部分也都是 JS/TS 代码 + 依赖库的形式,因此也可以使用 Webpack 打包,优化性能. 经过实测,经过 ...

  6. VsCode配置Python开发环境后运行代码会报错“无法加载文件 D:\Code\xxx\poetry-demo\.venv\Scripts\Activate.ps1”

    问题描述:在VsCode中配置Python开发环境后运行代码会报错"无法加载文件 D:\Code\xxx\poetry-demo\.venv\Scripts\Activate.ps1&quo ...

  7. VS Code加载 Web 视图时出错

    问题描述: VS Code加载 Web 视图时出错: Error: Could not register service workers: InvalidStateError: Failed to r ...

  8. WinDBG插件编写介绍及在Nano Code中加载扩展

    穷理者,因其所已知而及其所未知,因其所已达而及其所未达.人之良知,本所固有.然不能穷理者,只是足于已知已达,而不能穷其未知未达,故见得一截,又不曾见得一截,此其所以于理未精也.然仍须功夫日日增加.今日 ...

  9. UIWebView加载HTTPS站点出现NSURLErrorDomain code=-1202 SSL

    最近在做push 信息到facebook中.当使用UIWebview加载https的站点时webview总是会报NSURLErrorDomain code=-1202,导致网页加载失败.自己打印错误和 ...

  10. 关于使用UIWebView加载HTTPS站点出现NSURLErrorDomain code=-1202

    最近在做push 信息到facebook中.当使用UIWebview加载https的站点时webview总是会报NSURLErrorDomain code=-1202,导致网页加载失败.自己打印错误和 ...

最新文章

  1. [华为机试真题][2014]62.去除重复字符并排序
  2. 【Linux】一步一步学Linux——nice命令(127)
  3. springboot使用PageHelper实现分页
  4. HTML5 Audio(音频)
  5. MySQL数据库迁移到PostgreSQL
  6. java wrapper linux_Java Service Wrapper linux 服务 java 自启动
  7. [0].Net开发者社区--您好大的官威啊!
  8. 命令行linux iso,linux – 有没有办法从命令行更改.iso文件卷id?
  9. raspberry pi_构建自己的Raspberry Pi龙卷风预警系统
  10. hdu-5583 Kingdom of Black and White(数学,贪心,暴力)
  11. Java中string中hashcode_为什么String中的Java hashCode()使用31作为乘数?
  12. 零基础带你学习MySQL—not null 非空(二十四)
  13. go - json -struct
  14. android 手机关机代码非root,Android手机获取root权限并实现关机重启功能的方法
  15. 斐波那契堆 - 解析与实现
  16. 卡片游戏 基础c语言试题
  17. 局域网共享打印机教程
  18. 调用有道智云api做翻译器遇到播放音频的问题
  19. 计算机网络模拟器 mac,网易mumu模拟器mac版使用常见问题解决办法_3DM手游
  20. win7 java 开发环境搭建教程_Java开发环境配置教程(win7 64bit)

热门文章

  1. python统计图的三层结构设计代码_【Python数据可视化】用Matplotlib绘制常见统计图,中文显示字体任意设置...
  2. 计算机网络和lnternet的课件,Computer Networks and Internets《计算机网络与因特网》课件.ppt...
  3. C# Socket编程 通过线程方式的异步
  4. 设计模式----原型模式(C++实现)
  5. linux 快捷键回复禁用,Linux 禁用Ctrl+Alt+Delete重启服务器操作
  6. tp5 保存图片背景黑色_将照片背景换成黑色或白色,用snapseed手机修图软件,怎么操作?...
  7. 过滤器做权限校验以及遇到的坑
  8. JavaScript语法之语句、字面量、变量
  9. c语言的加法和平均值程序,编写求一组整数的和与平均值的程序
  10. .net mysql参数化查询,ASP.NET中的mysql参数化查询