好久没写下技术文档了,被感情问题困扰了,我们程序员找个女朋友咋就这么难呢,哎,不说了,说多了都是泪。还是进入正题吧。
要做到标题说的那种效果,需要用到Image I/O,有兴趣的可以先看看官方文档慢慢阅读,其实不难理解,这个主题只会用到其中一些功能。
主要是我们项目的app中需要加入广告页面,也就是我常常使用其他app时,打开的时候都会有个几秒种的广告,有个跳过按钮。图片是从后台下载的,包括GIF动态图和静态图。然后再扩展说说大图片缓慢加载,局部显示的做法。(ps:这里都适用iOS原生,不使用第三方)
这是demo源码地址:demo源码地址:https://github.com/cocoaliaolei/ImageDown
第一部分:GIF动图加载(当然如果图片不是gif图片照样可以加载。)
首先是图片下载,我们可以直接使用下面这个方法来下载图片
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
当然要放在线程中区,下载完成后做,数据缓存(简单的本地存储)和数据处理
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
/**
*缓存
*/
if (self.isNeedCache) {
[LLimageCache cacheImageData:imgData withPath:[NSURL URLWithString:url]];
}
/**
* 回到主线程处理
*/
dispatch_async(dispatch_get_main_queue(), ^{
[self gifImageHandle:imgData withUrl:url];
});
});
这里主要是讲使用Image I/O来处理数据
首先是创建 Image Sources包含不止一个图像,缩略图,各个图像的特征和图片文件。
CGImageSourceRef myImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imgData,NULL);
Image Sources中可能是多张图片,可以通过CGImageSourceGetCount来获得图片在Image Sources中的数量
size_t count = CGImageSourceGetCount(myImageSource);
判断count,如果count >1则是多张动态图,反之则是一张静态图.
静态图简单处理就好,如下
CGImageRef imgRef = CGImageSourceCreateImageAtIndex(myImageSource, 0, NULL);
UIImage *img = [UIImage imageWithCGImage:imgRef];
Image Sources包含了每一张的图片信息,大小以及播放时间
所以我们需要获取每一张图片的时间
/**
* 获取每一张图片的时间
*/
-(CGFloat)getIndexImageDuration:(CGImageSourceRef)myImageSource index:(size_t)i{
CGFloat indexDuration = 0.1f;
CFDictionaryRef cfProperties = CGImageSourceCopyPropertiesAtIndex(myImageSource, i, NULL);
NSDictionary *timesDic = (__bridge NSDictionary *)cfProperties;
NSDictionary *gifProperties = timesDic[(NSString *)kCGImagePropertyGIFDictionary];
NSNumber *UnclampedDelayTime = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
if (UnclampedDelayTime) {
indexDuration = UnclampedDelayTime.floatValue;
}
else{
NSNumber *DelayTime = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
if (DelayTime) {
indexDuration = DelayTime.floatValue;
}
}
if (indexDuration < 0.01f) indexDuration = 0.1f;
CFRelease(cfProperties);
return indexDuration;
}
再将图片组装起来
/**
* 将图片集成gif图片
*
*/
-(UIImage *)getCombineImages:(CGImageSourceRef)myImageSource index:(size_t)count{
NSMutableArray *aray = [[NSMutableArray alloc]init];
CGFloat Durations = 0.0f;
for (size_t i = 0; i < count; i ++) {
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(myImageSource, i, NULL);
[aray addObject:[UIImage imageWithCGImage:imageRef]];
Durations += [self getIndexImageDuration:myImageSource index:i];
/**
* 创建了CGImageRef实例就要release,不然内存爆炸
*/
CGImageRelease(imageRef);
}
if (Durations == 0.0f) Durations = 0.1f * count;
UIImage *img = [UIImage animatedImageWithImages:aray duration:Durations];
return img;
}
最后将返回的img给imageview显示就可以了。
第二部分:单张静态图的缓慢加载,即一部分一部分的显示
网络请求我们选用NSURLSession,不用connection,苹果好像要弃用她而推NSURLSession,不过用哪个都一样。
-(void)singleRequestWith:(NSString *)url{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *sesson = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSURLSessionDataTask *task = [sesson dataTaskWithRequest:request];
[task resume];
}
在代理中获取相关数据
#pragma mark - NSURLSessionDataDelegate
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
NSLog(@"%@", NSStringFromSelector(_cmd));
self.expectedLeght = response.expectedContentLength;
NSLog(@"---expectedLeght:%lld",self.expectedLeght);
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
[self.imgData appendData:data];
[self.TempImgData appendData:data];
if (self.imgData.length == self.expectedLeght) self.isDownloadFinished = YES;
/**
* 50这个值的设置是根据每次didReceiveData的数据长度估算的一个值
* 这里不能每次接收到数据就将其转换为图片,这样对cpu消耗太大,容易引起崩溃
*/
if (self.TempImgData.length > self.expectedLeght/50 || self.expectedLeght == self.imgData.length) {
self.TempImgData = nil;
UIImage *img = [self creatImageWithData];
if (self.isNeedCache && self.expectedLeght == self.imgData.length) {
[LLimageCache cacheImageData:self.imgData withPath:dataTask.response.URL];
}
[self returnImageWith:img];
}
}
下载完成释放session
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
if (error) NSLog(@"下载出错!!!---%@",error);
/**
* 释放session,防止内存泄漏
*/
[session finishTasksAndInvalidate];
}
得到数据后回调,block或代理
/**
*回调
*/
-(void)returnImageWith:(UIImage *)img{
if (self.block) self.block(img);
else if (self.delegate){
if ([_delegate respondsToSelector:@selector(LLImageLoadBitDiddidReceiveGetImages:)]) {
[_delegate LLImageLoadBitDiddidReceiveGetImages:img];
}
}
}