1.HTTP请求网络层
封装AFNetworking
框架的AFHTTPRequestOperationManager
这样整个项目都使用ZYXHttpTool
提供的这两个类方法发送http请求
如果AFN框架更新了只需要更改ZYXHttpTool
的这两个类方法即可
ZYXHttpTool.h
//
// ZYXHttpTool.h
// 网络请求工具类 : 负责整个项目的所有HTTP请求
//
// Created by zhaoyingxin on 16/8/17.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYXHttpTool : NSObject
/**
* 发送一个GET请求
*
* @param urlString 请求路径
* @param paramsDict 请求参数
* @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
* @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
*/
+ (void)get:(NSString *)urlString
params:(NSDictionary *)paramsDict
success:(void (^)(id responseObj))success
failure:(void (^)(NSError *error))failure;
+ (void)post:(NSString *)urlString
params:(NSDictionary *)paramsDict
success:(void (^)(id responseObj))success
failure:(void (^)(NSError *error))failure;
@end
ZYXHttpTool.m
//
// ZYXHttpTool.m
// 网络请求工具类 : 负责整个项目的所有HTTP请求
//
// Created by zhaoyingxin on 16/8/17.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import "ZYXHttpTool.h"
#import "AFNetworking.h"
@implementation ZYXHttpTool
+ (void)get:(NSString *)urlString
params:(NSDictionary *)paramsDict
success:(void (^)(id))success
failure:(void (^)(NSError *))failure{
// 1.获得请求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.发送GET请求
[mgr GET:urlString
parameters:paramsDict
success:^(AFHTTPRequestOperation *operation, id responseObj) {
if (success) {
success(responseObj);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}
];
}
+ (void)post:(NSString *)urlString
params:(NSDictionary *)paramsDict
success:(void (^)(id))success
failure:(void (^)(NSError *))failure{
// 1.获得请求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.发送POST请求
[mgr POST:urlString
parameters:paramsDict
success:^(AFHTTPRequestOperation *operation, id responseObj) {
if (success) {
success(responseObj);
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (failure) {
failure(error);
}
}
];
}
@end
目前应该使用 NSURLSession 基于Session封装 后面补充
2.数据解析层
ZYXBaseTool.h
//
// ZYXBaseTool.h
// 数据解析层 : 服务器返回JSON字典-->模型
//
// Created by zhaoyingxin on 16/8/24.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface ZYXBaseTool : NSObject
+ (void)getWithUrl:(NSString *)urlString
param:(id)paramModel
resultClass:(Class)resultClass
success:(void (^)(id))success
failure:(void (^)(NSError *))failure;
+ (void)postWithUrl:(NSString *)urlString
param:(id)paramModel
resultClass:(Class)resultClass
success:(void (^)(id))success
failure:(void (^)(NSError *))failure;
@end
ZYXBaseTool.m
//
// ZYXBaseTool.m
// 数据解析层 : 服务器返回JSON字典-->模型
//
// Created by zhaoyingxin on 16/8/24.
// Copyright © 2014年 zhaoyingxin@aliyun.com. All rights reserved.
//
#import "ZYXBaseTool.h"
#import "ZYXHttpTool.h"
#import "MJExtension.h"
@implementation ZYXBaseTool
+ (void)getWithUrl:(NSString *)urlString
param:(id)paramModel
resultClass:(Class)resultClass
success:(void (^)(id))success
failure:(void (^)(NSError *))failure{
// MJExtension 模型->字典
NSDictionary *params = [paramModel keyValues];
[ZYXHttpTool get:urlString
params:params
success:^(id responseObj) {
if (success) {
// MJExtension 字典->模型
id result = [resultClass objectWithKeyValues:responseObj];
success(result);
}
}
failure:^(NSError *error) {
if (failure) {
failure(error);
}
}
];
}
+ (void)postWithUrl:(NSString *)urlString
param:(id)paramModel
resultClass:(Class)resultClass
success:(void (^)(id))success
failure:(void (^)(NSError *))failure{
// 模型->字典
NSDictionary *params = [paramModel keyValues];
[ZYXHttpTool post:urlString
params:params
success:^(id responseObj) {
if (success) {
// 字典->模型
id result = [resultClass objectWithKeyValues:responseObj];
success(result);
}
}
failure:^(NSError *error) {
if (failure) {
failure(error);
}
}
];
}
@end
使用了 MJExtension 框架进行字典模型间的互转
3.封装服务器提供的get/post接口
以新浪微博的 OAuth 授权接口为例
获取 AccessToken 的参数模型
#import <Foundation/Foundation.h>
@interface ZYXAccessTokenParam : NSObject
/**
true string 申请应用时分配的AppKey。
*/
@property (nonatomic, copy) NSString *client_id;
/**
true string 申请应用时分配的AppSecret。
*/
@property (nonatomic, copy) NSString *client_secret;
/**
true string 请求的类型,填写authorization_code
*/
@property (nonatomic, copy) NSString *grant_type;
/**
true string 调用authorize获得的code值。
*/
@property (nonatomic, copy) NSString *code;
/**
true string 回调地址,需需与注册应用里的回调地址一致。
*/
@property (nonatomic, copy) NSString *redirect_uri;
@end
#import "ZYXAccessTokenParam.h"
@implementation ZYXAccessTokenParam
@end
微博用户模型
ZYXAccount.h
#import <Foundation/Foundation.h>
@interface ZYXAccount : NSObject <NSCoding>
/**
string 用于调用access_token,接口获取授权后的access token。
*/
@property (nonatomic, copy) NSString *access_token;
/**
string access_token的生命周期,单位是秒数。
*/
@property (nonatomic, copy) NSString *expires_in;
/**
过期时间
*/
@property (nonatomic, strong) NSDate *expires_time;
/**
string 当前授权用户的UID。
*/
@property (nonatomic, copy) NSString *uid;
/**
用户昵称
*/
@property (nonatomic, copy) NSString *name;
@end
ZYXAccount.m
#import "ZYXAccount.h"
@implementation ZYXAccount
- (void)setExpires_in:(NSString *)expires_in{
_expires_in = [expires_in copy];
// 确定帐号的过期时间 : 帐号创建时间 + 有效期
NSDate *now = [NSDate date];
self.expires_time = [now dateByAddingTimeInterval:expires_in.doubleValue];
}
/**
将对象写入文件的时候调用
在这个方法中写清楚:要存储哪些对象的哪些属性,以及怎样存储属性
*/
- (void)encodeWithCoder:(NSCoder *)encoder{
[encoder encodeObject:self.access_token forKey:@"access_token"];
[encoder encodeObject:self.expires_in forKey:@"expires_in"];
[encoder encodeObject:self.uid forKey:@"uid"];
[encoder encodeObject:self.expires_time forKey:@"expires_time"];
[encoder encodeObject:self.name forKey:@"name"];
}
/**
当从文件中解析出一个对象的时候调用
在这个方法中写清楚:怎么解析文件中的数据
*/
- (id)initWithCoder:(NSCoder *)decoder{
if (self = [super init]) {
self.access_token = [decoder decodeObjectForKey:@"access_token"];
self.expires_in = [decoder decodeObjectForKey:@"expires_in"];
self.uid = [decoder decodeObjectForKey:@"uid"];
self.expires_time = [decoder decodeObjectForKey:@"expires_time"];
self.name = [decoder decodeObjectForKey:@"name"];
}
return self;
}
@end
ZYXAccountTool.h
#import "ZYXAccessTokenParam.h"
#import "ZYXBaseTool.h"
@class ZYXAccount;
@interface ZYXAccountTool : ZYXBaseTool
/**
* 存储帐号
*/
+ (void)save:(ZYXAccount *)account;
/**
* 读取帐号
*/
+ (ZYXAccount *)account;
/**
* 获得accesToken
*
* @param paramModel 请求参数
* @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)
* @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)
*/
+ (void)accessTokenWithParam:(ZYXAccessTokenParam *)paramModel
success:(void (^)(ZYXAccount *account))success
failure:(void (^)(NSError *error))failure;
@end
ZYXAccountTool.m
#define ZYXWeiboAccountFilepath [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"weibo_account.data"]
#import "ZYXAccountTool.h"
#import "ZYXAccount.h"
@implementation ZYXAccountTool
+ (void)save:(ZYXAccount *)account{
[NSKeyedArchiver archiveRootObject:account toFile:ZYXWeiboAccountFilepath];
}
+ (ZYXAccount *)account{
ZYXAccount *account = [NSKeyedUnarchiver unarchiveObjectWithFile:ZYXWeiboAccountFilepath];
// 判断帐号是否已经过期
NSDate *now = [NSDate date];
if ([now compare:account.expires_time] != NSOrderedAscending) { // 过期
account = nil;
}
return account;
}
+ (void)accessTokenWithParam:(ZYXAccessTokenParam *)paramModel
success:(void (^)(ZYXAccount *))success
failure:(void (^)(NSError *))failure{
[self postWithUrl:@"https://api.weibo.com/oauth2/access_token"
param:paramModel
resultClass:[ZYXAccount class]
success:success
failure:failure];
}
@end
一个完整的网络请求 数据解析 写入数据到沙盒的过程
OAuthViewController.h
#import <UIKit/UIKit.h>
@interface OAuthViewController : UIViewController <UIWebViewDelegate>
@end
OAuthViewController.m
#import "OAuthViewController.h"
#import "ZYXAccount.h"
#import "ZYXAccountTool.h"
#import "ZYXHttpTool.h"
@implementation OAuthViewController
- (void)viewDidLoad{
[super viewDidLoad];
// 1.创建UIWebView
UIWebView *webView = [[UIWebView alloc] init];
webView.frame = self.view.bounds;
[self.view addSubview:webView];
// 2.加载登录页面
NSString *urlStr = [NSString stringWithFormat:
@"https://api.weibo.com/oauth2/authorize?client_id=%@&redirect_uri=%@",
ZYXAppKey, ZYXRedirectURI];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
// 3.设置代理
webView.delegate = self;
}
#pragma mark - UIWebViewDelegate
/**
UIWebView开始加载资源的时候调用(开始发送请求)
*/
- (void)webViewDidStartLoad:(UIWebView *)webView{
}
/**
UIWebView加载完毕的时候调用(请求完毕)
*/
- (void)webViewDidFinishLoad:(UIWebView *)webView{
}
/**
UIWebView加载失败的时候调用(请求失败)
*/
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
}
/**
UIWebView每当发送一个请求之前,都会先调用这个代理方法(询问代理允不允许加载这个请求)
@param request 即将发送的请求
@return YES : 允许加载, NO : 禁止加载
*/
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType{
// 1.获得url
NSString *url = request.URL.absoluteString;
// 2.判断是否为回调地址
NSRange range = [url rangeOfString:@"code="];
if (range.length != 0) { // 是回调地址
// 截取 code= 后面的参数值
NSUInteger fromIndex = range.location + range.length;
//用户授权后新浪微博返回的code参数
NSString *code = [url substringFromIndex:fromIndex];
// 利用code换取一个accessToken
[self accessTokenWithCode:code];
// 禁止加载回调地址
return NO;
}
return YES;
}
/**
根据code获得一个accessToken(发送一个POST请求)
@param code 授权成功后的请求标记
*/
- (void)accessTokenWithCode:(NSString *)code{
// 1.封装请求参数
ZYXAccessTokenParam *paramModel = [[ZYXAccessTokenParam alloc] init];
paramModel.client_id = ZYXAppKey;
paramModel.client_secret = ZYXAppSecret;
paramModel.redirect_uri = ZYXRedirectURI;
paramModel.grant_type = @"authorization_code";
paramModel.code = code;
// 2.获得accessToken
[ZYXAccountTool accessTokenWithParam:paramModel
success:^(ZYXAccount *accountModel) {
// 存储帐号模型
[ZYXAccountTool save:accountModel];
}
failure:^(NSError *error) {
NSLog(@"请求失败--%@", error);
}
];
}
@end
// 应用信息
#define ZYXAppKey @"2507721026"
#define ZYXAppSecret @"dd92b400310fa5eb9e2fe5bc9c1caa6c"
#define ZYXRedirectURI @"http://my.oschina.net/u/2333251"