2016-02-15 38 views
0

我在繼承NSURLProtocol攔截HTTP請求。自定義NSURLProtocol導致__psynch_mutexwait

這裏是自定義NSURLProtocol類。

+ (BOOL)canInitWithRequest:(NSURLRequest *)request { 
    if (NSOrderedSame != [request.URL.scheme caseInsensitiveCompare:@"http"] && 
     NSOrderedSame != [request.URL.scheme caseInsensitiveCompare:@"https"]) { 
     return NO; 
    } 

    if ([NSURLProtocol propertyForKey:kURLProtocolRequestHandledKey inRequest:request]) { 
     return NO; 
    } 

    return YES; 
} 

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 
    NSMutableURLRequest *mutableReqeust = [request mutableCopy]; 
    [NSURLProtocol setProperty:@YES forKey:kURLProtocolRequestHandledKey inRequest:mutableReqeust]; 
    return [mutableReqeust copy]; 
} 

- (void)startLoading { 
    self.startDate = [NSDate date]; 
    self.data = [NSMutableData data]; 
    self.error = nil; 

    self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:YES]; 
} 

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

#pragma mark - NSURLConnectionDelegate 

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

- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection *)connection { 
    return YES; 
} 

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

#pragma mark - NSURLConnectionDataDelegate 

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { 
    if (response != nil){ 
     _response = response; 
     NSMutableURLRequest *redirect = [request mutableCopy]; 
     redirect.URL = request.URL; 
     [NSURLProtocol setProperty:@NO forKey:kURLProtocolRequestHandledKey inRequest:redirect]; 
     [[self client] URLProtocol:self wasRedirectedToRequest:redirect redirectResponse:response]; 

     return redirect; 
    } 
    return request; 
} 

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

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

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { 
    return cachedResponse; 
} 

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

- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { 

} 

我添加UIWebView作爲一個子視圖,然後加載URL http://ln.clientaccess.10086.cn/shop/optical/Appointment?channel=007&PHONE_NUM=18240235054&AREA_CODE=240&key=4A35774433BA79EB950EDE4B5C4D7121,控制器被駁回後,應用程序被凍結,即使我打電話- stopLoading上web視圖它駁回了。

這裏是線程堆棧:

enter image description here

回答

0

要修改canonicalRequest的要求,我不認爲 - 離開單獨。您確實想在startLoading中對其進行修改,並在NSURLConnection的新調用中使用修改的請求,以便您的協議在該調用期間不再處理它。

第二件事是重定向實現可能是錯誤的 - 該方法在兩種情況下被調用;一次發送請求時(並且重定向爲零);你想在這種情況下返回請求(你這樣做)。第二個是當你實際得到重定向時;你想調用客戶端(你是),但是你想返回零,以便讓客戶端實際處理重定向(否則非零返回可以表示重定向已被處理)。

我不確定那些會導致問題,但他們是不同的。

我看到的唯一另外一件事與我實施的不同之處在於startImmediately:YES。這是默認的,所以這不應該成爲問題。也許嘗試避免緩存,看看是否有幫助,如果以上都沒有。或者確保在dealloc的連接上調用-cancel。

+0

感謝您的回覆。重定向實施是可以的。 我讀過一些'NSURLProtocol'教程也調用'startImmediately:YES',我認爲這不是問題。 – Weizhi

+0

我在NSURLProtocol類上花了更多的時間,比我關心的承認...我相信如果你不返回nil與重定向,它不會傳回到原始的NSURLConnection委託。我已經很仔細地測試了一堆協議。我沒有看到很多教程正確。另一方面,如果你實際上沒有獲得重定向,那不會是一個問題。如果你更多地擴展回溯,這可能會有所幫助 - 你會遇到死鎖,但是不清楚主線程是否自己或其他線程死鎖。 –

+0

WebView在'viewDidLoad'中啓動請求: ' - (void)viewDidLoad {super viewDidLoad]; NSString * URLString = @「http://ln.clientaccess.10086.cn/shop/optical/Appointment?channel=007&PHONE_NUM=18240235054&AREA_CODE=240&key=4A35774433BA79EB950EDE4B5C4D7121」; NSURL * URL = [NSURL URLWithString:URLString]; [[self webView] loadRequest:[NSURLRequest requestWithURL:URL]]; }' 該URL有66個請求,沒有重定向URL,我認爲重定向不是問題。 – Weizhi

0

使用startImmediately:NO而不是startImmediately:YES將解決此問題。

if (currentRunLoop && [currentRunLoop currentMode]) { 
     self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:NO]; 
     [self.connection scheduleInRunLoop:currentRunLoop forMode:[[NSRunLoop currentRunLoop] currentMode]]; 
     [self.connection start]; 

    } else { 
     self.connection = [[NSURLConnection alloc] initWithRequest:[[self class] canonicalRequestForRequest:self.request] delegate:self startImmediately:YES]; 
    } 

它是有線的。請問有人會告訴我爲什麼?

+0

如果您使用startImmediately:YES進行安排,則連接將使用默認模式安排在默認運行循環中。如果你想在主運行循環以外的任何地方運行它,你必須推遲啓動它,直到你將它安排在正確的運行循環中。不知道這是否回答你的問題。 – dgatwood

相關問題