gpt4 book ai didi

ios - 将 NSURLConnection 切换到 NSURLSession 后自定义 NSURLProtocol 变慢

转载 作者:可可西里 更新时间:2023-11-01 03:32:05 27 4
gpt4 key购买 nike

我有一个自定义的 NSURLProtocol(“UrlProtocol”),用于在导航到特定网站时拦截来自 UIWebView 的请求,并在发送前应用额外的 HTTP header 。我关注了https://www.raywenderlich.com/59982/nsurlprotocol-tutorial对于一个 worker 类(Class)。我的问题是从已弃用的 NSURLConnection 切换到 NSURLSession:我测试了一个非常简单的单文件 html 页面,它加载成功。但是,具有 js 文件、图像等资源的稍微复杂的站点将超时,而使用 NSURLConnection 整个站点将在几秒钟内加载。

我将使用 NSURLConnection 粘贴原始 UrlProtocol,然后使用 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

“Globals”是一个单例,我已经在其中初始化了一个 NSURLSession,以便在应用程序的整个运行时使用。它还包含我为所有请求设置为自定义 HTTP header 的 token :

#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

最佳答案

通过为每个 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 页面测试肯定是有效的,因为加载页面只需要一个任务

关于ios - 将 NSURLConnection 切换到 NSURLSession 后自定义 NSURLProtocol 变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41477434/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com