如何使用 Reactive Cocoa + MVVM 将 json 转换为 pageVo
how to transform json to pageVo using Reactive Cocoa + MVVM
休息 return json:
{
"respCode": {
"code": 0,
"msg": "success"
},
"timestamp": 1438004437838,
"pageVo": {
"pageSize": 5,
"pageNo": 1,
"recordSize": 2,
"hasNextPage": false,
"hasPrevPage": false,
"pageTotal": 1,
"data": [
{
"id": 1,
"status": 1,
"createDate": 1437747090000,
"modifyDate": 1437748290000,
"userId": 1,
"like": 0,
"relay": 0,
"category": 0,
"lat": "133.333",
"lng": "13.999",
"user": {
"id": 1,
"nickname": "Jack",
"avatar": "http://www.xx.xxxx/xxxx/xxx.jpg"
},
"itemsPrices": [
{
"id": 1,
"status": 1,
"itemsId": 1,
"price": 188.0,
"title": "world",
"x": "123.1223",
"y": "123.4444"
},
{
"id": 2,
"status": 1,
"itemsId": 1,
"price": 188.0,
"title": "world2",
"x": "123.1223",
"y": "123.4444"
}
],
"itemsPictures": [
{
"id": 1,
"status": 1,
"itemsId": 1,
"url": "http://xxx.xxxx.xxx",
"isCover": true
},
{
"id": 2,
"status": 1,
"itemsId": 1,
"url": "http://xxx.xxxx.xxx",
"isCover": false
}
]
},
{
"id": 2,
"status": 1,
"createDate": 1437747128000,
"modifyDate": 1437748341000,
"userId": 1,
"like": 0,
"relay": 0,
"category": 0,
"lat": "133.333",
"lng": "13.999",
"user": {
"id": 2,
"nickname": "world",
"avatar": "http://www.xx.xxxx/xxxx/xxx.jpg"
},
"itemsPrices": [
{
"status": 1
}
],
"itemsPictures": [
{
"status": 1
}
]
}
],
"firstIndex": null,
"lastIndex": null
}
}
休息获取数据:
@implementation ZCAPIManager (Items)
- (RACSignal *)fetchItems {
NSString *url = @"http://localhost:8080/zc_mobile/items/list? pageNo=1&pageSize=5";
RACSignal *resultSignal = [self requestGetWithRelativePath:url parameters:nil resultClass:nil listKey:nil];
return [[resultSignal subscribeOn:[RACScheduler mainThreadScheduler]] map:^id(RACTuple *jsonAndHeaders) {
NSDictionary *jsonResult = jsonAndHeaders.first;
NSHTTPURLResponse *httpResponse = jsonAndHeaders.second;
ZCItemsViewModel *itemsViewModel = [[ZCItemsViewModel alloc] init];
ZCRespCode *respCode = [MTLJSONAdapter modelOfClass:[ZCRespCode class] fromJSONDictionary:jsonResult[ZCJSONResponseResponseCodeKey] error:nil];
itemsViewModel.respCode = respCode;
if(ZCResponseCodeSuccess == respCode.code && httpResponse.statusCode == 200) {
NSDictionary *pageVoDictionary = jsonResult[ZCJSONResponsePageVoKey];
ZCPageVo *pageVo = [MTLJSONAdapter modelOfClass:[ZCPageVo class] fromJSONDictionary:pageVoDictionary error:nil];
itemsViewModel.pageVo = pageVo;
itemsViewModel.data = [[[pageVoDictionary[ZCJSONResponseDataKey] rac_sequence] map:^id(NSDictionary *itemsDictionary) {
ZCItems *items = [MTLJSONAdapter modelOfClass:[ZCItems class] fromJSONDictionary:itemsDictionary error:nil];
return items;
}] array];
}
return itemsViewModel;
}] ;
}
@end
ViewModel:
@interface ZCBaseViewModel : RVMViewModel
@property (nonatomic, strong) ZCRespCode *respCode;
@property (nonatomic, strong) ZCPageVo *pageVo;
@end
@interface ZCItemsViewModel : ZCBaseViewModel
@property (nonatomic, strong) RACSignal *executeFetch;
@property (nonatomic, strong) NSArray *data;
@end
@interface ZCItemsViewModel : ZCBaseViewModel
@property (nonatomic, strong) RACSignal *executeFetch;
@property (nonatomic, strong) NSArray *data;
@end
单元测试/ViewController像这样:
- (void)testRequestWithMethod_new3 {
hxRunInMainLoop(^(BOOL *done) {
RACSignal *loadItems = [[[ZCAPIManager alloc] init] fetchItems];
RAC(self, itemsViewModel) = loadItems;
[loadItems subscribeNext:^(id x) {
NSLog(@"x = %@\n",x);
NSLog(@"itemsViewModel = %@", self.itemsViewModel);
*done = YES;
}];
});
}
这种方式对吗?你有没有其他方法来解决这个问题 Complex json to ViewModel.
这种方式对吗?你有其他方法来解决这个问题吗 Complex json to ViewModel.
If JSON ViewModel 内部的转换逻辑。 ViewModel 初始化方法看起来像这样?
- (instancetype) init {
if(self = [super init]) {
ZCAPIManager *apiManager = [[ZCAPIManager alloc] init];
self.executeFetch = [[[apiManager fetchItems] subscribeOn: [RACScheduler mainThreadScheduler]] map:^id(RACTuple *jsonAndHeaders) {
NSDictionary *jsonResult = jsonAndHeaders.first;
NSHTTPURLResponse *httpResponse = jsonAndHeaders.second;
ZCRespCode *respCode = [MTLJSONAdapter modelOfClass:[ZCRespCode class] fromJSONDictionary:jsonResult[ZCJSONResponseResponseCodeKey] error:nil];
self.respCode = respCode;
if(ZCResponseCodeSuccess == respCode.code && httpResponse.statusCode == 200) {
NSDictionary *pageVoDictionary = jsonResult[ZCJSONResponsePageVoKey];
ZCPageVo *pageVo = [MTLJSONAdapter modelOfClass:[ZCPageVo class] fromJSONDictionary:pageVoDictionary error:nil];
self.pageVo = pageVo;
self.data = [[[pageVoDictionary[ZCJSONResponseDataKey] rac_sequence] map:^id(NSDictionary *itemsDictionary) {
ZCItems *items = [MTLJSONAdapter modelOfClass:[ZCItems class] fromJSONDictionary:itemsDictionary error:nil];
return items;
}] array];
}
return self;
}];
}
return self;
}
做对了吗?什么是正确的做法?
让我朗朗上口一点:
- 你的测试代码订阅了这个信号两次,为什么?
- 有一个很棒的框架来测试响应式 cocoa。 Expecta + LLReactiveMatchers
- 您的测试代码发出真实的网络请求,这使您的测试速度变慢并且依赖于网络。你应该注入一些模拟 API 网络管理器。也许 DI 与 Typhoon?
- 您的代码未填充 JSON 错误
- 我不会用一种方法合并职责:发出请求和解析。这些是不同的原则。
休息 return json:
{
"respCode": {
"code": 0,
"msg": "success"
},
"timestamp": 1438004437838,
"pageVo": {
"pageSize": 5,
"pageNo": 1,
"recordSize": 2,
"hasNextPage": false,
"hasPrevPage": false,
"pageTotal": 1,
"data": [
{
"id": 1,
"status": 1,
"createDate": 1437747090000,
"modifyDate": 1437748290000,
"userId": 1,
"like": 0,
"relay": 0,
"category": 0,
"lat": "133.333",
"lng": "13.999",
"user": {
"id": 1,
"nickname": "Jack",
"avatar": "http://www.xx.xxxx/xxxx/xxx.jpg"
},
"itemsPrices": [
{
"id": 1,
"status": 1,
"itemsId": 1,
"price": 188.0,
"title": "world",
"x": "123.1223",
"y": "123.4444"
},
{
"id": 2,
"status": 1,
"itemsId": 1,
"price": 188.0,
"title": "world2",
"x": "123.1223",
"y": "123.4444"
}
],
"itemsPictures": [
{
"id": 1,
"status": 1,
"itemsId": 1,
"url": "http://xxx.xxxx.xxx",
"isCover": true
},
{
"id": 2,
"status": 1,
"itemsId": 1,
"url": "http://xxx.xxxx.xxx",
"isCover": false
}
]
},
{
"id": 2,
"status": 1,
"createDate": 1437747128000,
"modifyDate": 1437748341000,
"userId": 1,
"like": 0,
"relay": 0,
"category": 0,
"lat": "133.333",
"lng": "13.999",
"user": {
"id": 2,
"nickname": "world",
"avatar": "http://www.xx.xxxx/xxxx/xxx.jpg"
},
"itemsPrices": [
{
"status": 1
}
],
"itemsPictures": [
{
"status": 1
}
]
}
],
"firstIndex": null,
"lastIndex": null
}
}
休息获取数据:
@implementation ZCAPIManager (Items)
- (RACSignal *)fetchItems {
NSString *url = @"http://localhost:8080/zc_mobile/items/list? pageNo=1&pageSize=5";
RACSignal *resultSignal = [self requestGetWithRelativePath:url parameters:nil resultClass:nil listKey:nil];
return [[resultSignal subscribeOn:[RACScheduler mainThreadScheduler]] map:^id(RACTuple *jsonAndHeaders) {
NSDictionary *jsonResult = jsonAndHeaders.first;
NSHTTPURLResponse *httpResponse = jsonAndHeaders.second;
ZCItemsViewModel *itemsViewModel = [[ZCItemsViewModel alloc] init];
ZCRespCode *respCode = [MTLJSONAdapter modelOfClass:[ZCRespCode class] fromJSONDictionary:jsonResult[ZCJSONResponseResponseCodeKey] error:nil];
itemsViewModel.respCode = respCode;
if(ZCResponseCodeSuccess == respCode.code && httpResponse.statusCode == 200) {
NSDictionary *pageVoDictionary = jsonResult[ZCJSONResponsePageVoKey];
ZCPageVo *pageVo = [MTLJSONAdapter modelOfClass:[ZCPageVo class] fromJSONDictionary:pageVoDictionary error:nil];
itemsViewModel.pageVo = pageVo;
itemsViewModel.data = [[[pageVoDictionary[ZCJSONResponseDataKey] rac_sequence] map:^id(NSDictionary *itemsDictionary) {
ZCItems *items = [MTLJSONAdapter modelOfClass:[ZCItems class] fromJSONDictionary:itemsDictionary error:nil];
return items;
}] array];
}
return itemsViewModel;
}] ;
}
@end
ViewModel:
@interface ZCBaseViewModel : RVMViewModel
@property (nonatomic, strong) ZCRespCode *respCode;
@property (nonatomic, strong) ZCPageVo *pageVo;
@end
@interface ZCItemsViewModel : ZCBaseViewModel
@property (nonatomic, strong) RACSignal *executeFetch;
@property (nonatomic, strong) NSArray *data;
@end
@interface ZCItemsViewModel : ZCBaseViewModel
@property (nonatomic, strong) RACSignal *executeFetch;
@property (nonatomic, strong) NSArray *data;
@end
单元测试/ViewController像这样:
- (void)testRequestWithMethod_new3 {
hxRunInMainLoop(^(BOOL *done) {
RACSignal *loadItems = [[[ZCAPIManager alloc] init] fetchItems];
RAC(self, itemsViewModel) = loadItems;
[loadItems subscribeNext:^(id x) {
NSLog(@"x = %@\n",x);
NSLog(@"itemsViewModel = %@", self.itemsViewModel);
*done = YES;
}];
});
}
这种方式对吗?你有没有其他方法来解决这个问题 Complex json to ViewModel. 这种方式对吗?你有其他方法来解决这个问题吗 Complex json to ViewModel.
If JSON ViewModel 内部的转换逻辑。 ViewModel 初始化方法看起来像这样?
- (instancetype) init {
if(self = [super init]) {
ZCAPIManager *apiManager = [[ZCAPIManager alloc] init];
self.executeFetch = [[[apiManager fetchItems] subscribeOn: [RACScheduler mainThreadScheduler]] map:^id(RACTuple *jsonAndHeaders) {
NSDictionary *jsonResult = jsonAndHeaders.first;
NSHTTPURLResponse *httpResponse = jsonAndHeaders.second;
ZCRespCode *respCode = [MTLJSONAdapter modelOfClass:[ZCRespCode class] fromJSONDictionary:jsonResult[ZCJSONResponseResponseCodeKey] error:nil];
self.respCode = respCode;
if(ZCResponseCodeSuccess == respCode.code && httpResponse.statusCode == 200) {
NSDictionary *pageVoDictionary = jsonResult[ZCJSONResponsePageVoKey];
ZCPageVo *pageVo = [MTLJSONAdapter modelOfClass:[ZCPageVo class] fromJSONDictionary:pageVoDictionary error:nil];
self.pageVo = pageVo;
self.data = [[[pageVoDictionary[ZCJSONResponseDataKey] rac_sequence] map:^id(NSDictionary *itemsDictionary) {
ZCItems *items = [MTLJSONAdapter modelOfClass:[ZCItems class] fromJSONDictionary:itemsDictionary error:nil];
return items;
}] array];
}
return self;
}];
}
return self;
}
做对了吗?什么是正确的做法?
让我朗朗上口一点:
- 你的测试代码订阅了这个信号两次,为什么?
- 有一个很棒的框架来测试响应式 cocoa。 Expecta + LLReactiveMatchers
- 您的测试代码发出真实的网络请求,这使您的测试速度变慢并且依赖于网络。你应该注入一些模拟 API 网络管理器。也许 DI 与 Typhoon?
- 您的代码未填充 JSON 错误
- 我不会用一种方法合并职责:发出请求和解析。这些是不同的原则。