这个类看了一下,信息量很大,然后学习一下他的牛逼代码写法
牛逼之处:
1.在类中设置一些数据(就是NSURLRequest的属性),使用KVO来监听自己的属性,使用C语言方法,获取要去监听属性的单利数组,为了防止普通字符串写起来容易出错,使用get方法
2.使用协议来声明一个方法,让AFHTTPRequestSerializer
,AFJSONRequestSerializer
,AFPropertyListRequestSerializer
他们去准守,扩展方法
3.使用递归方法,将字典参数转变成AFQueryStringPair
对象
4.对外暴露出属性,都是只读属性,然后使用了两种机制
1.在类中设置一些数据(就是NSURLRequest的属性),使用KVO来监听自己的属性,使用C语言方法,获取要去监听属性的单利数组
- 初始化时候,确定要去监听的属性数组
static NSArray * AFHTTPRequestSerializerObservedKeyPaths() {
static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))];
});
return _AFHTTPRequestSerializerObservedKeyPaths;
}
- 添加KVO
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
}
}
- 移除KVO
- (void)dealloc {
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self removeObserver:self forKeyPath:keyPath context:AFHTTPRequestSerializerObserverContext];
}
}
}
- 重写属性set方法,手动发送通知,执行KVO
- (void)setNetworkServiceType:(NSURLRequestNetworkServiceType)networkServiceType {
[self willChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))];
_networkServiceType = networkServiceType;
[self didChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))];
}
- (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval {
[self willChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))];
_timeoutInterval = timeoutInterval;
[self didChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))];
}
- 关闭自动发送通知,触发KVO
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
if ([AFHTTPRequestSerializerObservedKeyPaths() containsObject:key]) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
- 当监听的属性发送变化的时候,要去处理数据,如果是NULL,移除value,否则添加value
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(__unused id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == AFHTTPRequestSerializerObserverContext) {
if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
[self.mutableObservedChangedKeyPaths removeObject:keyPath];
} else {
[self.mutableObservedChangedKeyPaths addObject:keyPath];
}
}
}
好处:
1.使用静态创建C语言方法,杂糅这单利,为了防止手动写文字出现错误,没有验证字符串,所以使用了get方法,然后在内存中只保存一份,非常的简单,懒加载;
2.关闭自动的KVO,使用手动调用KVO,方便管理,减少非必要的调用;
2.使用协议来声明一个方法,让AFHTTPRequestSerializer
,AFJSONRequestSerializer
,AFPropertyListRequestSerializer
他们去准守,扩展方法
协议名称就是AFURLRequestSerialization
,声明了一个协议方法
- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(nullable id)parameters
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
这个类是通过一个request和paras然后创建一个新的request,这个协议为好多的类准守实现,然后在父类中调用,在子类中重写,不会发生奔溃;
//在AFHTTPRequestSerializer中,调用在本类中实现的协议方法
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
好处:
1.方法统一,方便管理.
2.父类中写一句,将来如果子类实现,可以直接调用该方法
3.使用递归方法,将字典参数转变成AFQueryStringPair对象
牛逼的第三方都用递归,AFNetworking
,SDWebImage
,MJExtension
都有对数据的判断,然后使用的就是递归
NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) {
NSMutableArray *mutableQueryStringComponents = [NSMutableArray array];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)];
if ([value isKindOfClass:[NSDictionary class]]) {
NSDictionary *dictionary = value;
// Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries
for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
id nestedValue = dictionary[nestedKey];
if (nestedValue) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)];
}
}
} else if ([value isKindOfClass:[NSArray class]]) {
NSArray *array = value;
for (id nestedValue in array) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)];
}
} else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
}
} else {
[mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]];
}
return mutableQueryStringComponents;
}
4.对外暴露出属性,都是只读属性,然后使用了两种机制
一个类,对外暴露一个属性,是readonly,那么其实是有两中写法的;
//例子一,通过其他数据构建一个新的对象
//.h文件
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
//.m文件
- (NSDictionary *)HTTPRequestHeaders {
return [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
}
//例子二,在.h 和.m 文件中去写同名的属性,只是后者是readwrite属性
//.h文件
@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue;
//.m文件
@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue;
好处:让外界只能使用,不能修改数据