如何使用 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;
}

做对了吗?什么是正确的做法?

让我朗朗上口一点:

  1. 你的测试代码订阅了这个信号两次,为什么?
  2. 有一个很棒的框架来测试响应式 cocoa。 Expecta + LLReactiveMatchers
  3. 您的测试代码发出真实的网络请求,这使您的测试速度变慢并且依赖于网络。你应该注入一些模拟 API 网络管理器。也许 DI 与 Typhoon?
  4. 您的代码未填充 JSON 错误
  5. 我不会用一种方法合并职责:发出请求和解析。这些是不同的原则。