2017-01-05 8 views
7

NSURLProtocol( "UrlProtocol")は、特定のWebサイトに移動するときにUIWebViewからの要求を代行受信し、送信する前に余分なHTTPヘッダーを適用します。私は労働者階級のためにhttps://www.raywenderlich.com/59982/nsurlprotocol-tutorialを続けた。 NSURLConnectionからNSURLSessionに切り替えると問題が発生します。正常に読み込まれた非常に単純な1ファイルのhtmlページをテストしました。しかし、jsファイルや画像などのリソースを持つ少し複雑なサイトはタイムアウトしますが、NSURLConnectionを使用するとサイト全体が数秒以内に読み込まれます。NSURLSessionをNSURLSessionに切り替えた後のカスタムNSURLProtocolの遅さ

UrlProtocolNSURLConnectionで貼り付け、次に新しいクラスをNSURLSessionで貼り付けます。オリジナル:

#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 

新しいUrlProtocol要求ごとにNSURLSessionDataTasksを使用して:

#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 

「グローバルは、」私はアプリのランタイム全体で使用するためのもの1 NSURLSessionを初期化したシングルトンです。また、私はすべての要求のためのカスタムHTTPヘッダーとして設定されたトークンが含まれています

#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 

答えて

4

は、各NSURLSessionDataTaskの新しいデフォルトNSURLSessionを作成することによって、私の問題を解決しました。 NSURLSessionをすべての自分のタスクに共有しようとしていたとき、何かが間違っていました。次のようにURLProtocolのstartLoading方法について、次のとおりです。

- (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]; 
} 

単純なHTMLページのテスト1つのタスクのみがページ

をロードするために必要だったので、働いている必要があります前に、
関連する問題