iOS开发--利用NSProxy实现消息转发-模块化的网络接口层设计
来源:互联网 发布:unity3d小游戏制作视频 编辑:程序博客网 时间:2024/05/20 22:30
前言
之前在做项目的时候,所有业务的网络接口方法,全部都写在了一个文件里面,一开始还好,毕竟每个方法的代码也只是十几行,增加、修改也比较容易。但是随着接口的增多,这个文件慢慢居然超过了1000行,里面几十个方法都写在一起,实在是不好维护。
虽然保持这样也没有什么,多用用Cmd+F就能找到。但是,真是越看越不顺眼
Github 示例
贴上本文中的示例工程:https://github.com/zekunyan/HttpProxyExample
问题
先抛出问题。
一款互联网应用,免不了要跟服务器打交道,在iOS项目中,最有名的网络库应该就是AFNetworking了。所以,很多人就会利用AFnetworking提供的Get、Post等基本Http请求接口,封装自己的网络接口层代码,我自己在项目中也是这么做的。
但是,AFNetworking只是提供了Get、Post、Json传输等基本的Http请求方法,所以一旦落实到具体的业务相关的请求上,我们要为每个请求(URL)都写一个单独的接口方法。
那么,问题就来了
业务相关的接口那么多,举个例子,什么“通过用户ID获取用户基本信息”、“获取用户的所有评论”等,每个请求都是一个方法,这么多方法该怎么组织呢?全部放在一起?那这个接口类岂不是会非常乱?不放在一起?那岂不是会有很多个网络请求类?(至于要不要统一接口入口,我想这个根据项目来决定吧=。=)
需求
- 所有网络接口都从统一的类调用,如HttpProxy。
- 网络接口的具体实现,按照业务划分到不同的类中,如“UserHttpHandler”、“CommentHttpHandler”。
其实,按照面向对象的原则,就是接口代理类HttpProxy拥有若干个按照业务划分的接口(Interface),这些接口的所有方法组成了网络层的不同的Http请求。如下图:
那么,调用的时候,所有接口都用HttpProxy调用,如:
//实际调用的是UserHttpHandler类的方法[[HttpProxy sharedInstance] getUserWithID:@100];//实际调用的是CommentHttpHandler类的方法[[HttpProxy sharedInstance] getCommentsWithDate:date];
关键
根据前面的描述,我们可以得出,关键就是:消息转发(Message Forward)
Objective-C里面没有我们传统的“方法调用”,取而代之的是“消息”,所有的方法都是通过向对象发送“消息”实现调用的。而这个机制,也就为我们的实现提供了方便。
也就是说:我们要将发给“HttpProxy”的消息,让HttpProxy转发给真正能接受这个消息的对象,HttpProxy就是个代理。
苹果已经给我们提供了这个“代理”类了-NSProxy。
NSProxy
什么是NSProxy:
- NSProxy没有父类,是顶级类(根类),跟NSObject同等地位。
- NSProxy和NSObject都实现了“NSObject Protocol”。
- NSProxy设计时就是以“抽象类”设计的,专门为转发消息而生。
实现要求:
- 继承NSProxy的子类要实现自己的初始化方法,如“init”、“initWith”。
- 重写“ - forwardInvocation: ”和“ - methodSignatureForSelector: ”方法,完成消息转发。
详细内容参考Apple的文档。
实现
定义
先不管HttpProxy,咱们看看具体的接口,先举两个例子:
//UserHttpHandler.h//用户相关接口@protocol UserHttpHandler <NSObject>- (void)getUserWithID:(NSNumber *)userID;@end//CommentHttpHandler.h//评论相关接口@protocol CommentHttpHandler <NSObject>- (void)getCommentsWithDate:(NSDate *)date;@end
好的,接口有了,我们的HttpProxy类应该“实现”了这两个接口。
然后,最好是单例类,所以还要有个获取单例的方法。
最后,还需要一个向HttpProxy注册具体实现了接口Protocol的方法。
所以,HttpProxy应该是这个样子的:
//HttpProxy.h//1. 继承了NSproxy。 2. “实现”了网络接口Protocol@interface HttpProxy : NSProxy <UserHttpHandler, CommentHttpHandler>//获取单例+ (instancetype)sharedInstance;//注册具体实现类- (void)registerHttpProtocol:(Protocol *)httpProtocol handler:(id)handler;@end
找到消息对应的实现类对象
如何在HttpProxy做消息转发时,找到某个消息对应的真正的实现类对象呢?
最好的办法就是保存每个接口方法到其实现类对象的映射,可以用Dictionary保存,关系如下图:
所以,registerHttpProtocol:handler:方法的职责就是:
- 遍历Protocol的所有方法(利用Objective-C的Runtime功能)。
- 保存Protocol所有方法到实现类的对象的映射关系。(用方法的字符串表示作为key,实现类对象为value)
所以,HttpProxy应该持有一个Dictionary的实例,用于保存映射关系,HttpProxy的实现部分如:
//HttpProxy.m@interface HttpProxy ()//保存映射关系的字典。@property(strong, nonatomic) NSMutableDictionary *selToHandlerMap;@end
注册方法实现如下:
- (void)registerHttpProtocol:(Protocol *)httpProtocol handler:(id)handler { unsigned int numberOfMethods = 0; //Get all methods in protocol struct objc_method_description *methods = protocol_copyMethodDescriptionList( httpProtocol, YES, YES, &numberOfMethods); //Register protocol methods for (unsigned int i = 0; i < numberOfMethods; i++) { struct objc_method_description method = methods[i]; [_selToHandlerMap setValue:handler forKey:NSStringFromSelector(method.name)]; }}
实现消息的转发
我们已经可以注册接口、保存映射关系了,剩下的就是重写NSProxy的两个方法,以实现消息的转发,至于这两个方法具体作用是什么,读者可以自行查阅相关资料。如下:
//HttpProxy.m//获取Method signature- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel { //获取method的字符串表示 NSString *methodsName = NSStringFromSelector(sel); //查找对应实现类对象 id handler = [_selToHandlerMap valueForKey:methodsName]; //再次检查handler是否可以相应此消息 if (handler != nil && [handler respondsToSelector:sel]) { return [handler methodSignatureForSelector:sel]; } else { return [super methodSignatureForSelector:sel]; }}//转发方法消息- (void)forwardInvocation:(NSInvocation *)invocation { NSString *methodsName = NSStringFromSelector(invocation.selector); id handler = [_selToHandlerMap valueForKey:methodsName]; if (handler != nil && [handler respondsToSelector:invocation.selector]) { [invocation invokeWithTarget:handler]; } else { [super forwardInvocation:invocation]; }}
Example
看看如何使用HttpProxy:
//初始化,注册Protocol对应的实现类对象[[HttpProxy sharedInstance] registerHttpProtocol:@protocol(UserHttpHandler) handler:[UserHttpHandlerImp new]];[[HttpProxy sharedInstance] registerHttpProtocol:@protocol(CommentHttpHandler) handler:[CommentHttpHandlerImp new]];//调用[[HttpProxy sharedInstance] getUserWithID:@100];[[HttpProxy sharedInstance] getCommentsWithDate:[NSDate new]];
总结
所有的代码及示例都提交到Github了,HttpProxyExample。
总的来说,就是利用Objective-C的“消息”机制,继承NSProxy抽象类,实现自己定义的转发机制,将网络接口层的各个方法的实现与声明分离,提升项目代码的可维护性,更加模块化。如下图表示:
以上,就是我自己在项目中,利用NSProxy设计并实现的网络接口层结构。
本文转载自: http://www.jianshu.com/p/1bde36ad9938
- iOS开发--利用NSProxy实现消息转发-模块化的网络接口层设计
- 利用NSProxy实现消息转发-模块化的网络接口层设计
- [iOS]使用NSProxy实现消息转发机制,模拟多重继承
- [iOS]使用NSProxy实现消息转发机制,模拟多重继承
- [iOS]使用NSProxy实现消息转发机制,模拟多重继承
- NSProxy实现代理(消息转发)
- 使用NSProxy实现消息转发机制,模拟多重继承
- NSProxy与消息转发机制
- iOS中消息转发的实现
- 利用OC的消息转发机制实现多重代理
- RxSwift Runtime分析(利用OC消息转发实现IOS消息拦截)<原理同ReactiveCocoa>
- iOS的动态创建实例方法和实现消息转发
- Ios的消息转发机制
- iOS的消息转发机制
- iOS 开发中界面层与网络相关的部分通用功能的的设计
- iOS开发 -- Objective-C 消息转发
- iOS开发 之 消息转发机制
- ios-NSProxy
- Java_socket程序学习0501-彩票销售-第一阶段server端整理-成功
- 职业女性确实处于劣势吗?记一次不甚严谨的考据 -- 向胡适之先生的遥远致敬
- Cocos2d-x_Box2D刚体使用PhysicsEditor工具生成形状
- 2011年哈尔滨工业大学计算机研究生机试真题
- WCF实例上下文与并发
- iOS开发--利用NSProxy实现消息转发-模块化的网络接口层设计
- hdu 2610 Sequence one ( dfs+可行性剪枝 )
- 动态规划-阿里笔试
- Spark集群资源调度
- 关于++i与i++以及静态成员变量与非静态成员变量新手疑惑的地方
- 汤米维斯提
- 最长回文子串的长度 南邮NOJ 1968
- 得到UIWebView内视频播放器弹出和关闭的通知
- Linux C++ 简单线程池