首页 > 代码库 > iOS开发项目篇—38深层重构

iOS开发项目篇—38深层重构

iOS开发项目篇—38深层重构

一、简单说明

说明:可以发现每个工具类,内部方法的代码长相都差不多,可以考虑再抽取出一个处理业务的公共的工具类,让其他的业务类继承自这个工具类,降低代码的冗余度。

1.新建一个工具类

该基础业务处理工具类中的代码设计:

YYBaseTool.h文件

 1 // 2 //  YYBaseTool.h 3  4 //最基本的业务工具类 5  6 #import <Foundation/Foundation.h> 7  8 @interface YYBaseTool : NSObject 9 + (void)getWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure;10 + (void)postWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure;11 @end

YYBaseTool.m文件

 1 // 2 //  YYBaseTool.m 3 // 4  5 #import "YYBaseTool.h" 6 #import "MJExtension.h" 7 #import "YYHttpTool.h" 8  9 @implementation YYBaseTool10 //get请求11 + (void)getWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure12 {13     NSDictionary *params = [param keyValues];14     15     [YYHttpTool get:url params:params success:^(id responseObj) {16         if (success) {17             id result = [resultClass objectWithKeyValues:responseObj];18             success(result);19         }20     } failure:^(NSError *error) {21         if (failure) {22             failure(error);23         }24     }];25 }26 27 //post请求28 +(void)postWithUrl:(NSString *)url param:(id)param resultClass:(Class)resultClass success:(void (^)(id))success failure:(void (^)(NSError *))failure29 {30     NSDictionary *params = [param keyValues];31     32     [YYHttpTool post:url params:params success:^(id responseObj) {33         if (success) {34             id result = [resultClass objectWithKeyValues:responseObj];35             success(result);36         }37     } failure:^(NSError *error) {38         if (failure) {39             failure(error);40         }41     }];42 }43 @end

2.其他的业务处理类,继承自该基础类

(1)用户信息业务处理类

YYUserTool.h文件

 1 // 2 //  YYUserTool.h 3 // 4  5 #import <Foundation/Foundation.h> 6 #import "YYUserInfoParam.h" 7 #import "YYUserInfoResult.h" 8 #import "YYBaseTool.h" 9 10 @interface YYUserTool : YYBaseTool11 /**12  *  加载用户的个人信息13  *14  *  @param param   请求参数15  *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)16  *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)17  */18 +(void)userInfoWithParam:(YYUserInfoParam *)param success:(void (^)(YYUserInfoResult *result))success failure:(void (^)(NSError *error))failure;19 @end

YYUserTool.m文件代码

 1 // 2 //  YYUserTool.m 3 // 4  5 #import "YYUserTool.h" 6 #import "YYHttpTool.h" 7 #import "MJExtension.h" 8  9 @implementation YYUserTool10 +(void)userInfoWithParam:(YYUserInfoParam *)param success:(void (^)(YYUserInfoResult *result))success failure:(void (^)(NSError *error))failure11 {12     13     [self getWithUrl:@"https://api.weibo.com/2/users/show.json" param:param resultClass:[YYUserInfoResult class] success:success failure:failure];14     15 //    [self getWithUrl:@"https://api.weibo.com/2/users/show.json" param:param resultClass:[HMUserInfoResult class] success:success failure:failure];16 //    //把请求参数模型转换为字典17 //    NSDictionary *params=param.keyValues;18 //    19 //    [YYHttpTool get:@"https://api.weibo.com/2/users/show.json" params:params success:^(id responseObj) {20 //        if (success) {21 //            YYUserInfoResult *result=[YYUserInfoResult objectWithKeyValues:responseObj];22 //            success(result);23 //        }24 //    } failure:^(NSError *error) {25 //        if (failure) {26 //            failure(error);27 //        }28 //    }];29 }30 @end

(2)微博业务处理类

 YYStatusTool.h文件

 1 // 2 //  YYStatusTool.h 3 //  微博业务类:处理跟微博相关的一切业务,比如加载微博数据、发微博、删微博 4  5 #import <Foundation/Foundation.h> 6 #import "YYHomeStatusesParam.h" 7 #import "YYHomeStatusesResult.h" 8 #import "YYSendStatusesParam.h" 9 #import "YYSendStatusesResult.h"10 #import "YYBaseTool.h"11 12 @interface YYStatusTool : YYBaseTool13 /**14 *  加载首页的微博数据15 *16 *  @param param   请求参数17 *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)18 *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)19 */20 21 +(void)homeStatusesWithParam:(YYHomeStatusesParam *)param success:(void (^)(YYHomeStatusesResult *result))success failure:(void(^)(NSError *error))failure;22 23 /**24  * 发微博25  *26  *  @param param   请求参数27  *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)28  *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)29  */30 31 +(void)sendStatusesWithParam:(YYSendStatusesParam *)param success:(void (^)(YYSendStatusesResult *result))success failure:(void(^)(NSError *error))failure;32 33 @end

YYStatusTool.m文件

 1 // 2 //  YYStatusTool.m 3 // 4  5 #import "YYStatusTool.h" 6 #import "YYHttpTool.h" 7 #import "MJExtension.h" 8 @implementation YYStatusTool 9 10 +(void)homeStatusesWithParam:(YYHomeStatusesParam *)param success:(void (^)(YYHomeStatusesResult *))success failure:(void (^)(NSError *))failure11 {12     13     [self getWithUrl:@"https://api.weibo.com/2/statuses/home_timeline.json" param:param resultClass:[YYHomeStatusesResult class] success:success failure:failure];14     15 //    //把请求参数模型转换为字典16 //    NSDictionary *params=param.keyValues;17 //    18 //    [YYHttpTool get:@"https://api.weibo.com/2/statuses/home_timeline.json" params:params success:^(id responseObj) {19 //        if (success) {20 //            //把获取的数据(返回结果)由字典转换为模型21 //            YYHomeStatusesResult *result=[YYHomeStatusesResult objectWithKeyValues:responseObj];22 //            success(result);23 //        }24 //    } failure:^(NSError *error) {25 //        if (failure) {26 //            failure(error);27 //        }28 //    }];29 }30 31 +(void)sendStatusesWithParam:(YYSendStatusesParam *)param success:(void (^)(YYSendStatusesResult *))success failure:(void (^)(NSError *))failure32 {33     [self postWithUrl:@"https://api.weibo.com/2/statuses/update.json" param:param resultClass:[YYSendStatusesResult class] success:success failure:failure];34     35 //    //把请求参数模型转换为字典36 //    NSDictionary *params=param.keyValues;37 //    38 //    [YYHttpTool post:@"https://api.weibo.com/2/statuses/update.json" params:params success:^(id responseObj) {39 //        if (success) {40 //            //把获取的数据(返回结果)由字典转换为模型41 //            YYSendStatusesResult *result=[YYSendStatusesResult objectWithKeyValues:responseObj];42 //            success(result);43 //        }44 //    } failure:^(NSError *error) {45 //        if (failure) {46 //            failure(error);47 //        }48 //    }];49 }50 @end

说明:在控制器中的代码不需要做额外的更改

 

二、授权控制器中业务处理(获取access_token)的类似处理

1.新建一个封装请求参数的类,继承自YYBaseTool这个类

查看获取授权,新浪官方需要的请求参数

封装请求参数类的代码设计:

YYAccessTokenParam.h文件

 1 // 2 //  YYAccessTokenParam.h 3 //  封装获取授权(access_token)的请求参数 4  5 #import "YYBaseTool.h" 6  7 @interface YYAccessTokenParam : YYBaseTool 8  9 /**    true    string    申请应用时分配的AppKey。*/10 @property (nonatomic, copy) NSString *client_id;11 12 /**        true    string    申请应用时分配的AppSecret。*/13 @property (nonatomic, copy) NSString *client_secret;14 15 /**        true    string    请求的类型,填写authorization_code*/16 @property (nonatomic, copy) NSString *grant_type;17 18 /**        true    string    调用authorize获得的code值。*/19 @property (nonatomic, copy) NSString *code;20 21 /**        true    string    回调地址,需需与注册应用里的回调地址一致。*/22 @property (nonatomic, copy) NSString *redirect_uri;23 24 @end

YYAccessTokenParam.m文件不做额外的处理。

2.封装返回结果的类

请求成功后,新浪官方接口返回的数据为

项目中的YYAccountModel类能够处理该部分的功能,可以使用这个类来作为封装返回结果的类。

该类的实现代码:

YYAccountModel.h文件

 1 // 2 //  YYAccountModel.h 3 // 4  5 #import <Foundation/Foundation.h> 6  7 @interface YYAccountModel : NSObject <NSCoding> 8 /**access_token    string    用于调用access_token,接口获取授权后的access token。*/ 9 @property(nonatomic,copy)NSString *access_token;10 11 /**expires_in    string    access_token的生命周期,单位是秒数。*/12 @property(nonatomic,copy)NSString *expires_in;13  14 /**uid    string    当前授权用户的UID。*/15 @property(nonatomic,copy)NSString *uid;16 17 /**18  *expires_time    nsdate    access_token的过期时间。19  */20 @property(nonatomic,copy)NSDate *expires_time;21 22 /**    string    用户昵称*/23 @property(nonatomic,strong)NSString *name;24 25 +(instancetype)accountModelWithDcit:(NSDictionary *)dict;26 @end

YYAccountModel.m文件

 1 // 2 //  YYAccountModel.m 3 // 4  5 #import "YYAccountModel.h" 6  7 @implementation YYAccountModel 8 +(instancetype)accountModelWithDcit:(NSDictionary *)dict 9 {10     //注意,json中返回的数据和model中的成员属性不对应,因此不能直接使用KVC11     YYAccountModel *model=[[self alloc]init];12     model.access_token=dict[@"access_token"];13     model.expires_in=dict[@"expires_in"];14     model.uid=dict[@"uid"];15 16     17     //确定账号的过期时间= 账号创建的时间 + 有效期18     NSDate *now=[NSDate date];19     model.expires_time=[now dateByAddingTimeInterval:model.expires_in.doubleValue];20     return model;21 }22 23 /**24  *从文件中解析出一个对象的时候调用25  *在这个方法中写清楚:怎么解析文件中的数据26  */27 -(id)initWithCoder:(NSCoder *)aDecoder28 {29     if (self=[super init]) {30         self.access_token=[aDecoder decodeObjectForKey:@"access_token"];31         self.expires_in=[aDecoder decodeObjectForKey:@"expires_in"];32         self.uid=[aDecoder decodeObjectForKey:@"uid"];33         self.expires_time=[aDecoder decodeObjectForKey:@"expires_time"];34         self.name=[aDecoder decodeObjectForKey:@"name"];35     36     }37     return self;38 }39 40 /**41  *将对象写入到文件中的时候调用42  *在这个方法中写清楚:要存储哪些对象的哪些属性,以及怎样存储属性43  */44 -(void)encodeWithCoder:(NSCoder *)aCoder45 {46     [aCoder encodeObject:self.access_token forKey:@"access_token"];47     [aCoder encodeObject:self.expires_in forKey:@"expires_in"];48     [aCoder encodeObject:self.uid forKey:@"uid"];49     [aCoder encodeObject:self.expires_time forKey:@"expires_time"];50     [aCoder encodeObject:self.name forKey:@"name"];51 52 }53 @end

3.获取授权的业务处理类

注意:该类继承自YYBaseTool类

该类的代码设计:

YYAccountTool.h文件

 1 // 2 //  YYAccountTool.h 3 // 4  5 #import <Foundation/Foundation.h> 6 #import "YYAccessTokenParam.h" 7 #import "YYAccountModel.h" 8  9 @class YYAccountModel;10 @interface YYAccountTool : YYBaseTool11 /**12  *存储数据13  */14 +(void)save:(YYAccountModel *)accountModel;15 /**16  *读取数据17  */18 +(YYAccountModel *)accountModel;19 20 /**21  *  获得accesToken22  *23  *  @param param   请求参数24  *  @param success 请求成功后的回调(请将请求成功后想做的事情写到这个block中)25  *  @param failure 请求失败后的回调(请将请求失败后想做的事情写到这个block中)26  */27 +(void)accessTokenWithParam:(YYAccessTokenParam *)param success:(void (^)(YYAccountModel *result))success failure:(void (^)(NSError *error))failure;28 29 @end

YYAccountTool.m文件

 1 // 2 //  YYAccountTool.m 3 // 4  5 #define YYAccountfilePath  [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"account.data"] 6  7 #import "YYAccountTool.h" 8 #import "YYAccountModel.h" 9 10 @implementation YYAccountTool11 12 /**13  *存储数据14  */15 +(void)save:(YYAccountModel *)accountModel16 {17     //使用归档18     [NSKeyedArchiver archiveRootObject:accountModel toFile:YYAccountfilePath];19 }20 /**21  *读取数据22  */23 +(YYAccountModel *)accountModel24 {25     //解析归档数据26     //读取账号27     YYAccountModel *account = [NSKeyedUnarchiver unarchiveObjectWithFile:YYAccountfilePath];28     NSDate *now=[NSDate date];29     if ([now compare:account.expires_time]==NSOrderedDescending) {//过期30         account=nil;31     }32     return account;33 }34 35 /**36  NSOrderedAscending = -1L,  升序,越往右边越大37  NSOrderedSame, 相等,一样38  NSOrderedDescending 降序,越往右边越小39  */40 41 +(void)accessTokenWithParam:(YYAccessTokenParam *)param success:(void (^)(YYAccountModel *))success failure:(void (^)(NSError *))failure42 {43     [self postWithUrl:@"https://api.weibo.com/oauth2/access_token" param:param resultClass:[YYAccountModel class] success:success failure:failure];44 }45 @end

4.在授权控制器中获取授权

  1 //  2 //  YYOAuthViewController.m  3 //  4   5 #import "YYOAuthViewController.h"  6 #import "MBProgressHUD+MJ.h"  7 //#import "AFNetworking.h"  8 #import "YYTabBarViewController.h"  9 #import "YYNewfeatureViewController.h" 10 #import "YYControllerTool.h" 11 #import "YYAccountModel.h" 12 #import "YYAccountTool.h" 13 //#import "YYHttpTool.h" 14  15  16  17 @interface YYOAuthViewController ()<UIWebViewDelegate> 18  19 @end 20  21 @implementation YYOAuthViewController 22  23 - (void)viewDidLoad 24 { 25     [super viewDidLoad]; 26      27     //1.创建UIWebView 28     UIWebView *webView=[[UIWebView alloc]init]; 29     webView.frame=self.view.bounds; 30     [self.view addSubview:webView]; 31  32      33     //2.加载登陆界面 34     NSString *urlStr=[NSString stringWithFormat:@"https://api.weibo.com/oauth2/authorize?client_id=%@&redirect_uri=%@",YYAppKey,YYRedirectURI]; 35     NSURL *url=[NSURL URLWithString:urlStr]; 36     NSURLRequest *request=[[NSURLRequest alloc]initWithURL:url]; 37     [webView loadRequest:request]; 38      39     //3.设置代理 40     webView.delegate=self; 41 } 42  43 #pragma mark-UIWebViewDelegate 44 /** 45  *  UIWebView开始加载资源的时候调用(开始发送请求) 46  */ 47 -(void)webViewDidStartLoad:(UIWebView *)webView 48 { 49     [MBProgressHUD showMessage:@"正在努力加载中···"]; 50 } 51  52 /** 53  *  UIWebView加载完毕的时候调用(请求结束) 54  */ 55 -(void)webViewDidFinishLoad:(UIWebView *)webView 56 { 57     [MBProgressHUD hideHUD]; 58 } 59  60 /** 61  *  UIWebView加载失败的时候调用(请求失败) 62  */ 63 -(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error 64 { 65     [MBProgressHUD hideHUD]; 66 } 67  68 /** 69  *  UIWebView每当发送一个请求之前,都会先调用这个代理方法(询问代理允不允许加载这个请求) 70  *  @param request        即将发送的请求 71  *  @return YES允许加载,NO不允许加载 72  */ 73 -(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 74 { 75     //1.获得请求地址 76     NSString *urlStr=request.URL.absoluteString; 77 //    NSLog(@"%@",urlStr); 78      79     //2.判断url是否为回调地址 80     //urlStr在字符串中的范围 81     //设置从等号位置开始,不用再额外的找位置 82     NSString *redirectURI=[NSString stringWithFormat:@"%@?code=",YYRedirectURI]; 83     NSRange range=[urlStr rangeOfString:redirectURI]; 84     //判断是否为回调地址 85     if (range.location!=NSNotFound) {//是回调地址 86         //截取授权成功后的请求标记 87         int from=range.location+range.length; 88         NSString *code=[urlStr substringFromIndex:from]; 89 //        YYLog(@"%@--%@--",urlStr,code); 90          91         //根据code获得一个accessToken 92         [self accessTokenWithCode:code]; 93          94         //禁止加载回调页面,拿到想要的东西就好了。 95         return NO; 96     } 97     return YES; 98 } 99 /**100  *  根据code获得一个accessToken(发送一个Post请求)101  *  @param code 授权成功后的请求标记102  */103 -(void)accessTokenWithCode:(NSString *)code104 {105 //    //1.封装请求参数106 //    NSMutableDictionary *params=[NSMutableDictionary dictionary];107 //    params[@"client_id"] =YYAppKey;108 //    params[@"client_secret"] =YYAppSecret;109 //    params[@"grant_type"] =@"authorization_code";110 //    params[@"code"] =code;111 //    params[@"redirect_uri"] =YYRedirectURI;112 //    113 //    //2.发送网络请求114 //    [YYHttpTool post:@"https://api.weibo.com/oauth2/access_token" params:params success:^(id responseObj) {115 //        //隐藏遮罩116 //        [MBProgressHUD hideHUD];117 //        118 //        //字典转模型119 //        YYAccountModel *accountmodel=[YYAccountModel accountModelWithDcit:responseObj];120 //        //存储账号模型121 //        [YYAccountTool save:accountmodel];122 //        123 //        //3.2切换控制器124 //        [YYControllerTool chooseRootViewController];125 //    126 //        YYLog(@"请求成功");127 //128 //    } failure:^(NSError *error) {129 //        //隐藏遮罩130 //        [MBProgressHUD hideHUD];131 //        YYLog(@"请求失败");132 //    }];133     134     //1.封装请求参数135     YYAccessTokenParam *param=[[YYAccessTokenParam alloc]init];136     param.client_id=YYAppKey;137     param.client_secret=YYAppSecret;138     param.grant_type=@"authorization_code";139     param.code=code;140     param.redirect_uri=YYRedirectURI;141     142     //2.获取access_token143     [YYAccountTool accessTokenWithParam:param success:^(YYAccountModel *accountmodel) {144         //隐藏遮罩145         [MBProgressHUD hideHUD];146 147         //存储账号模型148         [YYAccountTool save:accountmodel];149 150         //切换控制器151         [YYControllerTool chooseRootViewController];152     153         YYLog(@"请求成功");154     } failure:^(NSError *error) {155         //隐藏遮罩156         [MBProgressHUD hideHUD];157         YYLog(@"请求失败");158     }];159 }160 @end

三、补充

1.结构示意图

 

新建一个基本请求参数封装类,把access_token属性抽取出来,其他的请求参数封装类继承该类。

调整项目的文件结构如下:

在请求参数中,每次请求都需要获取相同的成功授权的标记,可以考虑在基础类中进行抽取。

YYBaseParam.h文件

 1 // 2 //  YYBaseParam.h 3 // 4  5 #import <Foundation/Foundation.h> 6  7 @interface YYBaseParam : NSObject 8  9 /**access_token    false    string    采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。*/10 @property(nonatomic,copy)NSString *access_token;11 12 +(instancetype)param;13 @end

YYBaseParam.m文件

 1 // 2 //  YYBaseParam.m 3 // 4  5 #import "YYBaseParam.h" 6 #import "YYAccountTool.h" 7  8 @implementation YYBaseParam 9 -(id)init10 {11     if (self=[super init]) {12         self.access_token=[YYAccountTool accountModel].access_token;13     }14     return self;15 }16 17 +(instancetype)param18 {19     return [[self alloc]init];20 }21 @end

修改控制器中相关实现的示例: