iOS网络相关iOS学习开发iOS学习笔记

分析NSURLProtocol是如何自定义的?如何使用的?

2016-04-29  本文已影响485人  刘书亚的天堂之路

PRHTTPURLProtocol.h文件

#import <Foundation/Foundation.h>

//继承自NSURLProtocol
@interface PRHTTPURLProtocol : NSURLProtocol

@end

PRHTTPURLProtocol.m文件

#import "PRHTTPURLProtocol.h"
#import "PRCachedURLResponse.h"

//自定义唯一标示符
static NSString *const PRHTTPURLProtocolHandledKey = @"PRHTTPURLProtocolHandledKey"; 

@interface PRHTTPURLProtocol ()

@property (nonatomic, strong) NSURLConnection *connection;//网络连接对象
@property (nonatomic, strong) NSMutableData *data;//网络请求返回数据
@property (nonatomic, strong) NSURLResponse *response;//网络返回封装对象(包含,数据,格式,请求链接等等)

@end

@implementation PRHTTPURLProtocol

//说白了这个函数是用来过滤网络请求的协议的,即满足我设置的协议就给你返回yes,允许你进行网络通信,一旦返回no后续的网络请求将不会被继续执行
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    //如果是非http https就不让他通过
    if (![request.URL.scheme isEqualToString:@"http"] && ![request.URL.scheme isEqualToString:@"https"]) {
        return NO;
    }
    
    //看看是否已经处理过了,防止无限循环,如果已经处理过(即设置了允许通过,就不再初始化了)
    if ([NSURLProtocol propertyForKey:PRHTTPURLProtocolHandledKey inRequest:request]) {
        return NO;
    }
    
    return YES;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
    return request;
}

- (void)startLoading
{
    //如果有缓存,就直接返回缓存的结果
    NSString *cacheKey = self.request.URL.absoluteString;
    PRCachedURLResponse *cachedResponse = [[CWObjectCache sharedCache] objectForKey:cacheKey];
    if (cachedResponse && cachedResponse.response && cachedResponse.data) {
        NSURLResponse *response = cachedResponse.response;
        NSData *data = cachedResponse.data;
        
        [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
        [self.client URLProtocol:self didLoadData:data];
        [self.client URLProtocolDidFinishLoading:self];
        return;
    }
    
   //没有缓存 返回这个新的请求
    NSMutableURLRequest *newRequest = [self.request mutableCopy];
    [newRequest setTimeoutInterval:15];
    //打标签,防止无限循环
    [NSURLProtocol setProperty:@YES forKey:PRHTTPURLProtocolHandledKey inRequest:newRequest];
    self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}

- (void)stopLoading
{
    [self.connection cancel];
}

#pragma mark - NSURLConnection delegate

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    
    // cache image only
    NSString *MIMEType = [response.MIMEType lowercaseString];
    if (![MIMEType hasPrefix:@"image"]) {
        return;
    }
    
    //保存网络获取的数据和数据对象
    self.data = [[NSMutableData alloc] init];
    self.response = response;
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [[self client] URLProtocol:self didLoadData:data];
    
    //累加数据
    [self.data appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [[self client] URLProtocol:self didFailWithError:error];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [[self client] URLProtocolDidFinishLoading:self];
    
    if (!self.response || [self.data length] == 0) {
        return;
    }
        
    //缓存对应url的数据和数据对象(序列化)
    PRCachedURLResponse *cache = [[PRCachedURLResponse alloc] init];
    cache.response = self.response;
    cache.data = self.data;
    [[CWObjectCache sharedCache] storeObject:cache forKey:[[self.request URL] absoluteString]];
}

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response
{
    if (response) {
        // simply consider redirect as an error
        NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorResourceUnavailable userInfo:nil];
        [[self client] URLProtocol:self didFailWithError:error];
    }
    return request;
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    [[self client] URLProtocol:self didReceiveAuthenticationChallenge:challenge];
}

- (void)connection:(NSURLConnection *)connection didCancelAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    [[self client] URLProtocol:self didCancelAuthenticationChallenge:challenge];
}

@end

上一篇下一篇

猜你喜欢

热点阅读