Custom NSURLProtocol caused

I am subclassing NSURLProtocol to intercept HTTP request.

Here is the custom NSURLProtocol class.

+ (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 {

}

I add a UIWebView as a subView and then loads a URL http://ln.clientaccess.10086.cn/shop/optical/Appointment?channel=007&PHONE_NUM=18240235054&AREA_CODE=240&key=4A35774433BA79EB950EDE4B5C4D7121 , after the controller is dismissed , the APP is frozen even though I call - stopLoading on webView before it's dismissed.

Here is the thread stack:

在这里输入图像描述


I don't think you want to modify the request in canonicalRequest -- leave that alone. You do want to modify it in startLoading, and use the modified request in the new call to NSURLConnection, so that your protocol does not process it again during that call.

The second thing is the redirect implementation is likely wrong -- that method gets called in two situations; once when the request is being sent (and the redirect is nil); you want to return the request in that situation (which you do). The second is when you actually get a redirect; you want to call the client (which you are) but then you want to return nil, in order to let the client actually handle the redirect (otherwise the non-nil return can indicate that the redirect has been handled).

I'm not sure that either of those would cause the problem, but they are differences.

The only other thing I see different from ones I've implemented is the startImmediately:YES . That is the default though, so that shouldn't be an issue. Maybe try avoid caching and see if that helps, if neither of the above do. Or make sure to call -cancel on the connection in dealloc.


Use startImmediately:NO instead of startImmediately:YES will solve this problem.

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

It's wired. Will someone please tell me why?

链接地址: http://www.djcxy.com/p/34792.html

上一篇: NSURLProtocol没有响应UIWebviews

下一篇: 导致自定义NSURLProtocol