CODING iPad 客户端源代码
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
CodingForiPad.xcodeproj
CodingForiPad.xcworkspace
CodingForiPad
CodingForiPadTests
Pods pod 里面platform的设置与应用支持版本的设置不一致的bug Sep 24, 2015
.gitattributes
.gitignore
License
Podfile
Podfile.lock
README.md
bootstrap

README.md

#Coding-iPad客户端说明

Just run it!

想要看看 iPad 版本什么样,没问题! clone 或者下载代码后,初次执行时,双击根目录下的 bootstrap 脚本,该脚本会准备初始数据,完成后会打开工程,点击 Xcode 运行!So easy,妈妈再也不用担心我的代码编译出错了!(之后只需打开 CodingForiPad.xcworkspace 即可)

嗯……,你的代码好像很棒,请告诉我xx是怎么做的

先告诉大家代码大概在哪里。

.
├── 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](http://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 目录下是与业务比较相关的请求和模型,这样做是为了使数据请求和模型与业务逻辑无关,保证这部分代码能够复用。

很好,我也要写一个这么棒的Coding客户端

没问题,现在来告诉大家,怎么复用代码。

不过,略微有点遗憾,由于项目比较紧张,当前只有网络请求和 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