#Coding-iPad客户端说明
想要看看 iPad 版本什么样,没问题! clone 或者下载代码后,初次执行时,双击根目录下的 bootstrap 脚本,该脚本会准备初始数据,完成后会打开工程,点击 Xcode 运行!So easy,妈妈再也不用担心我的代码编译出错了!(之后只需打开 CodingForiPad.xcworkspace 即可)
先告诉大家代码大概在哪里。
.
├── CodingForiPad
│ ├── Vendor:因为各种原因没有用Pods管理的第三方库
│ ├── Resources:资源文件
│ ├── Util:一些工具类,Category等
│ ├── Request:网络请求
│ ├── Models:数据模型,一般一个网络请求会对应一个model
│ ├── RequestExt:请求的业务扩展,用于分离基本请求以便于复用代码
│ ├── ModelsExt:数据模型的业务扩展,用于分离基本模型以便于代码复用
│ ├── Manager:一些单例
│ │ ├── AddressManager:iPhone版本代码
│ │ ├── Coding_FileManager:文件上传(iPhone版本代码)
│ │ ├── COSession:登录用户管理
│ │ ├── COUnReadCountManager:读信息、私信管理
│ │ ├── ImageSizeManager:iPhone版本代码
│ │ ├── JobManager:iPhone版本代码
│ │ ├── StartImagesManager:iPhone版本代码
│ │ ├── TagsManager:iPhone版本代码
│ │ └── WebContentManager:格式化为网页使用,iPhone版本代码
│ └── ViewController
│ ├── Style:基本样式,颜色等
│ ├── Custom:一些自定义的View
│ ├── Base:基本Controller
│ ├── User:用户资料相关的UI
│ ├── Project:项目相关的UI
│ ├── Task:任务相关的UI
│ ├── Tweet:冒泡相关的UI
│ ├── Message:消息和私信相关的UI
│ └── Setting:设置相关的UI
└── Pods:项目使用了[CocoaPods](https://code4app.com/article/cocoapods-install-usage)这个类库管理工具
有两个比较隐蔽的问题,需要说明一下。首先,Coding 上部分资源是WebP格式,使用 SDWebImage 时,需要加入 WebP.framework;另外,在 Coding 的一些图片需要验证 Cookie 的,所以,在使用 SDWebImage 时,注意启用 Cookie,增加 SDWebImageHandleCookies 选项,代码如下所示:
[self.regCodeImageView sd_setImageWithURL:[NSURL URLWithString:url] placeholderImage:nil options:SDWebImageRetryFailed | SDWebImageHandleCookies | SDWebImageRefreshCached completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (error) {
dispatch_async(dispatch_get_main_queue(), ^{
weakself.regCodeImageView.image = [UIImage imageNamed:@"captcha_loadfail"];
});
}
}];
iPad 客户端使用了 Storyboard,所以在代码阅读上,建议先从 Storyboard 开始,了解整个项目的脉络(由于项目比较大,打开 Storyboard 项目的速度取决于机器的配置,Orz)。另外从 UI 来入手也比较直观,在 Storyboard 中也可以直接看到 UI 对应的 Controllor。
关于 ViewControllerr目录的组织基本是按照 UI 上展现来组织的,比如 Tweet 目录,主要是存放冒泡相关实现的代码,而其所对应的网络请求和 Models 也都是 COTweet 开头,这样大家很容易提纲挈领从一点贯通全面。
RequestExt 和 ModelsExt 目录下是与业务比较相关的请求和模型,这样做是为了使数据请求和模型与业务逻辑无关,保证这部分代码能够复用。
没问题,现在来告诉大家,怎么复用代码。
不过,略微有点遗憾,由于项目比较紧张,当前只有网络请求和 Model 可以轻松复用。
首先,再讲一个隐蔽的问题,关于用户登录!Coding 的用户验证是通过 Cookie 来验证的,所以问题来了,如果你直接调用登录接口,会发现登录成功了,但是访问其他接口会提示用户未登录,为什么呢,因为 Cookie 没有存储,为什么没有存储,因为你在登录之前没有请求验证码接口。所以,再你调用登录接口之前,必须先请求验证码接口!!!必须先请求验证码接口!!!必须先请求验证码接口!!!(重要的事情说三遍)
网络请求时基于 AFNetworking 的,稍微封装了一下,所有接口请求都是继承于 CODataRequest。 Coding 是 RestFul 接口,HTTP 请求除了GET、POST,之外还有 PUT 和 DELETE 方法,所以在 CODataRequest 实现了上述四种基本请求方法。一个接口可能既支持 GET,也支持 DELETE,所需要的参数不尽相同。因此,我定义了几个指示说明性的宏来标识请求和参数,如下所示:
#define COQueryParameters // Get 参数
#define COUriParameters // URI 参数
#define COFormParameters // Post 参数
#define COGetRequest /** Get请求 */
#define COPostRequest /** Post请求 */
#define COPutRequest /** Pust请求 */
#define CODeleteRequest /** Delete请求 */
以用户登录接口为例:
COPostRequest
@interface COAccountLoginRequest : CODataRequest
@property (nonatomic, copy) COFormParameters NSString *email;
@property (nonatomic, copy) COFormParameters NSString *password;
@property (nonatomic, copy) COFormParameters NSString *jCaptcha;
@property (nonatomic, copy) COFormParameters NSString *rememberMe;
@end
COPostRequest 表示这个接口是 POST 接口,调用的时候需要执行 postWithSuccess 方法;
COFormParameters 表示参数是 Post 使用的参数;
####请求实现 CODataRequest 将一个请求分为了四个阶段,请求准备,参数填充,完成准备,发起请求,数据解析。如果需要实现一个新请求,正常来说,需要完成请求准备和参数填充两个阶段,一般来说在准备阶段我们主要设置请求的 path,代码如下所示:
- (void)prepareForRequest
{
self.path = @"/login";
}
参数准备主要是建立参数映射字典,将请求的参数映射为对应的接口参数,代码如下:
- (NSDictionary *)parametersMap
{
return @{
@"email" : @"email",
@"password" : @"password",
@"rememberMe" : @"remember_me",
@"jCaptcha" : @"j_captcha",
};
}
其中 key 是请求的属性,对应的 value 是接口的参数名。
数据解析阶段是将接口返回的 JSON 封装为 CODataResponse 对象,并将数据映射成对应的 Model,代码如下:
- (CODataResponse *)postResponseParser:(id)response
{
return [[CODataResponse alloc] initWithResponse:response dataModleClass:[COUser class] responseType:CODataResponseTypeDefault];
}
还有一个完成准备的阶段,这是表示,参数准备就绪,可以开始了,这时,我们可能还需要做一些事情,比如我封装了一个 COPageRequest,所有分页请求的数据都继承于它,让我们看看,它是怎么做的:
- (void)readyForRequest
{
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:self.params];
[params setObject:@(self.page) forKey:@"page"];
[params setObject:@(self.pageSize) forKey:@"pageSize"];
self.params = [NSDictionary dictionaryWithDictionary:params];
}
COPageRequest 使用了 readyForRequest,将 page 和 pageSize 两个参数追加到参数映射中,这样其他的分页请求就不需要在参数映射中写这两个参数了。
数据模型采用了Mantle将 JSON 映射为对象。来看一个简单的列子:
@interface COFileCount : MTLModel<MTLJSONSerializing>
@property (nonatomic, assign) NSInteger folderId;
@property (nonatomic, assign) NSInteger count;
@end
@implementation COFileCount
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return @{@"folderId" : @"folder",
@"count" : @"count",
};
}
@end
是不是有些熟悉?没错,网络请求也参考了 Mantle 的实现。同样的 JSONKeyPathsByPropertyKey 中,key 对应的是 Model 的属性,value 对应的是 JSON 中的数据名。
复杂模型的建立,请详细参考 Mantle 的文档。
CODataResponse 是请求于模型之间的桥梁。CODataResponse 封装了整个网络请求返回数据,包含了code、msg、error以及数据等。所以,一个网络请求返回后,我们需要先检查 CODataResponse 中的 code,如果 code 为0,则表示请求 OK,然后还需要判断 error,这个 error主要是我们解析数据时产生的错误,多数是模型建立的不对,或者接口模型调整导致的。
因为 Coding 的接口返回比较规范,主要是三种形式,字典,列表和 Pageable,因此 CODataResponse 封装了这三种形式的数据解析,解析数据变的非常简单,代码如下所示:
- (CODataResponse *)postResponseParser:(id)response
{
return [[CODataResponse alloc] initWithResponse:response dataModleClass:[COUser class] responseType:CODataResponseTypeDefault];
}
这是用户登录接口的数据解析,是不是很容易?
拷贝 Request 和 Model 目录到你的项目中,在 Podfile 中添加如下两行:
pod 'AFNetworking'
pod 'Mantle'
代码复用从未如此轻松……
你可以专注于 UI 和交互了,去写一个牛闪闪的 Coding 客户端吧!
#License MIT