AFNetworking

结构层次:

NSURLSession

  • AFURLSessionManager
  • AFHTTPSessionManager

Serialization(序列化)

* <AFURLRequestSerialization>

    * AFHTTPRequestSerializer
    * AFJSONRequestSerializer
    * AFPropertyListRequestSerializer

* <AFURLResponseSerialization>//iOS只会用到前三种

    * AFHTTPResponseSerializer
    * AFJSONResponseSerializer
    * AFXMLParserResponseSerializer
    * AFXMLDocumentResponseSerializer (Mac OS X)
    * AFPropertyListResponseSerializer
    * AFImageResponseSerializer
    * AFCompoundResponseSerializer

Additional Functionality(附加方法)

  • AFSecurityPolicy
  • AFNetworkReachabilityManager(检测网络状态,比如wifi切换3g)

AFN的Get,Post,下载,上传

//发送GET请求
/*
 第一个参数:请求路径(不包含参数).NSString
 第二个参数:字典(发送给服务器的数据~参数)
 第三个参数:progress 进度回调
 第四个参数:success 成功回调
 task:请求任务
 responseObject:响应体信息(JSON--->OC对象)
 第五个参数:failure 失败回调
 error:错误信息
 响应头:task.response
 */

- (void)get
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    NSDictionary *body = @{
                           @"username" : @"520it",
                           @"pwd" : @"520it",
                           @"type" : @"JSON",
                           };

    [manager GET:@"http://120.25.226.186:32812/login" parameters:body progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"%@",downloadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"%@",task.response);
        NSLog(@"%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",task.response);
        NSLog(@"%@",error);
    }];
}

//发送POST请求,方法结构和GET一模一样
/*
 第一个参数:请求路径(不包含参数).NSString
 第二个参数:字典(发送给服务器的数据~参数)
 第三个参数:progress 进度回调
 第四个参数:success 成功回调
 task:请求任务
 responseObject:响应体信息(JSON--->OC对象)
 第五个参数:failure 失败回调
 error:错误信息
 响应头:task.response
 */
- (void)post
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    NSDictionary *body = @{
                           @"username" : @"520it",
                           @"pwd" : @"520it",
                           @"type" : @"JSON",
                           };

    [manager POST:@"http://120.25.226.186:32812/login" parameters:body progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"%@",downloadProgress);
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"%@",task.response);
        NSLog(@"%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"%@",task.response);
        NSLog(@"%@",error);
    }];

}

//下载文件
/*
 第一个参数:请求对象
 第二个参数:progress 进度回调 downloadProgress
 第三个参数:destination 回调(目标位置)
 有返回值
 targetPath:临时文件路径
 response:响应头信息
 第四个参数:completionHandler 下载完成之后的回调
 filePath:最终的文件路径
 */
- (void)download
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_01.png"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        NSLog(@"%f", 1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {

        NSLog(@"%@",targetPath);

        NSString *fullPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:response.suggestedFilename];

        NSLog(@"%@",fullPath);

        return [NSURL fileURLWithPath:fullPath];
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        NSLog(@"%@",filePath);
    }];

    [downloadTask resume];
}

//不推荐
-(void)upload
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //2.1url
    NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/upload"];

    //2.2创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //2.3 设置请求方法
    request.HTTPMethod = @"POST";

    //2.4 设请求头信息
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];

    //3.发送请求上传文件
    NSURLSessionUploadTask *uploadTask = [manager uploadTaskWithRequest:request fromData:[self getBodyData] progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount/ uploadProgress.totalUnitCount);

    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {

        NSLog(@"%@",responseObject);
    }];

    //4.执行task
    [uploadTask resume];
}

-(NSData *)getBodyData
{
    NSMutableData *fileData = [NSMutableData data];
    //5.1 文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="file"; filename="Snip20160225_341.png"
     Content-Type: image/png(MIMEType:大类型/小类型)
     空行
     文件参数
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];

    //name:file 服务器规定的参数
    //filename:Snip20160225_341.png 文件保存到服务器上面的名称
    //Content-Type:文件的类型
    [fileData appendData:[@"Content-Disposition: form-data; name=\"file\"; filename=\"Sss.png\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];

    UIImage *image = [UIImage imageNamed:@"Snip20160227_128"];
    //UIImage --->NSData
    NSData *imageData = UIImagePNGRepresentation(image);
    [fileData appendData:imageData];
    [fileData appendData:KNewLine];

    //5.2 非文件参数
    /*
     --分隔符
     Content-Disposition: form-data; name="username"
     空行
     123456
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"Content-Disposition: form-data; name=\"username\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];
    [fileData appendData:KNewLine];
    [fileData appendData:[@"123456" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine];

    //5.3 结尾标识
    /*
     --分隔符--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--",Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    return fileData;
}

-(void)upload2
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //    NSDictionary *dictM = @{}
    //2.发送post请求上传文件
    /*
     第一个参数:请求路径
     第二个参数:字典(非文件参数)
     第三个参数:constructingBodyWithBlock 处理要上传的文件数据
     第四个参数:进度回调
     第五个参数:成功回调 responseObject:响应体信息
     第六个参数:失败回调
     */
    [manager POST:@"http://120.25.226.186:32812/upload" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {

        UIImage *image = [UIImage imageNamed:@"Snip20160227_128"];
        NSData *imageData = UIImagePNGRepresentation(image);

        //使用formData来拼接数据
        /*
         第一个参数:二进制数据 要上传的文件参数
         第二个参数:服务器规定的
         第三个参数:该文件上传到服务器以什么名称保存
         */
        //[formData appendPartWithFileData:imageData name:@"file" fileName:@"xxxx.png" mimeType:@"image/png"];

        //[formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip20160227_128.png"] name:@"file" fileName:@"123.png" mimeType:@"image/png" error:nil];

        [formData appendPartWithFileURL:[NSURL fileURLWithPath:@"/Users/xiaomage/Desktop/Snip20160227_128.png"] name:@"file" error:nil];

    } progress:^(NSProgress * _Nonnull uploadProgress) {

        NSLog(@"%f",1.0 * uploadProgress.completedUnitCount/uploadProgress.totalUnitCount);

    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"上传成功---%@",responseObject);

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"上传失败---%@",error);
    }];

}

如果返回的是XML

-(void)xml
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //http://120.25.226.186:32812/login?username=123&pwd=122&type=JSON
    //

    //注意:如果返回的是xml数据,那么应该修改AFN的解析方案
    manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    NSDictionary *paramDict = @{
                                @"type":@"XML"
                                };
    //2.发送GET请求
    /*
     第一个参数:请求路径(不包含参数).NSString
     第二个参数:字典(发送给服务器的数据~参数)
     第三个参数:progress 进度回调
     第四个参数:success 成功回调
        task:请求任务
        responseObject:响应体信息(JSON--->OC对象)
     第五个参数:failure 失败回调
        error:错误信息
     响应头:task.response
     */
    [manager GET:@"http://120.25.226.186:32812/video" parameters:paramDict progress:nil success:^(NSURLSessionDataTask * _Nonnull task,NSXMLParser *parser) {

        //NSLog(@"%@---%@",[responseObject class],responseObject);
        //NSXMLParser *parser =(NSXMLParser *)responseObject;

        //设置代理
        parser.delegate = self;

        //开始解析
        [parser parse];

    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

#pragma mark ----------------------
#pragma mark NSXMLParserDelegate
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary<NSString *,NSString *> *)attributeDict
{
    NSLog(@"%@--%@",elementName,attributeDict);
}

如果返回的二进制数据

-(void)httpData
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //注意:如果返回的是xml数据,那么应该修改AFN的解析方案AFXMLParserResponseSerializer
    //注意:如果返回的数据既不是xml也不是json那么应该修改解析方案为:
    //manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //2.发送GET请求
    [manager GET:@"http://120.25.226.186:32812/resources/images/minion_01.png" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task,id  _Nullable responseObject) {
        NSLog(@"%@-",[responseObject class]);

        //UIImage *image = [UIImage imageWithData:responseObject];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

-(void)httpData2
{
    //1.创建会话管理者
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];

    //注意:如果返回的是xml数据,那么应该修改AFN的解析方案AFXMLParserResponseSerializer
    //注意:如果返回的数据既不是xml也不是json那么应该修改解析方案为:
    //manager.responseSerializer = [AFXMLParserResponseSerializer serializer];

    //告诉AFN能够接受text/html类型的数据
    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];

    manager.responseSerializer = [AFHTTPResponseSerializer serializer];

    //2.发送GET请求
    [manager GET:@"http://www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task,id  _Nullable responseObject) {
        NSLog(@"%@-%@",[responseObject class],[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);

        //UIImage *image = [UIImage imageWithData:responseObject];
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"请求失败--%@",error);
    }];
}

一个AFN框架封装的工具类:

//
//  YYHttpTool.h
//网络请求工具类,负责整个项目中所有的Http网络请求

#import <Foundation/Foundation.h>
#import "AFNetworking.h"

@interface YYHttpTool : NSObject
/**
 *  发送一个GET请求
 *
 *  @param url     请求路径
 *  @param params  请求参数
 *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
 *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
 */
+ (void)get:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;

/**
 *  发送一个POST请求
 *
 *  @param url     请求路径
 *  @param params  请求参数
 *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
 *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
 */
+ (NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void(^)(id responseObj))success failure:(void(^)(NSError *error))failure;
@end
//
//  YYHttpTool.m
//

#import "YYHttpTool.h"


@implementation YYHttpTool
+(void)get:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
    //1.获得请求管理者
    AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];

    //2.发送Get请求
    [mgr GET:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
}

+(NSURLSessionDataTask *)post:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))success failure:(void (^)(NSError *))failure
{
    //1.获得请求管理者
    AFHTTPSessionManager *mgr = [AFHTTPSessionManager manager];

   NSURLSessionDataTask *dataTask = [mgr POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {

       if (success) {
           success(responseObject);
       }

   } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

       if (failure) {
           failure(error);
       }
   }];

    return dataTask;
}
@end

AFN监听网络状态的实例:

#import "ViewController.h"
#import "AFNetworking.h"
#import "Reachability.h"

@interface ViewController ()
@property (nonatomic, strong) Reachability *r;
@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appleReachability) name:kReachabilityChangedNotification object:nil];

    Reachability *r = [Reachability reachabilityForLocalWiFi];
    [r startNotifier];
    self.r = r;
}

-(void)dealloc
{
    [[NSNotificationCenter defaultCenter]removeObserver:self];

}

-(void)appleReachability
{
    /*
     NotReachable = 0,
     ReachableViaWiFi,
     ReachableViaWWAN
     */
    //该方法得到一个Reachability类型的蜂窝网络对象
    if ([Reachability reachabilityForInternetConnection].currentReachabilityStatus == ReachableViaWWAN)
    {
        NSLog(@"蜂窝网络");
        return;
    }

    if ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == ReachableViaWiFi) {
        NSLog(@"WIFI");
        return;
    }

    NSLog(@"没有网络");
}

-(void)afn
{

    //1.获得一个网络状态检测管理者
    AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager];

    //2.监听状态的改变
    /*
     AFNetworkReachabilityStatusUnknown          = -1, 未知
     AFNetworkReachabilityStatusNotReachable     = 0,  没有网络
     AFNetworkReachabilityStatusReachableViaWWAN = 1,  蜂窝网络
     AFNetworkReachabilityStatusReachableViaWiFi = 2   Wifi
     */
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        switch (status) {
            case AFNetworkReachabilityStatusReachableViaWWAN:
                NSLog(@"蜂窝网络");
                break;
            case AFNetworkReachabilityStatusReachableViaWiFi:
                NSLog(@"WIFI");
                break;
            case AFNetworkReachabilityStatusNotReachable:
                NSLog(@"没有网络");
                break;
            case AFNetworkReachabilityStatusUnknown:
                NSLog(@"未知");
                break;
            default:
                break;
        }
    }];

    //3.开始监听
    [manager startMonitoring];
}

@end

上面程序用到的API:Reachability

Reachability.h

#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <netinet/in.h>


typedef enum : NSInteger {
    NotReachable = 0,
    ReachableViaWiFi,
    ReachableViaWWAN
} NetworkStatus;


extern NSString *kReachabilityChangedNotification;


@interface Reachability : NSObject

/*!
 * Use to check the reachability of a given host name.
 */
+ (instancetype)reachabilityWithHostName:(NSString *)hostName;

/*!
 * Use to check the reachability of a given IP address.
 */
+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress;

/*!
 * Checks whether the default route is available. Should be used by applications that do not connect to a particular host.
 */
+ (instancetype)reachabilityForInternetConnection;

/*!
 * Checks whether a local WiFi connection is available.
 */
+ (instancetype)reachabilityForLocalWiFi;

/*!
 * Start listening for reachability notifications on the current run loop.
 */
- (BOOL)startNotifier;
- (void)stopNotifier;

- (NetworkStatus)currentReachabilityStatus;

/*!
 * WWAN may be available, but not active until a connection has been established. WiFi may require a connection for VPN on Demand.
 */
- (BOOL)connectionRequired;

@end

Reachability.m

#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#import <sys/socket.h>

#import <CoreFoundation/CoreFoundation.h>

#import "Reachability.h"


NSString *kReachabilityChangedNotification = @"kNetworkReachabilityChangedNotification";


#pragma mark - Supporting functions

#define kShouldPrintReachabilityFlags 1

static void PrintReachabilityFlags(SCNetworkReachabilityFlags flags, const char* comment)
{
#if kShouldPrintReachabilityFlags

//    NSLog(@"Reachability Flag Status: %c%c %c%c%c%c%c%c%c %s\n",
//          (flags & kSCNetworkReachabilityFlagsIsWWAN)                ? 'W' : '-',
//          (flags & kSCNetworkReachabilityFlagsReachable)            ? 'R' : '-',
//
//          (flags & kSCNetworkReachabilityFlagsTransientConnection)  ? 't' : '-',
//          (flags & kSCNetworkReachabilityFlagsConnectionRequired)   ? 'c' : '-',
//          (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic)  ? 'C' : '-',
//          (flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
//          (flags & kSCNetworkReachabilityFlagsConnectionOnDemand)   ? 'D' : '-',
//          (flags & kSCNetworkReachabilityFlagsIsLocalAddress)       ? 'l' : '-',
//          (flags & kSCNetworkReachabilityFlagsIsDirect)             ? 'd' : '-',
//          comment
//          );
#endif
}


static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
{
#pragma unused (target, flags)
    NSCAssert(info != NULL, @"info was NULL in ReachabilityCallback");
    NSCAssert([(__bridge NSObject*) info isKindOfClass: [Reachability class]], @"info was wrong class in ReachabilityCallback");

    Reachability* noteObject = (__bridge Reachability *)info;
    // Post a notification to notify the client that the network reachability changed.
    [[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification object: noteObject];
}


#pragma mark - Reachability implementation

@implementation Reachability
{
    BOOL _alwaysReturnLocalWiFiStatus; //default is NO
    SCNetworkReachabilityRef _reachabilityRef;
}

+ (instancetype)reachabilityWithHostName:(NSString *)hostName
{
    Reachability* returnValue = NULL;
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
    if (reachability != NULL)
    {
        returnValue= [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
            returnValue->_alwaysReturnLocalWiFiStatus = NO;
        }
    }
    return returnValue;
}


+ (instancetype)reachabilityWithAddress:(const struct sockaddr_in *)hostAddress
{
    SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)hostAddress);

    Reachability* returnValue = NULL;

    if (reachability != NULL)
    {
        returnValue = [[self alloc] init];
        if (returnValue != NULL)
        {
            returnValue->_reachabilityRef = reachability;
            returnValue->_alwaysReturnLocalWiFiStatus = NO;
        }
    }
    return returnValue;
}



+ (instancetype)reachabilityForInternetConnection
{
    struct sockaddr_in zeroAddress;
    bzero(&zeroAddress, sizeof(zeroAddress));
    zeroAddress.sin_len = sizeof(zeroAddress);
    zeroAddress.sin_family = AF_INET;

    return [self reachabilityWithAddress:&zeroAddress];
}


+ (instancetype)reachabilityForLocalWiFi
{
    struct sockaddr_in localWifiAddress;
    bzero(&localWifiAddress, sizeof(localWifiAddress));
    localWifiAddress.sin_len = sizeof(localWifiAddress);
    localWifiAddress.sin_family = AF_INET;

    // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0.
    localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);

    Reachability* returnValue = [self reachabilityWithAddress: &localWifiAddress];
    if (returnValue != NULL)
    {
        returnValue->_alwaysReturnLocalWiFiStatus = YES;
    }

    return returnValue;
}


#pragma mark - Start and stop notifier

- (BOOL)startNotifier
{
    BOOL returnValue = NO;
    SCNetworkReachabilityContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};

    if (SCNetworkReachabilitySetCallback(_reachabilityRef, ReachabilityCallback, &context))
    {
        if (SCNetworkReachabilityScheduleWithRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode))
        {
            returnValue = YES;
        }
    }

    return returnValue;
}


- (void)stopNotifier
{
    if (_reachabilityRef != NULL)
    {
        SCNetworkReachabilityUnscheduleFromRunLoop(_reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    }
}


- (void)dealloc
{
    [self stopNotifier];
    if (_reachabilityRef != NULL)
    {
        CFRelease(_reachabilityRef);
    }
}


#pragma mark - Network Flag Handling

- (NetworkStatus)localWiFiStatusForFlags:(SCNetworkReachabilityFlags)flags
{
    PrintReachabilityFlags(flags, "localWiFiStatusForFlags");
    NetworkStatus returnValue = NotReachable;

    if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
    {
        returnValue = ReachableViaWiFi;
    }

    return returnValue;
}


- (NetworkStatus)networkStatusForFlags:(SCNetworkReachabilityFlags)flags
{
    PrintReachabilityFlags(flags, "networkStatusForFlags");
    if ((flags & kSCNetworkReachabilityFlagsReachable) == 0)
    {
        // The target host is not reachable.
        return NotReachable;
    }

    NetworkStatus returnValue = NotReachable;

    if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0)
    {
        /*
         If the target host is reachable and no connection is required then we'll assume (for now) that you're on Wi-Fi...
         */
        returnValue = ReachableViaWiFi;
    }

    if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) ||
        (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0))
    {
        /*
         ... and the connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs...
         */

        if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0)
        {
            /*
             ... and no [user] intervention is needed...
             */
            returnValue = ReachableViaWiFi;
        }
    }

    if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN)
    {
        /*
         ... but WWAN connections are OK if the calling application is using the CFNetwork APIs.
         */
        returnValue = ReachableViaWWAN;
    }

    return returnValue;
}


- (BOOL)connectionRequired
{
    NSAssert(_reachabilityRef != NULL, @"connectionRequired called with NULL reachabilityRef");
    SCNetworkReachabilityFlags flags;

    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
    }

    return NO;
}


- (NetworkStatus)currentReachabilityStatus
{
    NSAssert(_reachabilityRef != NULL, @"currentNetworkStatus called with NULL SCNetworkReachabilityRef");
    NetworkStatus returnValue = NotReachable;
    SCNetworkReachabilityFlags flags;

    if (SCNetworkReachabilityGetFlags(_reachabilityRef, &flags))
    {
        if (_alwaysReturnLocalWiFiStatus)
        {
            returnValue = [self localWiFiStatusForFlags:flags];
        }
        else
        {
            returnValue = [self networkStatusForFlags:flags];
        }
    }

    return returnValue;
}


@end

AFN网络请求通过获取cookies保持会话

在现在大多数的iOS的APP开发中,与服务端保持通信会话,更多的是使用token。但难免会需要使用到cookies。最近项目中就使用到了。

由于网上关于cookies的资料参差不齐,或者说基本都不适用于我吧。所以在此总结一下自己使用中遇到的坑吧。

首先,我在登录成功的回调函数中就记录下当时的cookie,并保存在本地中,全局调用。

//获取cookie  
NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage]cookiesForURL:[NSURL URLWithString:url]];  
for (NSHTTPCookie *tempCookie in cookies)  
        {  
            //打印cookies  
            NSLog(@"getCookie:%@",tempCookie);  
        }  
NSDictionary *Request = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];  

NSUserDefaults *userCookies = [NSUserDefaults standardUserDefaults];  
[userCookies setObject:[Request objectForKey:@"Cookie"] forKey:@"mUserDefaultsCookie"];  
[userCookies synchronize];

再在你需要的页面中调用出你的cookie,并存放在请求头中即可

[session.requestSerializer setValue:[[NSUserDefaults standardUserDefaults]objectForKey:@"mUserDefaultsCookie"]forHTTPHeaderField:@"Cookie"];

Error Domain=com.alamofire.error.serialization.response Code=-1016 "(AFN问题)

同样的接口,不同的项目怎么就请求不成功了呢?

尝试过很多方法,都没有找到原因,最后经过搜集大量资料

原来是AFN的问题,我是用cocoapods导入的

可能是AF2.0本身的问题,解析格式不全,所以需要在AF的源文件AFURLResponseSerialization.m中修改代码就能解决:

修改文件

self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil nil];

为:

self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil nil];


// 有做微信的话可能还要加@"text/plain"


self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",@"text/plain", nil];

AFN用post发送的parameters在Java后台接收

因为之前传的参数都是json格式,也有可能是form-data格式,PHP后台都可以接收,现在的Java后台不能接收这种格式,所以请求失败了。需要修改AFNetworking的requestSerializer

网上看到设置:

[manager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

不管用

解决:

这里我把AFJSONRequestSerializer改成了AFHTTPRequestSerializer就OK了,具体意思我看到一个博客,下方贴出有解释

//AFJSONRequestSerializer

AFHTTPRequestSerializer *request = [AFHTTPRequestSerializer serializer];

manager.requestSerializer = request;

AFNetworking的Post失败,关于requestSerializer的正确使用

错误描述和发现过程

Error Domain=NSCocoaErrorDomain Code=3840 "JSON text did not start with array or object and option to allow fragments not set."

看了错误描述后,根据它的描述是因为返回的json数据格式不对,不是json的,我就去修改AFNetworking的responseSerializer返回的序列化器,发现怎么改怎么不对,各种尝试无果之后,我打印了一下元数据,发现返回的居然是Html格式的消息,消息内容大概是服务器请求失败了,好吧,搞了半天是我请求错误了。我验证半天发现参数没什么问题啊,于是我就打印了一下用ASI请求body的数据发现是这样子的:

mid=10&method=userInfo&dateInt=20160818

我再打印了一下我用AFNetworking拼接成的body的数据格式居然是这样子的

{"mid":"11","method":"userInfo","dateInt":"20160818"}

好吧,现在我知道是哪里有问题了,因为之前传的参数都是json格式的所以没问题,谁知道这个服务器接受的数据不是json格式的,所以请求失败了。那我就需要修改AFNetworking的requestSerializer了。

requestSerializer

关于 requestSerializer它就是AFNetworking参数编码的序列化器,它一共有三种编码格式:

AFHTTPRequestSerializer:第一种是普通的http的编码格式也就是mid=10&method=userInfo&dateInt=20160818,这种格式的。

AFJSONRequestSerializer:第二种也是json编码格式的,也就是编码成{"mid":"11","method":"userInfo","dateInt":"20160818"}

AFPropertyListRequestSerializer:第三种没用过,但是看介绍接编码成pislt格式的参数

看了上面的介绍应该能明白到底该如何修改了,下面贴上我的修改过程。

解决办法

修改前:

_sharedCBClient = [[AFAppCBNetAPIClient alloc] initWithBaseURL:baseURL];
//拼接参数的序列化器,使用的错误的序列化器
_sharedCBClient.requestSerializer = [AFJSONRequestSerializer serializer];
//返回数据的序列化器
_sharedCBClient.responseSerializer = [AFJSONResponseSerializer serializer];

修改后:

_sharedCBClient = [[AFAppCBNetAPIClient alloc] initWithBaseURL:baseURL];
//拼接参数的序列化器,使用的正确的序列化器
_sharedCBClient.requestSerializer = [AFHTTPRequestSerializer serializer];
//返回数据的序列化器
_sharedCBClient.responseSerializer = [AFJSONResponseSerializer serializer];

results matching ""

    No results matching ""