2017-01-05 24 views
7

Tôi có tùy chỉnh NSURLProtocol ("UrlProtocol") được viết để chặn yêu cầu từ UIWebView khi điều hướng đến các trang web cụ thể và áp dụng tiêu đề HTTP bổ sung trước khi được gửi. Tôi đã theo dõi https://www.raywenderlich.com/59982/nsurlprotocol-tutorial cho một lớp học đang hoạt động. Vấn đề của tôi đi kèm với việc chuyển đổi từ việc không được chấp nhận NSURLConnection thành NSURLSession: Tôi đã thử nghiệm trang html một tệp cực kỳ đơn giản, đã tải thành công. Tuy nhiên, các trang web phức tạp hơn một chút với các tài nguyên như tệp js, hình ảnh, v.v. sẽ hết thời gian chờ, trong khi sử dụng NSURLConnection toàn bộ trang web sẽ tải trong vòng vài giây.Tuỳ chỉnh NSURLProtocol chậm hơn sau khi chuyển NSURLConnection sang NSURLSession

Tôi sẽ dán UrlProtocol gốc bằng cách sử dụng NSURLConnection, sau đó là lớp mới sử dụng NSURLSession. Bản gốc:

#import "UrlProtocol.h" 
#import "Globals.h" 

@implementation UrlProtocol 

+ (BOOL)canInitWithRequest:(NSURLRequest *)request { 
    if (![request.URL.absoluteString hasPrefix:@"http"]) return NO; //No need to intercept non-http requests 

    if ([NSURLProtocol propertyForKey:@"handled" inRequest:request]) { 
     return NO; 
    } 

    return YES; 
} 

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 
    NSString* key = @"custom-auth-header"; 
    Globals* globals = [Globals getInstance]; 
    NSString* token = [globals token]; 

    NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified 
    [newRequest setValue:token forHTTPHeaderField:key]; 

    return [newRequest copy]; //return a non-mutable copy 
} 

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b { 
    return [super requestIsCacheEquivalent:a toRequest:b]; 
} 

- (void)startLoading { 
    NSMutableURLRequest *newRequest = [self.request mutableCopy]; 
    [NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest]; 

    self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self]; 
} 

- (void)stopLoading { 
    NSLog(@"stopLoading"); 
    [self.connection cancel]; 
    self.connection = nil; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    [self.client URLProtocol:self didLoadData:data]; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 
    [self.client URLProtocolDidFinishLoading:self]; 
} 

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

@end 

mới UrlProtocol sử dụng NSURLSessionDataTasks cho mọi yêu cầu:

#import "UrlProtocol.h" 
#import "Globals.h" 

@implementation UrlProtocol 

+ (BOOL)canInitWithRequest:(NSURLRequest * _Nonnull) request { 
    if (![request.URL.absoluteString hasPrefix:@"http"]) return NO; //No need to intercept non-http requests 

    if ([NSURLProtocol propertyForKey:@"handled" inRequest:request]) { 
     return NO; 
    } 

    return YES; 
} 

+ (NSURLRequest * _Nonnull)canonicalRequestForRequest:(NSURLRequest * _Nonnull)request { 
    NSString* key = @"custom-auth-header"; 
    Globals* globals = [Globals getInstance]; 
    NSString* token = [globals token]; 

    NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified 
    [newRequest setValue:token forHTTPHeaderField:key]; 
    return [newRequest copy]; //return a non-mutable copy 
} 

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest * _Nonnull)a toRequest:(NSURLRequest * _Nonnull)b { 
    return [super requestIsCacheEquivalent:a toRequest:b]; 
} 

- (void)startLoading { 
    NSMutableURLRequest *newRequest = [self.request mutableCopy]; 
    [NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest]; 
    [Globals setUrlSessionDelegate:self]; 
    Globals* globals = [Globals getInstance]; 
    self.dataTask = [globals.session dataTaskWithRequest:newRequest]; 
    [self.dataTask resume]; 
} 

- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveData:(NSData * _Nullable)data{ 
    [self.client URLProtocol:self didLoadData:data]; 
} 

- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveResponse:(NSURLResponse * _Nullable)response 
       completionHandler:(void (^ _Nullable)(NSURLSessionResponseDisposition))completionHandler{ 
    [self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; 
    completionHandler(NSURLSessionResponseAllow); 
} 

- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task didCompleteWithError:(NSError * _Nullable)error{ 
    if (error){ 
     [self.client URLProtocol:self didFailWithError:error]; 
    } else { 
     [self.client URLProtocolDidFinishLoading:self]; 
    } 
} 

- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task willPerformHTTPRedirection:(NSHTTPURLResponse * _Nonnull)response 
         newRequest:(NSURLRequest * _Nonnull)request completionHandler:(void (^ _Nonnull)(NSURLRequest * _Nullable))completionHandler { 
    completionHandler(request); 
} 

- (void)stopLoading { 
    [self.dataTask cancel]; 
    self.dataTask = nil; 
} 

@end 

"Globals" là một singleton nơi tôi đã khởi tạo một NSURLSession nghĩa là để được sử dụng trong suốt thời gian chạy của ứng dụng. Nó cũng chứa token tôi thiết lập như là một tiêu đề HTTP tùy chỉnh cho tất cả các yêu cầu:

#import "Globals.h" 
#import "UrlProtocol.h" 

@implementation Globals 
@synthesize token; 
@synthesize session; 

static Globals *instance = nil; 

+(Globals*) getInstance 
{ 
    @synchronized(self) 
    { 
     if (instance == nil) 
     { 
      instance = [Globals new]; 
     } 
    } 
    return instance; 
} 

//UrlProtocol class has no init method, so the NSURLSession delegate is being set on url load. We will ensure only one NSURLSession is created. 
+(void) setUrlSessionDelegate:(UrlProtocol*) urlProtocol{ 
    Globals* globals = [Globals getInstance]; 
    if (!globals.session){ 
     globals.session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration delegate:urlProtocol delegateQueue:nil]; 
    } 
} 

@end 

Trả lời

4

Giải Quyết vấn đề của tôi bằng cách tạo ra một NSURLSession mặc định mới cho mỗi NSURLSessionDataTask. Đã xảy ra lỗi với cách tôi đang cố gắng chia sẻ một NSURLSession cho tất cả các nhiệm vụ của mình. phương pháp startLoading URLProtocol bây giờ là như sau:

- (void)startLoading { 
    NSMutableURLRequest *newRequest = [self.request mutableCopy]; 
    [NSURLProtocol setProperty:@YES forKey:@"handled" inRequest:newRequest]; 
    NSURLSessionConfiguration* config = NSURLSessionConfiguration.defaultSessionConfiguration; 
    NSURLSession* session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; 
    self.dataTask = [session dataTaskWithRequest:newRequest]; 
    [self.dataTask resume]; 
} 

Các thử nghiệm trang HTML đơn giản trước khi phải làm việc vì chỉ có một nhiệm vụ là cần thiết để tải các trang

Các vấn đề liên quan