CNLiveWebImageDownloadOperation.m 5.46 KB
//
//  CNLiveWebImageDownloadOperation.m
//  WSWebImageDemo
//
//  Created by 王帅 on 16/7/25.
//  Copyright © 2016年 王帅. All rights reserved.
//

#import "CNLiveWebImageDownloadOperation.h"
#import "CNLiveWebImageOperation.h"
#import <ImageIO/ImageIO.h>
#import "UIImage+MultiFormat.h"

#define CNLiveWebImageBackgroundSessionIdentifier @"CNLiveWebImageBackgroundSessionIdentifier"

@interface CNLiveWebImageDownloadOperation ()<CNLiveWebImageOperation, NSURLSessionDataDelegate, NSURLSessionTaskDelegate, NSURLSessionDelegate>

@property (nonatomic, copy) CNLiveDownloadProgressBlock progressBlock;
@property (nonatomic, copy) CNLiveDownloadCompletedBlock completedBlock;
@property (nonatomic, assign) CNLiveWebImageDownloadOptions options;
@property (nonatomic, strong) NSURL *url;

@property (nonatomic, strong) NSURLSessionConfiguration *config;
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSURLSessionDataTask *dataTask;
@property (nonatomic, assign) NSInteger expectedSize;
@property (nonatomic, strong) NSMutableData *imageData;
@property (nonatomic, strong) NSURLResponse *response;

@end

@implementation CNLiveWebImageDownloadOperation

- (id)initWithURL:(NSURL *)url options:(CNLiveWebImageDownloadOptions)options progress:(CNLiveDownloadProgressBlock)progress completed:(CNLiveDownloadCompletedBlock)completed
{
    if ((self = [super init])) {
        _url = url;
        _progressBlock = progress;
        _completedBlock = completed;
        _options = options;
    }
    return self;
}

- (void)start
{
    @synchronized (self) {
        if (self.isCancelled) {
            return;
        }
    }
    self.dataTask = [self.session dataTaskWithURL:self.url];
    [self.dataTask resume];
    [self.session finishTasksAndInvalidate];
}

- (NSURLSessionConfiguration *)config
{
    if (!_config) {
        if (self.options & CNLiveWebImageDownloadContinueInBackground) {
            _config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:CNLiveWebImageBackgroundSessionIdentifier];
        }
        else {
            _config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
        }
    }
    return _config;
}

- (NSURLSession *)session
{
    if (!_session) {
        _session = [NSURLSession sessionWithConfiguration:self.config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    }
    return _session;
}

#pragma mark <NSURLSessionDataDelegate>
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
    if (![response respondsToSelector:@selector(statusCode)] || ([((NSHTTPURLResponse *)response) statusCode] < 400 && [((NSHTTPURLResponse *)response) statusCode] != 304)) {
        NSInteger expected = response.expectedContentLength > 0 ? (NSInteger)response.expectedContentLength : 0;
        self.expectedSize = expected;
        if (self.progressBlock) {
            self.progressBlock(0, expected);
        }
        
        self.imageData = [[NSMutableData alloc] initWithCapacity:expected];
        self.response = response;
        completionHandler(NSURLSessionResponseAllow);
    }
    else {
        
        [self.dataTask cancel];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.completedBlock) {
                self.completedBlock(nil, nil, [NSError errorWithDomain:NSURLErrorDomain code:[((NSHTTPURLResponse *)response) statusCode] userInfo:nil], YES);
            }
        });
    }
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    [self.imageData appendData:data];
    if (self.options & CNLiveWebImageDownloadProgressiveDownload && self.completedBlock) {
        const NSInteger totalSize = self.imageData.length;
        CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)self.imageData, NULL);
        if (totalSize < self.expectedSize) {
            CGImageRef partialImageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
            if (partialImageRef) {
                UIImage *image = [UIImage imageWithCGImage:partialImageRef];
                CGImageRelease(partialImageRef);
                dispatch_async(dispatch_get_main_queue(), ^{
                    if (self.completedBlock) {
                        self.completedBlock(image, self.imageData, nil, NO);
                    }
                });
            }
        }
        
        CFRelease(imageSource);
    }
    
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.progressBlock) {
            self.progressBlock(self.imageData.length, self.expectedSize);
        }
    });
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    if (error) {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.completedBlock) {
                self.completedBlock(nil, nil, error, NO);
            }
        });
    }
    else {
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.completedBlock) {
                self.completedBlock([UIImage ws_imageWithData:self.imageData], self.imageData, nil, YES);
            }
        });
    }
}

- (void)cancel
{
    if (self.session) {
        [self.session invalidateAndCancel];
    }
    self.completedBlock = nil;
    self.progressBlock = nil;
    self.session = nil;
    self.imageData = nil;
}














@end