iOS YTKNetwork用法

作者: 七分呗轻唱 | 来源:发表于2016-03-18 11:37 被阅读6716次

    1.YTKNetworkConfig 类

    YTKNetworkConfig 类有两个作用:
    统一设置网络请求的服务器和 CDN 的地址。
    管理网络请求的 YTKUrlFilterProtocol 实例
    按照设计模式里的 Do Not Repeat Yourself原则,我们应该把服务器地址统一写在一个地方。
    在实际业务中,我们的测试人员需要切换不同的服务器地址来测试。统一设置服务器地址到 YTKNetworkConfig 类中,也便于我们统一切换服务器地址。
    具体的用法是,在程序刚启动的回调中,设置好 YTKNetworkConfig 的信息,如下所示:

     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    
        [YTKNetConfig config:SeverTEST];
        [YTKNetConfig config:SeverDEV];
    }
    

    改变网络请求的一些配置

    + (NSString *)config:(YTKSever)sever{
    YTKNetworkAgent *agent = [YTKNetworkAgent sharedInstance];
    [agent setValue:[NSSet setWithObjects:@"application/json", @"text/plain", @"text/javascript", @"text/json",@"text/html",@"text/css", nil] forKeyPath:@"_manager.responseSerializer.acceptableContentTypes"];
    
    YTKNetworkConfig *config = [YTKNetworkConfig sharedInstance];
    NSString *msg = @"";
    switch (sever) {
        case SeverDEV:     // 开发服务器地址
            config.baseUrl = @"http://www.baidui.com";
            msg = [NSString stringWithFormat:@"开发网%@",config.baseUrl];
            break;
        case SeverTEST:     //测试服务器地址
            config.baseUrl = @"http://www.baidui.com";
            msg = [NSString stringWithFormat:@"测试网%@",config.baseUrl];
            break;
        case SeverRELEASE:   //发布版服务器地址
            config.baseUrl = @"http://www.baidui.com";
            msg = [NSString stringWithFormat:@"外网%@",config.baseUrl];
            break;
        default:
            break;
    }
    NSLog(@"\\n\\n%@\\n\\n",msg);
    return msg;
    }
    

    置好之后,所有的网络请求都会默认使用 YTKNetworkConfig 中baseUrl参数指定的地址。

    大部分企业应用都需要对一些静态资源(例如图片、js、css)使用CDN。YTKNetworkConfig的cdnUrl参数用于统一设置这一部分网络请求的地址。

    当我们需要切换服务器地址时,只需要修改 YTKNetworkConfig 中的 baseUrl和cdnUrl参数即可。

    2.YTKRequest 类

    YTKNetwork 的基本的思想是把每一个网络请求封装成对象。所以使用 YTKNetwork,你的每一种请求都需要继承 YTKRequest类,通过覆盖父类的一些方法来构造指定的网络请求。把每一个网络请求封装成对象其实是使用了设计模式中的 Command 模式。

    + (YTKApi *)apiPostWithUrl:(NSString *)url paraDictionary:(NSDictionary *)para;          //生成api(post调用)
    + (YTKApi *)apiPostWithUrl:(NSString *)url parameter:(YTKDataModel *)para;          //生成api(post调用)
    + (YTKApi *)apiGetWithUrl:(NSString *)url parameter:(YTKDataModel *)para;           //生成api(get调用)
    - (YTKApi *)appendUrlParameter:(NSNumber *)para;                                //给url后附带整形的参数
    
    • (YTKApi *)apiPostWithUrl:(NSString *)url para:(id)para{
      YTKApi *api = [[YTKApi alloc] init];
      api->_method = YTKRequestMethodPOST;
      api->_para = para;
      api->_url = url;
      api.requestSerializerType = YTKRequestSerializerTypeJSON;
      return api;
      }

    • (YTKApi *)apiPostWithUrl:(NSString *)url paraDictionary:(NSDictionary *)para{
      YTKApi *api = [[YTKApi alloc] init];
      api->_method = YTKRequestMethodPOST;
      api->_para = para;
      api->_url = url;
      api.requestSerializerType = YTKRequestSerializerTypeJSON;
      return api;
      }

    • (YTKApi *)apiPostWithUrl:(NSString *)url parameter:(DataModel *)para{
      YTKApi *api = [[YTKApi alloc] init];
      api->_method = YTKRequestMethodPOST;
      api->_para = [para toDictionary];
      api->_url = url;
      api.requestSerializerType = YTKRequestSerializerTypeJSON;
      return api;
      }

    • (YTKApi *)apiGetWithUrl:(NSString *)url parameter:(DataModel *)para{
      YTKApi *api = [[YTKApi alloc] init];
      api->_method = YTKRequestMethodGET;
      api->_para = [para toDictionary];
      api->_url = url;
      api.requestSerializerType = YTKRequestSerializerTypeJSON;
      return api;
      }

    • (YTKApi *)appendUrlParameter:(NSNumber *)para{
      NSString *str = [NSString stringWithFormat:@"%ld",[para longValue]];
      _url = [_url stringByAppendingPathComponent:str];
      return self;
      }

    • (YTKApi *)appendUrlStringParameter:(NSString *)para{
      NSString *str = [NSString stringWithFormat:@"%@",para];
      _url = [_url stringByAppendingPathComponent:str];
      return self;
      }

    3、调用 RegisterApi 在controller中调用

    - (void)excuteApi{
    YTKApi *api = [YTKApi apiPostWithUrl:@"User/Intention/OfferDetail" parameter:nil];
    [api appendUrlParameter:self.supplyId];
    [api startWithSuccess:^(YTKBaseRequest *request) {
        NSDictionary *dict = request.responseJSONObject;
    
    }];
    }
    

    4.按时间缓存内容

    YTKRequest继承自YTKBaseRequest类,用于单独封装所有responseData缓存代码
    // 首先YTKRequest的代码如下:
    @interface YTKRequest : YTKBaseRequest

    //表示当前请求,是否忽略本地缓存responseData
    @property (nonatomic) BOOL ignoreCache;

    /// 返回当前缓存的对象
    - (id)cacheJson;

    /// 是否当前的数据从缓存获得
    - (BOOL)isDataFromCache;

    /// 返回是否当前缓存需要更新【缓存是否超时】
    - (BOOL)isCacheVersionExpired;

    /// 强制更新缓存【不使用缓存数据】
    - (void)startWithoutCache;

    /// 手动将其他请求的JsonResponse写入该请求的缓存
    - (void)saveJsonResponseToCacheFile:(id)jsonResponse;

    /// 子类重写方法【参数方法】
    - (NSInteger)cacheTimeInSeconds; //当前请求指定时间内,使用缓存数据
    - (long long)cacheVersion; //当前请求,指定使用版本号的缓存数据
    - (id)cacheSensitiveData;

    @end

    然后从YTKRequest的start方法看起,这个方法表示开始执行请求
    // 该方法的执行逻辑,如下:

    - (void)start {
    
    //1. 当前请求,是否忽略缓存数据 
    if (self.ignoreCache) {
        [super start];
        return;
    }
    
    //2. 当前请求,是否设置了缓存超时时间
    if ([self cacheTimeInSeconds] < 0) {
        [super start];
        return;
    }
    
    //3. 当前请求,对应的本地缓存数据的版本号,是否与当前请求指定的版本号一致
    long long cacheVersionFileContent = [self cacheVersionFileContent];
    if (cacheVersionFileContent != [self cacheVersion]) {
        [super start];
        return;
    }
    
    //4. 当前请求,本地是否存在缓存数据文件
    NSString *path = [self cacheFilePath];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath:path isDirectory:nil]) {
        [super start];
        return;
    }
    
    //5. 当前请求,对应的缓存数据,是否已经超时
    int seconds = [self cacheFileDuration:path];
    if (seconds < 0 || seconds > [self cacheTimeInSeconds]) {
        [super start];
        return;
    }
    
    //6. 当前请求,对应的本地缓存数据文件,是否能够取到responseJSON
    _cacheJson = [NSKeyedUnarchiver     unarchiveObjectWithFile:path];
    if (_cacheJson == nil) {
        [super start];
        return;
    }
    
    //7. 如果以上情况,都不满足,表示本次请求的数据,来自本地缓存
    _dataFromCache = YES;
     
    //8. 结束本次请求,执行回调Block,释放Block
    [self requestCompleteFilter];
    
    YTKRequest *strongSelf = self;
    [strongSelf.delegate requestFinished:strongSelf];
    if (strongSelf.successCompletionBlock) {
        strongSelf.successCompletionBlock(strongSelf);
    }
    [strongSelf clearCompletionBlock];
    

    }

    两种管理缓存方式

    (1)按版本号
    /1. 得到responseJSON的缓存文件名
    - (NSString *)cacheFileName {
    NSString *requestUrl = [self requestPath];
    NSString *baseUrl = nil;
    if ([self baseURLType] == ZSYBaseURLBasic) {
    baseUrl = [YTKNetworkConfig sharedInstance].basicBaseUrl;
    } else if ([self baseURLType] == ZSYBaseURLWealthManagement) {
    baseUrl = [YTKNetworkConfig sharedInstance].cashBaseUrl;
    }
    id argument = [self cacheFileNameFilterForRequestArgument:[self requestArgument]];
    NSString *requestInfo = [NSString stringWithFormat:@"Method:%ld Host:%@ Url:%@ Argument:%@ AppVersion:%@ Sensitive:%@",
    (long)[self requestMethod], baseUrl, requestUrl,
    argument, [YTKNetworkPrivate appVersionString], [self cacheSensitiveData]];
    NSString *cacheFileName = [YTKNetworkPrivate md5StringFromString:requestInfo];
    return cacheFileName;
    }

    //2. 2个缓存文件的全路径
    //文件一: 手机沙盒Document/LazyRequestCache/缓存文件名
    //文件二: 手机沙盒Document/LazyRequestCache/缓存文件名.version

    - (NSString *)cacheFilePath {
    NSString *cacheFileName = [self cacheFileName];
    NSString *path = [self cacheBasePath];
    path = [path stringByAppendingPathComponent:cacheFileName];
    return path;
    }
    

    //3. 读取版本号文件中保存的NSNumber值

    - (long long)cacheVersionFileContent {
    NSString *path = [self cacheVersionFilePath];
    NSFileManager * fileManager = [NSFileManager defaultManager];
    if ([fileManager fileExistsAtPath:path isDirectory:nil]) {
        NSNumber *version = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
        return [version longLongValue];
    } else {
        return 0;//默认版本号=0
    }
    }
    

    //4. 当前请求指定的版本号 与 本地缓存文件保存的版本号 ,对比后如果一致表示是合法缓存数据,否则是不合法缓存数据

    long long cacheVersionFileContent = [self cacheVersionFileContent];
    if (cacheVersionFileContent != [self cacheVersion]) {
        [super start];
        return;
        }
    

    //5. 保存从服务器获取到的responseJSON按版本号

    • (void)saveJsonResponseToCacheFile:(id)jsonResponse {

      //1. 当前请求设置过缓存超时--》使用缓存
      //2. responseJSON不是来自本地缓存文件
      if ([self cacheTimeInSeconds] > 0 && ![self isDataFromCache]) {
      NSDictionary *json = jsonResponse;
      if (json != nil) {

            //保存responseJSON
            [NSKeyedArchiver archiveRootObject:json toFile:[self cacheFilePath]];
      
            //保存当前request指定的版本号
            [NSKeyedArchiver archiveRootObject:@([self cacheVersion]) toFile:[self cacheVersionFilePath]];
        }
      

      }
      }
      (2)按超时时间
      通过本地文件,创建时间 与 当前操作时间,的时间差,是否超过指定的时间长度
      - (int)cacheFileDuration:(NSString *)path {
      NSFileManager *fileManager = [NSFileManager defaultManager];
      // get file attribute
      NSError *attributesRetrievalError = nil;
      NSDictionary *attributes = [fileManager attributesOfItemAtPath:path
      error:&attributesRetrievalError];
      if (!attributes) {
      YTKLog(@"Error get attributes for file at %@: %@", path, attributesRetrievalError);
      return -1;
      }
      int seconds = -[[attributes fileModificationDate] timeIntervalSinceNow];
      return seconds;
      }
      int seconds = [self cacheFileDuration:path];
      if (seconds < 0 || seconds > [self cacheTimeInSeconds]) {
      [super start];
      return; }

    调用缓存方式
    - (void)excuteApi{
    YTKApi *api = [YTKApi apiPostWithUrl:@"IndexCategory/Get" parameter:nil];
    [api setCatchTime:10000]; //开启缓存 时差10000s
    if ([api cacheJson]) {
    NSDictionary *dict = [api cacheJson];
    DLog(@"获取基础数据缓存成功");
    [self setupCategoryData:dict];
    }
    [api startWithSuccess:^(YTKBaseRequest *request) {
    NSDictionary *dict = request.responseJSONObject;
    [self setupCategoryData:dict];
    }];
    }

    YTKChainRequest

    - (void)UploadPictureWith:(UIImage *)image{
        BYSApi *api = [BYSApi apiPostWithUrl:@"User/HeadPortrait/GetImageSetAddress" parameter:nil];
    YTKChainRequest *chainReq = [[YTKChainRequest alloc] init];
    [chainReq addRequest:api callback:^(YTKChainRequest *chainRequest, YTKBaseRequest *baseRequest) {
        BYSApi *result = (BYSApi *)baseRequest;
        NSDictionary *dict = result.responseJSONObject;
            }];
        }
    }];
    chainReq.delegate = self;
    [chainReq start];
    }
    - (void)chainRequestFinished:(YTKChainRequest *)chainRequest {
    // all requests are done
    [MBProgressHUD showMessage:@"头像上传成功" finishBlock:nil];
    
    }
    
    - (void)chainRequestFailed:(YTKChainRequest *)chainRequest failedBaseRequest:(YTKBaseRequest*)request {
    // some one of request is failed
    [MBProgressHUD showMessage:@"头像上传失败" finishBlock:nil];
    }
    

    github下载地址

    相关文章

      网友评论

      • d9d97ef2a023:请问如何上传json作为参数
      • 指尖猿:我正常请求成功,但是上传图片返回error 为nil
      • 319b8885add9:求demo?谢谢楼主
      • ZhangCc_:在appdelegate中配置了baseurl,在登录后,需要切换服务器,怎么修改baseurl?用什么方法?
        ZhangCc_:@1分之_二 后来我就是这么做的,谢咯~
        七分呗轻唱:@ZhangCc_ YTKNetworkConfig 这个是个单例,直接设置就行了, appdelegate里的设置是方便切换而已
      • 充电星球:3840的错误码有遇到过的吗?在YTKNetwork
        胖子程:让他支持text/html模式应该就可以解决了
      • 83096bc6ec73:设置了[agent setValue:[NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html",nil] forKeyPath:@"_manager.responseSerializer.acceptableContentTypes"];之后图片上传还是不成功,但是在pods里面修改AFURLResponseSerialization.m的 init方法成 self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript",@"text/html", nil];后图片上传可以额成功,不知道是何种原因?
        Yehuaqiang:@寻找犄角的牛 没有,具体一点的错误有吗?
        充电星球:@Yehuaqiang 遇到过3840 这个错误吗?
        Yehuaqiang:@83096bc6ec73 我也是啊,不知道ytk怎么没有提供text/html的修改
      • LibraCoder:在appdelegate中配置了baseurl,在viewdidload中写请求方法,提示错误,url的错误,缺少baseurl,但是在viewwillappear中使用就可以请求到数据,请问这是什么问题
      • biboba:怎么用YTK上传多张图片
      • 七月不下雨:尴尬 卡了 以为没发出去 。。
        七分呗轻唱:@MortimerMartin 吓死宝宝了 :fearful:
      • 七月不下雨:请问,config 和 agent 在 app delegate 里面设置好后 是全局的吗 不需要 和 request 关联吗?
        七分呗轻唱:@MortimerMartin 那是个单例适配
      • Damon_Rao:怎么实现multipart/form-data格式上传图片呢
        七分呗轻唱:@Damon_Rao http://www.jianshu.com/p/a0e3c77d3164
      • 陽光柏拉图:缓存怎么做的?有没有demo啊,急啊
        胖子程:@寒田半_亩 Demo没了
        七分呗轻唱:@陽光柏拉图 demo https://github.com/temagit/YTKNetworkEncapsulation
        七分呗轻唱:@陽光柏拉图 调用 [api setCatchTime:6000]; //开启缓存
      • a02efb1fb47a:content_type 怎么添加的?
        七分呗轻唱:@杨某某D 网络配置那里,
      • 旧夏2014:你好,我实现了- (NSString *)resumableDownloadPath发法 然后来下载文件,下载成功后,当下载文件的地址下的文件内容变化,我再去重新下载文件(同一个地址)结果下载下来的数据没有变化,ytk默认是缓存的吗?如何不从缓存取呢?
        旧夏2014:@寒田半亩博客 那就怪了,我没有开启缓存。。。
        七分呗轻唱:@旧夏2014 默认是不缓存的,除非你自己开启
      • 肉身佛陀:用cocoaPads集成的YTKNetwork,YTKNetwork中使用AFNetworking是2.6.3的,可以使用3.1.0么?有什么影响没
        肉身佛陀: @寒田半亩博客 哦,谢谢
        七分呗轻唱:@三寸季光不忘卿 现在YTKNetwork只支持到2.6.3的 AFNetworking,这个之间是有依赖的的,用YTKNetwork的话并不操作AFNetworking层,直接使用YTKNetwork就好了,所有没有影响
      • yj603:我这个也是空啊 responseJSONObject = (null) ,request.responseString有值。是son数据啊 {"state":0,"errno":"10000","errmsg":"","errfield":""} responseJSONObject = (null) 一直是空
        yj603:@寒田半亩博客好的谢谢了!就是texthtml的原因
        七分呗轻唱:@yj603 这个有配置没有 YTKNetworkAgent *agent = [YTKNetworkAgent sharedInstance];
        [agent setValue:[NSSet setWithObjects:@"application/json", @"text/plain", @"text/javascript", @"text/json",@"text/html",@"text/css", nil] forKeyPath:@"_manager.responseSerializer.acceptableContentTypes"];
      • 许豪贤:我用ytknetwork jsonobj为nil。但是jsonstring有数据 这是什么原因 求大神指点
        七分呗轻唱:@许豪贤 responseJSONObject只接受jason
      • 琪一可:如果有返回值,这个方法是必须写的吗。。?
        ```
        - (id)jsonValidator
        ```
        琪一可:@寒田半亩博客 好的 谢谢
        七分呗轻唱:@琪一可 不用
      • 琪一可:你好 我想问一下 如果request.responseJSONObject 是空,大概是因为什么原因呢。。? :fearful:
        琪一可:@寒田半亩博客 谢谢。我这里产生这个的原因是因为:后台返回的数据是NSData类型的。所以jsonObject没有值, 但是,respondData有值, 并且是正确的数据。
        许豪贤:@寒田半亩博客 解决了
        添加texthtml
        七分呗轻唱:@琪一可 这个只接受Jason数据

      本文标题:iOS YTKNetwork用法

      本文链接:https://www.haomeiwen.com/subject/njoclttx.html