NSURLProtocol
定义了以下方法:
/*!
@method propertyForKey:inRequest:
@abstract Returns the property in the given request previously
stored with the given key.
@discussion The purpose of this method is to provide an interface
for protocol implementors to access protocol-specific information
associated with NSURLRequest objects.
@param key The string to use for the property lookup.
@param request The request to use for the property lookup.
@result The property stored with the given key, or nil if no property
had previously been stored with the given key in the given request.
*/
+ (nullable id)propertyForKey:(NSString *)key inRequest:(NSURLRequest *)request;
/*!
@method setProperty:forKey:inRequest:
@abstract Stores the given property in the given request using the
given key.
@discussion The purpose of this method is to provide an interface
for protocol implementors to customize protocol-specific
information associated with NSMutableURLRequest objects.
@param value The property to store.
@param key The string to use for the property storage.
@param request The request in which to store the property.
*/
+ (void)setProperty:(id)value forKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
/*!
@method removePropertyForKey:inRequest:
@abstract Remove any property stored under the given key
@discussion Like setProperty:forKey:inRequest: above, the purpose of this
method is to give protocol implementors the ability to store
protocol-specific information in an NSURLRequest
@param key The key whose value should be removed
@param request The request to be modified
*/
+ (void)removePropertyForKey:(NSString *)key inRequest:(NSMutableURLRequest *)request;
但是,如果我尝试将NSURLAuthenticationChallenge
与请求关联,请使用以下代码
[NSURLProtocol setProperty:challenge forKey:@"challenge" inRequest:self.request];
我在日志中看到下一个错误:
2016-03-20 18:00:41.252 Web@Work[6084:586155] ERROR: createEncodedCachedResponseAndRequestForXPCTransmission - Invalid protocol-property list - CFURLRequestRef. protoProps=<CFBasicHash 0x7f98ec6dcca0 [0x10684e180]>{type = mutable dict, count = 3,
entries =>
0 : <CFString 0x101f47938 [0x10684e180]>{contents = "challenge"} = <NSURLAuthenticationChallenge: 0x7f98ec4cd700>
1 : <CFString 0x7f98e9fd03a0 [0x10684e180]>{contents = "Accept-Encoding"} = <CFBasicHash 0x7f98ec7c4490 [0x10684e180]>{type = mutable dict, count = 1,
entries =>
2 : <CFString 0x7f98ec78b930 [0x10684e180]>{contents = "Accept-Encoding"} = <CFString 0x106330828 [0x10684e180]>{contents = "gzip, deflate"}
}
2 : <CFString 0x1063310e8 [0x10684e180]>{contents = "kCFURLRequestAllowAllPOSTCaching"} = <CFBoolean 0x10684ebf0 [0x10684e180]>{value = true}
}
从这条消息中,我怀疑只有属性列表支持的对象可能会使用此API与NSURLRequest
相关联。但我不完全理解为什么。
另外,我的问题是应该使用这个API。如何正确使用?我想知道setProperty:forKey:inRequest:
究竟是做什么的,因为它似乎做了更多工作,而不仅仅是将对象与请求相关联。
UPD 因此,最小的可验证示例。非常简单的NSURLProtocol
子类:
#import "MyURLProtocol.h"
#define kOurRecursiveRequestFlagProperty @"recursive"
@interface MyURLProtocol ()
@property NSURLConnection *connection;
@end
@implementation MyURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
return ![[[self class] propertyForKey:kOurRecursiveRequestFlagProperty inRequest:request] boolValue];
}
- (id)initWithRequest:(NSURLRequest *)request cachedResponse:(NSCachedURLResponse *)cachedResponse client:(id <NSURLProtocolClient>)client {
return [super initWithRequest:request cachedResponse:cachedResponse client:client];
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
NSMutableURLRequest* mutableRequest = [[self request] mutableCopy];
[[self class] setProperty:@YES forKey:kOurRecursiveRequestFlagProperty inRequest:mutableRequest];
// Associate any non-property list object with mutableRequest to reproduce issue.
[[self class] setProperty:[UIApplication sharedApplication] forKey:@"dummyKey" inRequest:mutableRequest];
self.connection = [[NSURLConnection alloc] initWithRequest:mutableRequest delegate:self startImmediately:YES];
}
- (void)stopLoading {
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[[self client] URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[[self client] URLProtocol:self didLoadData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse {
return request;
}
@end
UPD2 目前,我认为缓存是罪魁祸首。即使我使用NSURLCacheStorageNotAllowed
,此代码仍会尝试创建缓存字典,并将关联的[UIApplication sharedApplication]
写入其中。
2016-03-20 20:52:19.630 WebViewDemo [7102:663895] ADD:无法在path = / Users / xxx / Library / Developer / CoreSimulator / Devices / 89D7C50F-939B-4360-A19F-创建缓存字典4547AE4F7515 /数据/容器/数据/应用/ 6F05411C-0261-4A33-9531-9E4E900C4910 /库/缓存/ Test.WebViewDemo。键= 0x7fe76af45f90
所以,接下来我的问题是 - 如何在不实现自己的关联字典的情况下禁用此缓存。我应该这样做,还是我应该避免setProperty:forKey:inRequest:
。
最重要的是,使用setProperty:forKey:inRequest:
来存储kOurRecursiveRequestFlagProperty
是正确的,正如Apple sample所暗示的那样?我还在试图弄明白何时可以使用这种方法,何时无法使用。
答案 0 :(得分:2)
您在此处存储的对象需要是小型的,自包含的数据,以便您的协议识别该请求。
通常,如果您需要将更复杂的内容与请求相关联,则可以使用此方法来存储UUID或其他任意字符串。然后,您将在应用程序中的正常NSDictionary中存储与键相同的字符串,在告诉客户端请求已完成/失败后处理字典键和关联数据。