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];