AFNetWorking初探之AFHTTPRequestOperationManager(一)

使用方法如下 post get大同小异

-(void)getTrainOnWaySearchGroupList:(NSDictionary*)value isClean:(BOOL)clean completeblock:(void (^)(NSDictionary *))complete faild:(void (^)(void *))faild
{
    
    NSString* requestURI=[[NSString alloc] initWithFormat:@"%@%@",SERVER_URI,TRAINXCGROUPSEARCHLIST];
    
    
    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
   // manager.responseSerializer = [AFHTTPResponseSerializer serializer];//根据情况添加默认的是self.responseSerializer = [AFHTTPReponseSerializer serializer]
    
    [manager POST:requestURI parameters:value
     
          success:^(AFHTTPRequestOperation *operation,id responseObject) {
              
             
              
          }failure:^(AFHTTPRequestOperation *operation,NSError *error) {
              
              //NSLog(@"发生错误!%@",error);
              faild(nil);
              
          }];
    
}


使用方法很简单 

1.初始化manager  

2.调用manager的方法,如上面调用的是manager当中的post方法,如果打开.h文件我们还会发现很多其他方法get put head。。。。


初始化

初始化过程afnetworing给我们封装的很简单只要调用一个manager方法就可以 源码如下

+ (instancetype)manager {
    return [[self alloc] initWithBaseURL:nil];
}

- (instancetype)init {
    return [self initWithBaseURL:nil];
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    self = [super init];
    if (!self) {
        return nil;
    }

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url; 

    self.requestSerializer = [AFHTTPRequestSerializer serializer]; 
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    self.securityPolicy = [AFSecurityPolicy defaultPolicy]; //安全相关

    self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];

    self.operationQueue = [[NSOperationQueue alloc] init];//初始化一个操作队列 在执行post,get等方法时会将生成的request添加到这个队列

    self.shouldUseCredentialStorage = YES;

    return self;
}

这个过程中首先if语句为添加了一个空字符串 注释写了是为了保证 NSURL +URLWithString:relativeToURL:这个方法正常工作。详细的可以看看苹果的API。然后下面就是一系列的赋值操作。


先看self.requestSerializer 一个初始化操作都干了些什么呢源码如下

+ (instancetype)serializer {
    return [[self alloc] init];
}

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.stringEncoding = NSUTF8StringEncoding;//编码

    self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];

    // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
    NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
    [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        float q = 1.0f - (idx * 0.1f);
        [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
        *stop = q <= 0.5f;
    }];
    [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];

    NSString *userAgent = nil;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
    // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
    userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
    userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleExecutableKey] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
#endif
#pragma clang diagnostic pop
    if (userAgent) {
        if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
            NSMutableString *mutableUserAgent = [userAgent mutableCopy];
            if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
                userAgent = mutableUserAgent;
            }
        }
        [self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
    }

    // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
    self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];

    self.mutableObservedChangedKeyPaths = [NSMutableSet set];
    for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
        if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
            [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
        }
    }

    return self;
}

可以看到这个requsetserializer 方法里面做了很多事情设置请求头啥的,模棱两可。


这里说下self.responseSerializer = [AFJSONResponseSerializer serializer]; 以前在介绍AFHTTPRequestOperation时曾看到过类似的赋值操作self.responseSerializer = [AFHTTPReponseSerializer serializer];其实这两个地方的声明都是一样的 AFHTTPReponseSerializer是AFJSONResponseSerializer的父类。AFJSONResponseSerializer 覆盖了父类的 serializer 两个serializer方法如下

AFHTTPReponseSerializer

@implementation AFHTTPResponseSerializer

+ (instancetype)serializer {
    return [[self alloc] init];
}

- (instancetype)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.stringEncoding = NSUTF8StringEncoding;

    self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
    self.acceptableContentTypes = nil;

    return self;
}

AFJSONResponseSerializer

@implementation AFJSONResponseSerializer

+ (instancetype)serializer {
    return [self serializerWithReadingOptions:(NSJSONReadingOptions)0];
}

+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions {
    AFJSONResponseSerializer *serializer = [[self alloc] init];
    serializer.readingOptions = readingOptions;

    return serializer;
}

- (instancetype)init {
    self = [super init]; //调用父类方法
    if (!self) {
        return nil;
    }

    self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil];//父类这里设置的是nil 这里重新赋值了

    return self;
}

整个下来其实子类要比父类多完成一下工作1.为acceptableContentTypes赋值 2.将Serializer声明为AFJSONResponseSerializer类型 为readingOptions赋值 (作用还不明了)

注:在很多时候我们使用manager的时候会报错 错误原因

Domain=com.alamofire.error.serialization.response Code=-1016 "Request failed: unacceptable content-type: text/plain" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x7fcf34032de0>


这是因为acceptableContentTypes这个值默认的给我们的是@"application/json", @"text/json", @"text/javascript" 而很多服务器要求的是text/plain ,解决这个问题有两种方案1.修改源码 添加text/plain。2.在manager初始化完毕后添加

//manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/html"];//如果提示的是text/html则添加这个

manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/plain"];


调用manager的方法

点开afnetworking...manager.h我们发现这里面的有很多类似以下的方法 只是名字换成了 get head等等 穿进去的参数都是一样的。

/**
 Creates and runs an `AFHTTPRequestOperation` with a `GET` request.

 @param URLString The URL string used to create the request URL.
 @param parameters The parameters to be encoded according to the client request serializer.
 @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
 @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.

 @see -HTTPRequestOperationWithRequest:success:failure:
 */
- (AFHTTPRequestOperation *)GET:(NSString *)URLString
                     parameters:(id)parameters
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

官方的解释最后都是让我们去参见-HTTPRequestOperationWithRequest:success:failure:这个方法。先不论这个方法是干什么的我们点进去看看我们会调用的上面的方法源码如下

- (AFHTTPRequestOperation *)GET:(NSString *)URLString
                     parameters:(id)parameters
                        success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                        failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil];//调用self.requestSerializer的requsetWithMethod:URLString :parameters:error:方法,作用上面已经说过。
    AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];//这里果然让我们调用了上面提到的方法。

    [self.operationQueue addOperation:operation];//放到队列里面请求

    return operation;
}

其实我们仔细看源码就话发现无论是get post 还是head方法基本上是这几个步骤 

1.调用self.requestSerializer的requsetWithMethod:URLString :parameters:error:方法得到一个request 。

2.用这个request作为参数传入HTTPRequestOperationWithRequest:success:failure:这个方法当中得到一个opreation。

3.将opreation 加入到请求队列里面开始请求。










你可能感兴趣的:(AFNetWorking初探之AFHTTPRequestOperationManager(一))