当前位置: 首页 > news >正文

html5教育网站百度指数怎么看排名

html5教育网站,百度指数怎么看排名,个人网站建设策划书,什么是网络营销战略?网络营销战略的内容有哪些?在上一篇《MCCSframework 教程(一)介绍》中,我们介绍了一个“不那么复杂”的例子。在这个例子中,我们搜索商品时使用了 mock (模拟)数据。在真实项目中,这当然是不可能的。APP 的数据一般来自于…

在上一篇《MCCSframework 教程(一)介绍》中,我们介绍了一个“不那么复杂”的例子。在这个例子中,我们搜索商品时使用了 mock (模拟)数据。在真实项目中,这当然是不可能的。APP 的数据一般来自于网络,而MCCSframework 作为一个 APP 构建框架而不仅仅是 UI 框架,当然也包含了网络 API。

框架提供的网络 API

框架提供了一个分类 NSObject+AFN。对于常规的 HTTP JSON 接口,它提供了两个方法:

-(RACSignal*)dataFromUrl:(NSString*)urlmethod:(NSString*)methodparams:(NSDictionary*)paramstoken:(NSString*)tokenerrorFilter:(Class<JSONResponseErrorFilter>)validatordataClass:(Class)dataClassparseBlock:(id (^)(id data,id resp,NSError** error))parseBlock;
-(RACSignal*)dictionaryFromUrl:(NSString*)urlmethod:(NSString*)methodparam:(NSDictionary*)paramtoken:(NSString*)tokenerrorFilter:(Class<JSONResponseErrorFilter>)validator;

dataFromUrl 方法

NSObject+AFN 使用了 ReactiveObjC 框架,方法返回结果已经封装为 RAC 信号,方便你以响应式的方式调用。

首先是 dataFromUrl 方法。这个方法会比第二个方法要做更多的工作,它会把接口返回的 JSON 中的 data 数据取出来发送(调用 sendNext:方法) 给你。如果在这个过程中有任何错误,则发送一个错误(调用 sendError:)。它需要的参数较多,前 4 个参数不用解释,一看就懂。特别的是后面这 3 个参数:

errorFilter 参数

这是一个实现了 JSONResponseErrorFilter 协议的类(注意是类,不是对象)。这个类起一个“错误过滤器”的作用,负责过滤在解析 Response 过程中出现的各种错误,最终返回一个 NSDictionary 对象给你。

JSONResponseErrorFilter 协议在 APIError.h 中定义:

@protocol JSONResponseErrorFilter <NSObject>
+ (id)dictionaryWithResponse:(id)responseObj;// 获取 NSDictionary,如有错误返回错误
+ (id)dataWithResponse:(NSDictionary*)responseDic;// 获取 data 字段,如有错误返回错误
@end

注意,APIError 类也实现了该协议。

这些方法用于描述每种错误应当如何识别和定义。比如用户未登录错误,token 过期等。这些错误对于不同的项目会有不同的定义,在实际项目中,你应该创建自己的 JSONResponseErrorFilter 类,然后根据业务定义来实现这两个方法。例如,你可以这样实现 dictionaryWithResponse 方法:

+(id)dictionaryWithResponse:(id)responseObj{if([responseObj isKindOfClass:NSString.class]){NSString* str = (NSString*)responseObj;if([str containsString:@"please to login"]||[str containsString:@"Request failed: unauthorized (401)"]){return [APIError noLoginError];// 915:未登录}else if([str containsString:@"This request token is expired"]){return [APIError tokenInvalid];// 916:token 无效}return str;}else if([responseObj isKindOfClass:NSDictionary.class]){NSDictionary* responseDic =(NSDictionary*)responseObj;NSNumber* code = responseDic[@"code"];// 如果 code 字段的 key 不是 'code',修改此处NSNumber* succeed = responseDic[@"succeed"];// 如果 succeed 字段的 key 不是 'succeed',修改此处NSString* msg = responseDic[@"msg"];// 如果 msg 字段的 key 不是 'msg',修改此处if([code isEqual:@404]){return [APIError http404Error];// 918: HTTP 404 错误}if([msg containsString:@"Request failed: unauthorized (401)"]){return [APIError noLoginError];// 915:未登录}if(![code isEqual: @0] || succeed.boolValue==NO){return stringIsEmpty(msg) ? [APIError statusFailedError]: [NSError errorWithDomain:@"APIError" code:919 userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%@:%@",code,msg]}];// 919:后台返回状态异常}return responseDic;}else{// NSString 和 NSDictionary 以外的类型不接受return [APIError dataParseError];// 913: 服务器返回的数据类型无法解析}
}

在这个方法中,你可以识别出后台返回的 response 中包含的各种错误,以上面的代码为例,它主要拦截了以下错误:

  1. 用户未登录

    如果后台接口直接返回 “please to login” 或 “Request failed: unauthorized (401)” 字符串,那么说明用户未登录。

  2. token 过期

    而当后台接口直接返回 “This request token is expired” 字符串,则表明 token 过期了。

    上述两种错误,后台返回的数据格式都是字符串,而不是 JSON。对于后台来说, JSON 接口本来不应该返回除 JSON 以外的数据格式,但在实际开发过程中移动端经常会碰到这种操蛋的问题,这其实是因为后台缺乏经验或粗心大意导致的。你无法确定自己会不会碰到这样的后台开发人员,所以你必须多做一些工作,在自己的代码中防范此类问题。

  3. 404 错误

    后台有时候会把 HTTP 返回码在 JSON 中返回。404 是一种比较特殊的错误,一般表示 url 地址不存在或者错误,因此需要单独列出,以便你能够检查是不是接口地址写错了。

  4. 后台返回不成功状态的错误

    一般后台返回的 JSON 中会有一个状态表示请求是否成功。但很多时候,后台还会用一个返回码(code)和简短信息(msg)表示具体失败的原因是什么。这也是我们唯一能“真正理解”为什么出错的地方。

  5. data 字段缺失错误

    这种错误就真的是由于后台的粗心大意了。在某些时候,后台返回的结果中直接就缺少了 data 字段。当然,data 字段的 key 不一定总是叫 “data”,只要你知道要到哪里查找想要的数据,那么把它替换成什么名字都可以。

dataWithResponse 方法的实现则比较简单,返回 data 字段中存储的对象就可以了,如果 data 字段缺失,返回一个错误:

/// 获取 data 字段,如缺失返回 dataNilError
+ (id)dataWithResponse:(NSDictionary*)responseDic{id dataObj = responseDic[@"data"];// 如果 data 字段的 key 不是 'data',修改此处if(dataObj==nil)return [APIError dataNilError];// 911:data 字段缺失elsereturn dataObj;
}

dataClass 参数

你必须指定 data 字段的类型。通常后台返回的 JSON 字符串中,查询结果会放在 data 字段中。但根据要查询的数据不同,data 字段有可能被解析为多种类型:字典、数组、字符串。具体讲:

  • 如果前端是通过唯一ID来查询,那么后台只可能会查询到单条记录,而且后台很可能直接将这条记录放到 data 字段,那么 data 字段就应该被解析为一个 NSDictionary 类型。
  • 如果前端根据其他条件查询,那么后台查询结果可能是多条记录,那么后台很可能会在 data 字段中放入数组,前端应当把 data 字段识别为 NSArray 类型。
  • 很少的情况下,后台会直接在 data 字段中放入字符串,比如一个 token 值。那么 dataClass 参数应当指定为 NSString 类型。

parseBlock 参数

data 字段的具体解析过程在这个 block 中进行。在 MCCSframework 中,网络请求大部分代码已经封装好,我们唯一需要关心的部分就是数据的解析。在 dataParseBlock 块中,我们可以对 JSON 字符串中的 data 字段进行解析,其实在这个块中的代码通常都是非常简单的,一般只有 2 行代码,比如:

GoodsTypeDetail *detail = [[GoodsTypeDetail alloc]initWithDictionary:data error:error];
return detail;

dictionaryFromUrl 方法

第二个方法是 dictionaryFromUrl 方法,它比起第一个方法来省略了后两个参数。因为在某些情况下,我们对服务器的请求不是查询而是更新操作时,我们并不需要关心 data 字段的内容,也不需要对它进行解析,这样 dataClass 和 dataParseBlock 参数就可以省略了。比如删除或修改某条记录时。

其它方法

对于一般的 JSON 格式的网络接口,上面两个方法足够使用。如果接口的数据格式不是 JSON,或者上两个方法不能满足你的使用,那么 NSObject+AFN 还提供了另外两个非RAC 信号封装的、使用传统 block 回调的方法,可以满足你对任意 HTTP/HTTPs 接口的调用:

-(NSURLSessionDataTask*)postUrl:(NSString *)urlparams:(id)paramsheaders:(NSDictionary<NSString *,NSString*>*)headersrequestType:(NSString *)requestType success:(void (^)(NSURLSessionDataTask *task, id responseObject))successfailure:(void (^)(NSURLSessionDataTask* task, NSError *error))failure;
-(NSURLSessionDataTask*)getUrl:(NSString*)urlparams:(NSDictionary<NSString *,id>*)paramsheaders:(NSDictionary<NSString *,NSString*>*)headerssuccess:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))successfailure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

这两个方法分别用于 HTTP/HTTPs 的 POST 和 GET 请求。

封装 NSObject+AFN

为了便于使用,我们可以在框架提供的 API 的基础上进一步封装网络接口。进一步的封装需要根据项目的具体业务进行调整,不同的项目其封装代码可能不一样。这里我们演示一个具体的例子,你可以根据自己的项目需求进行调整。

新建一个分类 NSObject+RAC_HTTP,声明两个方法。定义如下:

#import <ReactiveObjC.h>@interface NSObject (RAC_HTTP)// 需要解析 data JSON 的调用此 API
-(RACSignal*)signalFromUrl:(NSString*)url method:(NSString*)method params:(NSDictionary*)params dataClass:(Class)dataClass dataParseBlock:(id (^)(id data,id resp,NSError** error))dataParseBlock;
// 不需要解析 data JSON 的调用此 API
-(RACSignal*)signalFromUrl:(NSString*)url method:(NSString*)method params:(NSDictionary*)params;
@end

这两个方法分别在 NSObject+AFN 分类的 dataFromUrl 方法和 dictionaryFromUrl 方法基础上进行了封装,进一步减少了 token 参数和 validator 参数。

NSObject+RAC_HTTP 分类的实现如下:

#import "NSObject+RAC_HTTP.h"
#import <MCCSframework/NSString+Add.h>
#import <MCCSframework/NSObject+AFN.h>
#import <MCCSframework/Utils.h>
#import <MCCSframework/APIError.h>
#import "BaseModel.h"
#import "AppDelegate.h"
#import <MCCSframework/APIError.h>@implementation NSObject (RAC_HTTP)// 需要解析 data 字段的调用此方法
-(RACSignal*)signalFromUrl:(NSString*)url method:(NSString*)method params:(NSDictionary*)params dataClass:(Class)dataClass dataParseBlock:(id (^)(id data,id resp,NSError** error))dataParseBlock{NSString* token = appDelegate.auth.token;RACSignal* signal = [self dataFromUrl:url method:method params:params token:token errorFilter:APIError.class dataClass:dataClass parseBlock:dataParseBlock];return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {return [signal subscribeNext:^(id x) {[subscriber sendNext:x];[subscriber sendCompleted];} error:^(NSError * _Nullable error) {if(error.code == 916 || error.code == 915){// 拦截 token 无效的错误[appDelegate gotoLoginVC];}else{[subscriber sendError:error];}}];}];
}
// 不需要解析 data 字段的调用此方法
-(RACSignal*)signalFromUrl:(NSString*)url method:(NSString*)method params:(NSDictionary*)params{NSString* token = appDelegate.auth.token;RACSignal* signal = [self dictionaryFromUrl:url method:method param:params token:token errorFilter:APIError.class];return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {return [signal subscribeNext:^(NSDictionary* x) {NSError* error;BaseModel* bm = [[BaseModel alloc]initWithDictionary:x error:&error];if(error){[subscriber sendError:APIError.dataParseError];}else if(bm.code == 0){[subscriber sendNext:bm];[subscriber sendCompleted];}} error:^(NSError * _Nullable error) {if(error.code == 916 || error.code == 915){// 拦截 token 无效的错误[appDelegate gotoLoginVC];}else{[subscriber sendError:error];}}];}];
}
@end

要在你自己的工程中使用该分类,需要对代码进行一些修改。例如:

  1. 错误处理

    注意这一句,if(error.code == 916 || error.code == 915),这是因为当 token 过期或无效时,一般情况下,服务器后台会返回 915/916 错误,所以这里需要引导用户回到登录页重新登录。但对于不同的服务器后台,这个情况可能会不一样,因此你可能需要修改这部分的代码。

    此外,注意这一句:

     RACSignal* signal = [self dataFromUrl:url method:method params:params token:token validator:APIError.class dataClass:dataClass parseBlock:dataParseBlock];
    

    validator 参数我们使用的是 APIError 类,这是框架默认的错误定义类。实际上你应该在这里替换成自己的 JSONResponseErrorFilter 协议实现类,因为每个项目中对于接口错误的定义是不一样的。

  2. BaseModel 类

    一个 JKModel 子类。对于一般的后台而言,它们返回的 JSON 格式是基本固定的,比如都是这样的:

    {
    "succeed": true,
    "code": 0,
    "msg": "查询成功",
    "data": ...
    }
    

    唯一会变化的可能是 data 字段,根据不同的查询 data 字段会返回不同类型的数据:字典、数组或字符串。
    因此 BaseModel 会定义成这样:

     @interface BaseModel : JKModel@property (strong, nonatomic) NSString* msg;@property(assign, nonatomic) NSInteger code;@property(assign, nonatomic) BOOL succeed;@end
    

    其中 3 个固定字段都定义在 BaseModel 中了。因此在第一个方法中,可以先解析出 BaseModel,然后将 data 字段传给 dataParseBlock 块去解析。

    BaseModel 不需要定义 data 属性,因为不关心 data 字段,data 字段的解析交给 dataParseBlock 块进行解析。

  3. token

    注意这句 NSString* token = appDelegate.auth.token;,当用户登录成功后,我们会把 token 保存到 AppDelegate 的 auth 属性中,因此我们可以通过 AppDelegate 的 auth.token 访问到它。你的项目也许会将 token 存放在不同的地方,因此这里的代码也需要根据实际情况进行修改。

使用 NSObject+RAC_HTTP 请求服务器数据

以上一篇中的二级分类商品列表为例。假设后台给我们的接口是这样的:

因为这个接口支持分页数据,因此参数中除了二级分类 ID 外,还会有 2 个分页相关数据:

  • pageSize 页大小
  • pageCurrent 页码

那么我们可以编写查询这个接口的方法:

#import <MCCSframework/NSObject+toDictionary.h>@implementation MallAPI
+(RACSignal*)goodsPageList:(GoodsQuery*)query{NSString* url = @"http://127.0.0.1/mallProductsInfo/getProductList";return [self signalFromUrl:url method:@"post" params:[query toDictionary:query containSuper:YES] dataClass:[NSDictionary class] dataParseBlock:^id(id data, id resp, NSError *__autoreleasing *error) {GoodsPage* page = [[GoodsPage alloc]initWithDictionary:data error:error];return page;}];
}
@end

其中 GoodsQuery 封装了查询参数:

@interface GoodsQuery : NSObject@property(assign, nonatomic) NSInteger pageCurrent;// 页号
@property(assign, nonatomic) NSInteger pageSize;// 页大小
@property (strong, nonatomic) NSString* categoryId;// 分类Id@end

GoodsPage 封装了对 data 字段解析后的对象:

#import <UIKit/UIKit.h>
#import <MCCSframework/JKModel.h>@class Goods;@interface GoodsPage : NSObject
@property(assign, nonatomic) NSInteger size;// 页大小
@property(assign, nonatomic) NSInteger current;// 页码
@property (assign, nonatomic) NSInteger pages;// 总页数
@property(assign, nonatomic) NSInteger total;// 总记录数
@property (strong, nonatomic) NSArray<Goods*>* records;
@end@interface Goods : JKModel
@property (strong, nonatomic) NSString* id;
@property (strong, nonatomic) NSString* categoryId;
@property (strong, nonatomic) NSString* productName; // 商品名称
@property (strong, nonatomic) NSString* introduction;// 文字介绍
@property (strong, nonatomic) NSString* imgId;// 商品图片
@property(assign, nonatomic) CGFloat price;// 价格
@property (strong, nonatomic) NSString* priceUnit;// 单位...... @end

然后在 ViewController 中这样调用 goodsPageList 方法:

	  @weakify(self)[[MallAPI goodsPageList:query] subscribeNext:^(GoodsPage* x) {@strongify(self)// 1[self.optimumSC.goodsArray addObjectsFromArray:x.records];// 2[self.optimumSC.collectionContext  reloadSectionController:self.optimumSC];} error:^(NSError * _Nullable error) {[self showHint:error.localizedDescription];}];
  1. x 是 GoodsPage 类型,它的 records 属性包含了查询到的商品数据,我们将数据添加到 optimumSC(这是一个 SubController)的 goodsArray 数组中。
  2. 然后刷新 SubController,查询到的商品立即显示到列表中。

结束

网络 API 实际上是你和后台交互的过程。但后台开发人员不是上帝,他们和你一样,也经常会犯这样那样的错误。所以在网络 API 中,大量的代码用于处理“出了什么错”以及“错误在哪里”的问题上。

MCCSframework 框架为了解决这个问题,引入了 JSONResponseErrorFilter 协议用于通过 Response 来定义各种错误。在所有的错误中,后台返回的状态是非常重要的,具有重要的参考意义,这是后台在明确告诉我们 “为什么失败” 了。但除此之外的所有错误都是不明确的,需要我们根据每个后台的实际情况进行识别和定义。因此在不同项目中,实现 JSONResponseErrorFilter 协议的实现是不一样的,每个错误的定义要因“人”而异。

当然,如果你遇到一个“好的后台”,所有错误都被后台定义了,那么JSONResponseErrorFilter 类中需要做的工作会很少。

http://www.lbrq.cn/news/2697661.html

相关文章:

  • 域名停靠app免费下载网站郭生b如何优化网站
  • 烟台网站建设科技今日国际新闻摘抄十条
  • 购物网站建设目标查网站权重
  • 网站建设云平台上海网站seoseodian
  • 商贸网站上海关键词排名手机优化软件
  • 淘宝优惠券网站用什么软件做企业官网首页设计
  • 湛江网上房地产厦门seo优化
  • 数据交易网站开发青岛网络seo公司
  • 做微信广告网站有哪些内容淘宝代运营1个月多少钱
  • 在360上做网站怎么样单页网站模板
  • 企业电商网站建设目前推广软件
  • 做网站怎样找seo在线培训课程
  • 广州网站设计十年乐云seo免费的行情软件app网站
  • 官方网站内容更新需要怎么做淘宝运营培训课程
  • 做网站 报价网址之家大全
  • 长春火车站最新通知seo是哪个英文的缩写
  • 东莞天助网的网站广州seo公司哪个比较好
  • 怎样做千年私服网站武汉推广服务
  • 无锡企业网站制作公司免费外链代发平台
  • 做淘宝网站买个模版可以吗运营推广的方式和渠道
  • 网站修改思路公司在百度怎么推广
  • 网站的容量seo技术306
  • 微信微网站开发报价企业邮箱注册
  • 专门做珠宝的网站站长工具关键词查询
  • 郑州交友网站建设广州今天新闻
  • 电商网站怎么做seo优化做app的网站
  • 如何百度到自己的网站台州关键词优化服务
  • 番禺网站建设专家今天中国新闻
  • 河南省建设厅上班时间宁波seo整站优化
  • 素材网站建设千万不要学网络营销
  • 基于DDPG的车辆纵向速度控制优化:兼顾速度与乘坐舒适性
  • 101、【OS】【Nuttx】【周边】文档构建渲染:reStructuredText 格式
  • 备战国赛算法讲解——马尔科夫链,2025国赛数学建模B题详细思路模型更新
  • 机器学习算法篇(十):TF-IDF算法详解与应用实战
  • B 树与 B + 树解析与实现
  • vue3-pinia