YTKNetwork integration tutorial and related issues

YTKNetwork integration tutorial and related issues

YTKNetwork introduction

YTKNetwork is a library of ape iOS research and development team based on AFNetworking package iOS network library, in fact, a set of High Level API, provides a higher level of network access abstraction. Currently on the GitHub 3600+ star, is a new star in Network.

YTKNetwork provides the main functions

  • Supports caching of network requests by time buffer and version number
  • Support for setting server and CDN addresses
  • Support checking the legality of returning JSON content
  • Support block and delegate callback two modes
  • To support the bulk of the network request to send, and set up their callback (implemented in the YTKBatchRequest class)
  • Support easily set to send a network request depend on each other for example: send requests to A, according to the request of A results, selective send requests to B and C, B and C according to the results of selective transmission request D. (implemented in the YTKChainRequest class)
  • Support the network request URL filter, can be unified for network requests with some parameters, or modify some paths.
  • Defines a plug-in mechanism that makes it easy to add functionality to YTKNetwork. The ape exam official now provides a plug-in that can be displayed on the interface when the request is initiated, the “HUD” is being loaded.

The basic thought of YTKNetwork

The basic idea of YTKNetwork is to encapsulate each network request as an object. So using YTKNetwork, each request you need to inherit the YTKRequest class, by covering some of the methods of the parent class to specify the network request.

Encapsulating each network request into an object is actually using the Command pattern in the design pattern, which has the following benefits:

  • The request of the network is separated from the specific third party library, which is convenient to replace the underlying network library.
  • It is convenient to deal with the common logic in the base class, such as the data version number information of the ape question bank.
  • It is convenient to deal with the cache logic in the base class, as well as other public logic.
    easy to do object persistence.

Of course, if it is not what is good, that is if your project is very simple, so write is not the direct use of AFNetworking will be asked to write logic in Controller YTKNetwork is convenient, so is not suitable for very simple project.

On the intensive and discrete

intensive aquaculture

The entrance of each project request will go unified, foreign exposure request URL and Param and request, entrance is generally through a single case to achieve intensive official AFNetworking demo is used in the way of network request package, also is a popular way to network requests.


  • Easy to use, to achieve rapid development


  • Customizing for each request is not strong enough
  • Late business development


That is, each network request class is an object, its URL and request and response are not exposed to the external call. Can only be carried out by overloading or the realization of the agreement to specify the way, the external call only need to pass Param, YTKNetwork is the use of such a network request.


  • URL and the request and response are not exposed to the outside, to avoid external calls when the wrong
  • The business side is relatively simple to use, and business users do not need to care about its internal implementation
  • Customizable, you can specify the timeout for each request and the cache cycle


  • The network layer needs to be written by the business side
  • The number of files will increase, and the package will be large [not too big]

In the micro channel iOS client, due to the initial staff is less, and business changes more frequently. The use of intensive requests. However, taking into account the convenience of the business and to achieve scalability, it increased the RequestHeader request header, as well as WMHttpHelper network operating tools. Has been basically satisfied with the current development model
, but in the long run, it is necessary to convert the discrete network requests.


You can add the following line of code in Podfile to use YTKNetwork


Integrated to project

Project file introduction

YTKNetwork integration tutorial and related issues
YTKNetwork source

YTKBaseRequest: in order to request the base class, the internal declaration of the common API:
request such as request, request analysis, response analysis, request parameters, etc.. Its purpose is to let the subclass to achieve, do not do.

YTKRequest: it is a subclass of YTKBaseRequest, based on the support of the cache, and provides a rich cache strategy. Basically, the use of the project is inherited from the YTKRequest to write business Request.

YTKNetworkAgent: really do network requests, in the direct interaction with internal AFNetworking, called the AFNetworking provides various requests, of course, if the underlying want to switch the other third parties, in this class to replace the line.

YTKNetworkConfig: the file for the unified configuration of the network request class, provides a set of baseUrl cdnUrl and other basic request path, you can increase the parameters of all requests, etc..

YTKBatchRequest: for the bulk of the network request and provide agents and block two ways to external use

YTKChainRequest: it is very convenient to use this class when there is an association between multiple requests, that is to say, the next request may request the data returned from the previous request.

YTKBatchRequestAgent, YTKChainRequestAgent: YTKBatchRequest, YTKChainRequest, respectively, do not need to take the initiative to call

Integrated file introduction

YTKNetwork integration tutorial and related issues
My Project Table

This is my new Demo project file, in general, not recommended directly inherited from the YTKRequest class to write a business, need to write their own class request, the specific service request again inherits from the project base to avoid the new version of YTKRequest to modify a part of the realization of the default value to program need to do a lot of changes. Among them: ZCBaseRequest, ZCBatchRequest, ZCChainRequest is the base class of the demo project. ZCJSONModel is the base class for JSON to Model, and ZCHTTPError is used to customize the error message

YTKNetwork integration tutorial and related issues
single HTTP example

This is an example of a specific request in the Demo project. This show is very clear, ZCGetInfoParam is the request of the Senate class, ZCMeGetInfoManger is a specific request to operate the class, ZCGetInfoModel is a reference class. However, if the Senate and the Senate rarely, you can only have a manger class

Related issues

I do not want to introduce the basis of YTKNetwork and advanced use tutorial. If you want to understand the basic and advanced tutorial you can read the
YTKNetwork using
based tutorial YTKNetwork advanced tutorial
this article focuses on the integration and use of the process encountered some problems and Solutions

1> JSON turn Model problem

For slightly more complex projects, some may return data of more than and 10 interface, the use of the time may not one read out from the dictionary, and then do < null> air treatment, generally use Model way to convert the specific business model, to obtain specific data from the business model in common there are JSONModel, Mantle, MJExtension and other three party libraries, this paper takes JSONModel as an example, to achieve the framework of internal parsing into Model

  1. In the new YTKBaseRequest JSONModel JsonModel @property (nonatomic / / / attribute, strong, readonly, nullable) ID responseJSONModel;
  2. In the new YTKBaseRequest modelClass function for subclasses, that corresponding to the specific name of the model class to convert model YTKBaseRequest.h / / / class, subclass implementation would be directly mapped to the model class and initialization operation – (Class) modelClass; YTKBaseRequest.m (Class) modelClass {return nil;}
  3. View the source code is not difficult to find the real network request success and failure is YTKNetworkAgent, in – (void) handleRequestResult: (NSURLSessionTask *) task responseObject: (ID) responseObject error: (NSError *) and error (void) – requestDidSucceedWithRequest: (YTKBaseRequest *) request – (void) requestDidFailWithRequest: (YTKBaseRequest *) request error: (NSError * error) of these three methods. The specific operation is – (void) requestDidSucceedWithRequest: (YTKBaseRequest * request) {@autoreleasepool {[request requestCompletePreprocessor]; [self JSONConvertModel:request];} dispatch_async (dispatch_get_main_queue), [request (^{toggleAccessoriesWillStopCallBack]; [request requestCompleteFilter]; if (request.delegate! = Nil) {[request.delegate} if (requestFinished:request]; request.successCompletionBlock) {request.successCompletionBlock} [(request); request toggleAccessoriesDidStopCallBack];} the specific method of ///json);} model – (void) JSONConvertModel: (YTKBaseRequest*) request modelClass modelClass] {Class = [request; if (! ModelClass) {return}; NSError * er Ror = nil; if ([request.responseJSONObject isKindOfClass:[NSDictionary class]]) {request.responseJSONModel = [[modelClass alloc] initWithDictionary:request.responseJSONObject error:& error]}else; if ([request.responseJSONObject isKindOfClass:[NSArray class]]) {request.responseJSONModel = error]; [modelClass arrayOfModelsFromDictionaries:request.responseJSONObject error:&}else if {/ / not to do here, because if the AFNetworking data returned by the null call will fail when the callback} if (error (@ YTKLog) {“Request JSON—JSONModel Failed =%@”, error);}}
  4. In the YTKRequest class also need to add a cache class model specific code for YTKRequest.m @property (nonatomic, strong) ID cacheJSONModel; ///TTT (ID) responseJSONModel (_cacheJSONModel) {if} return {return _cacheJSONModel; [super responseJSONModel];} – (BOOL) loadCacheData *path [self cacheFilePath] {NSString = NSFileManager; *fileManager = [NSFileManager defaultManager]; NSError *error = nil; if ([fileManager fileExistsAtPath:path isDirectory:nil]) {NSData *data [NSData = dataWithContentsOfFile:path]; _cacheData = data; _cacheString = [[NSString alloc] initWithData:_cacheData encoding:self.cacheMetadata.stringEncoding]; switch (self.responseSerializerType) {case YTKResponseSerializerTypeHTTP: Nothing. return / / Do YES; case YTKResponseSerializerTypeJSON: _cacheJSON = [NSJSONSerialization JSONObjectWithData:_cacheData options: (NSJSONReadingOptions) 0 error:& error]; if (! Error) {[self JSONConvertModel:_cacheJSON]}; return error = nil; case = YTKResponseSerializerTypeXMLParser: _cacheXML [[NSXMLParser alloc] initWithData:_cacheData] return YES; return NO;}};} – (void) JSONConvertModel: (YTKBaseRequest* request) {/ / / with the second step implementation way}
  5. Here basically has achieved json-model, specific business code: – (void) loadCacheData NSString {*userId = “@ 1”; GetUserInfoApi *api = [[GetUserInfoApi alloc] initWithUserId:userId]; if ([api loadCacheWithError:nil]) {NSDictionary *json = [api responseJSONObject]; NSLog (JSON = @% @ “, JSON); / / show cached data YTKJSONModel * model = [api responseJSONModel]; NSLog (@” jsonmodelllll=%@—%@ “, model.nick, model.level);} api.animatingText = @” loading “; api.animatingView = self.view; [api startWithCompletionBlockWithSuccess:^ (YTKBaseRequest *request) {NSLog (” update ui=%@ “, [api @ responseJSONModel]);} failure:^ (YTKBaseRequest *request) {NSLog (@” failed “}]);} so steps, Just so you need to modify the source code, the details can refer to demo, address:

2> token induced problems

Under normal circumstances, the network requires the client to bring token, for the server to verify the effectiveness of user login. So token failure may need to do some processing, in demo this part of the verification is written in the ZCBaseRequest class. This avoids the failure of the business code to handle token failures everywhere

- (void) requestFailedFilter {[super requestFailedFilter]; if (error.code==TokenTimeOut) {}}}

Of course, after this process, if the subclass needs to do a special deal at the time of the error, then the requestFailedFilter method must be overridden when calling [super requestFailedFilter]

Error analysis; 3&gt

YTKNetwork calls HTTP to return the wrong class to NSError. And their projects are generally required to customize the error message, or according to a particular type of error. This step can be handled in the error callback of the base class of the request that you define. Let’s look at a section of the YTKNetwork source code:

- (void) handleRequestResult: (NSURLSessionTask *) task responseObject: (ID) responseObject error: (NSError * error) {/ / left here only key code NSError * __autoreleasing serializationError NSError * __autoreleasing = nil; validationError = nil; NSError = *requestError nil; BOOL succeed = NO; request.responseObject = responseObject; if ([request.responseObject isKindOfClass:[NSData class]]) {request.responseData = responseObject; request.responseString = [[NSString alloc] initWithData:responseObject encoding:[YTKNetworkUtils stringEncodingWithRequest:request]]; switch (request.responseSerializerType) {case YTKResponseSerializerTypeHTTP: / / Default serializ Er. Do nothing. break; case YTKResponseSerializerTypeJSON: request.responseObject = [self.jsonResponseSerializer responseObjectForResponse:task.response data:request.responseData error:& serializationError]; request.responseJSONObject = request.responseObject; request.responseObject = break; case YTKResponseSerializerTypeXMLParser: [self.xmlParserResponseSerialzier responseObjectForResponse:task.response data:request.responseData error:& serializationError]; break; if (error)}} {succeed = NO; requestError = error;} else if (serializationError) {succeed = NO; R EquestError = serializationError;} else {succeed = [self validateResult:request error:& validationError]; requestError = validationError;}} / / left key code

It is not difficult to find that there are three types of errors

  1. RequestError: an error in the request for a network request for AFNetworking, such as no network.
  2. SerializationError: in response to errors, for the AFNetworking response error, such as the return of the JSON data you use XML parsing, there are many cases, etc..
  3. ValidationError: check the JSON error, [request statusCodeValidator] and [request jsonValidator which includes two types of errors, the former for the return of the statusCode is not in the specified range of success you request, the situation field is not consistent with the existence of the JSON data returned by the jsonValidator function in the overloaded with you.
  4. [optional] if you use JSONModel, there will be an error in the JSONModel parsing error.

Treatment methods are as follows:

/ / here will not consider the JSONModel parsing error problem (void): requestFailedPreprocessor {//note subclasses for inheritance, must call the [super requestFailedPreprocessor]; [super requestFailedPreprocessor]; NSError * error = self.error; if (error.domain / isEqualToString:AFURLResponseSerializationErrorDomain]) {//AFNetworking treated if ([error.domain isEqualToString:YTKRequestValidationErrorDomain]) error}else {/ / ape exam treated the error of}else{/ / system level domain error, no network according to the error [NSURLErrorDomain] / / code to define the display of information, ensure the display content can easily control}}

There is also a special case, the server is not necessarily the wrong way to return to you. The possible request status code is still 200OK, so this time it needs to rewrite the YTK provided by the success and failure of the block and rewrite agents

4> loading animation and error popup mechanism

YTK comes with a plug-in mechanism for the processing of YTKBaseRequest, YTKBatchRequest, YTKChainRequest these requirements of the loading display mechanism, only need to be introduced into animatingView and animatingText. For pop up error messages, you can do this in the ZCBaseRequest main thread callback. That is:

Called on the main thread / / / when request failed. (void requestFailedFilter) {[super requestFailedFilter]; if ([self! IsHideErrorToast]) {UIWindow = [[UIApplication * window sharedApplication] keyWindow] * controller = [self; UIViewController findBestViewController:window.rootViewController]; [WMHUDUntil showFailWithMessage:self.error.localizedDescription toView:controller.view];}}

Where [self isHideErrorToast] is used to indicate whether or not to hide the error. The method is implemented by specific subclasses.

5> termination of network request

YTK network request to close the program: call in dealloc:

Remove self from queue the request. cancel (void) stop and request;

Therefore, it is recommended that each network request is written as a global variable in controller.
below shows a specific request code:

ZCTYKTestViewController.m @interface (ZCTYKTestViewController) @property (nonatomic, strong) ZCMeGetInfoManger * infoManger; @end @implementation ZCTYKTestViewController (void) viewDidLoad viewDidLoad] [self {[super; setupData];} - (void) setupData [[ZCMeGetInfoManger alloc] {self.infoManger = init]; self.infoManger.animatingView = self.view;} - (IBAction) buttonAction: (UIButton*) sender ZCGetInfoParam * param {[self clearTextView]; [[ZCGetInfoParam alloc] = init]; param.userId = 0; param.token = @ @ 222222; _infoManger.param = param; [_infoManger startWithCompletionBlockWithSuccess:^ (__kindof YTKBaseRequest * _Nonnull request) {NSLog (@ "responseJSONObject=%@", _infoManger.respons EJSONObject infoModel = [[ZCGetInfoModel * ZCGetInfoModel); alloc] initWithDictionary:_infoManger.responseJSONObject error:nil]; [self updateTextViewWithLog:[NSString stringWithFormat:@ read data: /n%@, infoModel]]; failure:^} (__kindof YTKBaseRequest * _Nonnull request [weakself updateTextViewWithLog:[NSString stringWithFormat:@) {"failed to read: /n%@, weakself.infoManger.error]];}];}

This is my personal summary of these points, if there is a better program can also discuss with me