关闭

iOS 开发中如何显示网络图片

标签: objciOS
2407人阅读 评论(0) 收藏 举报
分类:
              by Fanxiushu  2015-07-10 转载或引用请注明原作者

 iOS开发中,使用UIImageView控件来显示图片,非常简单几句话就能显示一个完整的图片:
UIImageView* img =[[UIImageView alloc] initWithFrame:frame];
[superView addSubView:img];
img.image=[UIImage imageNamed:@"picture.png"];
这是图片在本地的情况,可是如果图片文件在网络上该如何实现呢?
你可以使用 NSData* data = [NSData dataWithContentsOfURL:URL];
然后NSData数据转化到 UIImage,
但是 dataWithContentsOfURL是同步获取数据,如果图片文件太大,会阻塞主线程,造成界面假死。
当然也可以使用别人开发的库,比如 SDWebImage就能很好的下载和缓存网络图片。
可是如果花不了多少精力能自己实现这个功能,我就会尽力自己实现来满足某些项目的要求,
这样看起来简洁好维护,更重要的是通过自己实现更能掌握核心部分。
自己实现关键是要解决网络同步传输问题。
然后你也许又想到一堆别人开发的网络库,比如AFNetworking,ASIHTTPRequest等等,
其实这些都用不着,直接用苹果原生SDK API就可以了,使用他的 NSURLConnection,
至少iOS的自带的网络API,比起windows平台下的WININET要简洁不少。

设计一个 UIImageView的Category类别类,在这个类别类中增加一个方法,比如setImageWithUrl,
这个方法就是我们需要实现的从网络下载并且显示到 UIImageView控件的方法。

 要在这个方法中异步下载网络图片,并且要实时显示下载进度,因此得做个NSURLConnection代理类,管理下载进度。

 定义的接口如下:
 @interface ImageDownDelegate : NSObject
///
/////
@end
 
@interface UIImageView (URLImage)
 
@property(nonatomic,strong)ImageDownDelegate* callback;
-(void) setImageWithUrl:(NSString*)url imgName:(NSString*)imgName progress:(void(^)(int progress, NSError* error)) progress;
 
@end

 ImageDownDelegate 是负责数据下载的接口。
setImageWithUrl的progress,表示使用BLOCK函数块的方式显示下载进度。
参数imgName的意思占位图片,当网络图片正在下载的时候,
用一个本地图片来暂时代替展现。
 
ImageDownDelegate私有属性如下:
 
typedef void (^FUNC)(int progress,  NSError* error);         这个就是setImageWithUrl提供的下载进度回调函数
typedef void (^FUNC2)(NSData* data, NSError* error);     这个是完成回调函数
@interface ImageDownDelegate()
/////
@property(copy) FUNC func;
@property(copy) FUNC2 completion;
@property(nonatomic)UIImageView* imageView;   当下载完成后,设置这个图片控件的Image,让网络图片展示出来
@property(nonatomic)UIButton* imageButton;  这个是UIButton的情况下,下载完网络图片之后展示UIButton的背景。
@property(nonatomic,strong)NSMutableData* data; 这个是下载的图片数据内容,在didReceiveData 组合所有下载的数据。
@property(nonatomic) long long total_length; 图片数据的总长度,在 didReceiveResponse计算得知
@property(nonatomic) long long curr_length;当前下载的数据长度,在 didReceiveData 计算得知
 
@end
 
ImageDownDelegate 接口实现如下主要几个方法:
 
////这个方法是从网络获取 HTTP回答头信息,从这里可以知道下载的图片长度,因此记录下来,作为下载进度的依据。
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
/////真正的数据接收回调函数,在这里应该把接收到的数据组合起来,计算并且调用进度函数,通知下载进度。
 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
 
/////图片数据已经完全下载完成,在这里应该设置UIImageView的Image,这个时候,图片就可以展现出来。
 -(void)connectionDidFinishLoading:(NSURLConnection *)connection;
 
///////下载过程中出现错误,这里应该通知失败。
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
 
 
可以看到 UIImageView (URLImage) 里有个 callback属性, 但是类别类不允许有属性存在,因此采用
objc_setAssociatedObject, objc_getAssociatedObject函数来解决这个问题。
为何需要这个代理类的 callback呢?
因为假设某个UIImageView调用 setImageWithUrl下载某个网络图片,当这个网络图片正在下载过程中,
接着它又调用setImageWithUrl下载另一个网络图片,应该取消第一次的下载,这个callback就起到这个作用。
 
最后看看 setImageWithUrl的大致实现过程:
 
-(void) setImageWithUrl:(NSString*)url imgName:(NSString*)imgName progress:(void(^)(int progress, NSError* error)) progress
{
    ////
    if( self.callback){ ///如果之前有正在下载的数据,则需要移除,否则遇到重新请求网络图片的UIImageView可能出现混乱
        ////这里应该真正取消前一次的图片下载,但是我使用 NSURLProtocol协议缓存数据,所以这里让他继续后台下载并且缓存起来。
        self.callback.imageButton = nil;
        self.callback.imageView = nil;
        ////
     //   NSLog(@"######***** CCOOOOOOOO ");
    }
   
    ///////这里我使用 NSURLProtocol 协议来缓存所有图片数据,这里的意思先判断缓存是否存在这个URL定位的图片,
          如果存在则从缓存获取图片直接显示。
         
    NSString* path = [SimpleURLProtocolCache getCacheFile:url];
    if(path){
        self.image = [UIImage imageWithContentsOfFile:path];
        ////
        return ; //////
    }
    ///////是否显示占位图
    if( imgName ){
        ////
        self.image = [UIImage imageNamed:imgName]; ////
       
        ///////
    }
   
    ////
    NSMutableURLRequest* newRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]
                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                          timeoutInterval:10.0];
   
    ///////
    ImageDownDelegate* cbk = [[ImageDownDelegate alloc] init];
   
    cbk.func = progress;
    cbk.completion = nil;
    cbk.imageView = self;
    cbk.imageButton = nil;
   
   
    self.callback = cbk;  /////////
   
    ////
    if(progress){
        ////
        progress(0, nil); ///
    }
    设置代理,开始图片的真正下载,下载后会同时被 NSURLProtocol 协议缓存。
    NSURLConnection* conn = [NSURLConnection connectionWithRequest:newRequest delegate:cbk];
   
    [conn start];
    ///////
   
}
 图片缓存,我使用扩展 NSURLProtocol协议来缓存所有 NSURL的数据,
你也可以自己实现缓存来缓存图片,相信自己实现这个缓存也不复杂的。


这个接口对应的资源下载地址:

http://download.csdn.net/detail/fanxiushu/8886897



0
0
查看评论

ios通过URL获取网络图片的原始大小

//需要用到第三方库SDWebImage UIImageView *v1 = [[UIImageView alloc]init];         [self.view addSubview:v1];        ...
  • sharmir
  • sharmir
  • 2016-04-22 14:16
  • 9011

iOS NSURL来请求图片(delegate 和block两种方法)

截图: 码 一.异步连接(delegate)    //    1.设置请求路径     NSURL *url = [NSURL URLWithString:requestPNGUrl];     // ...
  • robinson_911
  • robinson_911
  • 2016-09-16 12:18
  • 664

iOS UIImageView显示网络图片的基础用法

先解释下以下代码中的变量: picsURL是一个存储URL地址的数组 choice是选择图片的索引数 self.imageView是View中的UIImageView 其实显示一幅网络上的图片十分简单,如下2行代码即可。 1 2 UIImage *image = [UIIma...
  • zhaopenghhhhhh
  • zhaopenghhhhhh
  • 2013-09-25 08:24
  • 28173

SDWebImage加载图片URL第一次失败,后面图片URL存在不刷新的问题

业务需求,有时候会首先出现图片的网络URL地址,但是并没有显示出来,使用SDWebImage显示图片如下 self.itemImageView sd_setImageWithURL:]; 但是发现,后面有图片了,再去刷新,无论如何也刷新不出来这图片。 最后发现SDWebImag...
  • elsonpeng
  • elsonpeng
  • 2016-12-21 17:27
  • 1467

SDWebImage 加载网络图片不能显示

iOS9让所有的HTTP默认使用了HTTPS,原来的HTTP协议传输都改成TLS1.2协议进行传输。直接造成的情况就是App发请求的时候弹出网络无法连接。解决办法就是在项目的info.plist 文件里加上如下节点: 在info.plist文件中加入此节点就可以加载出网...
  • zhaojinqiang12
  • zhaojinqiang12
  • 2016-11-15 16:32
  • 1270

IOS SDWebImage内部实现原理

想必大家都很熟悉SDWebImage了,项目中也经常用。可大家知道它的实现原理吗?今天就跟大家分享一下。 先看一下下面这幅图: 图片解释:内存层面的相当是个缓存器,以Key-Value的形式存储图片。当内存不够的时候会清除所有缓存图片。用搜索文件系统的方式做管理,文件替换方式是以时间为单位,剔除...
  • gsg8709
  • gsg8709
  • 2018-01-10 14:12
  • 88

IOS中UIImageView使用网络图片

考虑到UI线程阻塞。使用_operationQueue。 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downloadImage) object:...
  • howlaa
  • howlaa
  • 2016-04-28 17:10
  • 469

ios 加载本地HTML文件,图片不显示的问题

第一种方式导入HTML文件的时候,要用这种方法:    NSString *path = [[NSBundle mainBundle] pathForResource:@"文件名" ofType:@"html"]; ...
  • wangqiuwei07
  • wangqiuwei07
  • 2017-04-25 17:05
  • 551

iOS 控件加载图片不显示的原因--多么痛的领悟

在编辑项目代码的过程中曾多次出现加载图片不显示的情况,有按钮上的,也有imageView上的,当时稀里糊涂的换了图片就可以了,还以为是图片本身的格式问题,现在终于抓到元凶了。 在Xcode中的Images.xcassets部分添加项目中需要的图片,一般是从外部直接拖拽的,有时候为了代码的可读性,会...
  • r614288863
  • r614288863
  • 2014-12-25 10:48
  • 1335

UIButton 获取网络图片的排版技巧

最近在做 UI 的时候,遇到一排 button 需要通过后端来控制它的 image 和 title。但由于 Android 和 iOS 对图片要求的尺寸有差异,因此通过后端开控制图片大小比较麻烦。
  • u013749108
  • u013749108
  • 2017-09-10 15:18
  • 273
    个人资料
    • 访问:146429次
    • 积分:2127
    • 等级:
    • 排名:千里之外
    • 原创:55篇
    • 转载:0篇
    • 译文:0篇
    • 评论:315条
    文章分类
    最新评论