AFURLRequestSerialization 观后感

这个类看了一下,信息量很大,然后学习一下他的牛逼代码写法

牛逼之处:
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  *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;

好处:让外界只能使用,不能修改数据


你可能感兴趣的:(AFURLRequestSerialization 观后感)