平时收藏学无止境上海恩美路演

勤之时 - 网络层的实现

2017-03-20  本文已影响212人  启发禅悟

应用很早就上线了,欢迎大家下载使用:http://itunes.apple.com/app/id1206687109
源码已经公开,大家可以去https://github.com/Inspirelife96/ILDiligence下载。 喜欢的话Fork或者给个Star,非常感谢。
下面是这一系列的全部帖子:
想法和原型
勤之时 - 架构与工程组织结构
勤之时 - 数据持久层的实现
勤之时 - 网络层的实现
勤之时 - 业务逻辑层
勤之时 - Info.plist的改动
勤之时 - 表示层(一)
勤之时 - 表示层(二)
勤之时 - 表示层(三)
勤之时 - 表示层(四)
勤之时 - 表示层(五)

事实上,【勤之时】一个本地应用,基本上没有什么网络请求,或者需要从服务器端下载数据。不过为了美观,每天的背景图片会变化,并且会有一个每日故事的分享页面,也就是说,每天一图。

网络层需求.png

那么具体这个图片怎么来?当然可以自己搭建服务器,然后提供图片。不过这样相对来说比较复杂,不但要搭建服务器,还要自己准备图片。所以最简单的是看有没有现成的API 服务,我找到了两个:

  1. Bing 的每日一图
  2. Unsplash API

Bing的每日一图并不是API服务,不过通过抓包,可以发现http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1 可以获取到无水印的图片。


{
    "images": [{
                   "startdate":"20170319",
                   "fullstartdate":"201703191600",
                   "enddate":"20170320",
                   "url":"/az/hprichbg/rb/TingSakura_ZH-CN14945610051_1920x1080.jpg",
                   "urlbase":"/az/hprichbg/rb/TingSakura_ZH-CN14945610051",
                   "copyright":"一只在樱花树上嬉戏的绿绣眼(© Reece Cheng/500px)",
                   "copyrightlink":"http://www.bing.com/search?q=%E6%98%A5%E5%88%86&form=hpcapt&mkt=zh-cn",
                   "quiz":"/search?q=Bing+homepage+quiz&filters=WQOskey:%22HPQuiz_20170319_TingSakura%22&FORM=HPQUIZ",
                   "wp":true,
                   "hsh":"c4afb61170efde716ed371c02f8db13f","drk":1,"top":1,"bot":1,"hs":[]
               }],
    "tooltips": {
        "loading":"正在加载...",
        "previous":"上一个图像",
        "next":"下一个图像",
        "walle":"此图片不能下载用作壁纸。",
        "walls":"下载今日美图。仅限用作桌面壁纸。"
    }
}

从返回的Json中可以看到,我们可以获取到urlbase,经过测试,bing提供了1080x1920的图片,其后缀为_1080x1920.jpg,所以最后无水印图片的下载地址为http://www.bing.com/urlbase_1080x1920.jpg

那么当前图片对应的故事在哪里呢?同样发现了API接口http://cn.bing.com/cnhp/coverstory/,不过这里的图片是有水印的。

{
    "date":"March 20",
    "title":"碧玉妆 绿丝绦",
    "attribute":"枝头嬉戏的绿绣眼",
    "para1":"古代的春分分为三候:“一候玄鸟至,二候雷乃发声,三候始电。”便是说春分日后,燕子便从南方飞来了,下雨时天空便要打雷并发出闪电。春分后,中国南方大部分地区越冬作物进入春季生长阶段,气温也继续回升,真正的春天来了,你也开始一个全新的自己吧!",
    "para2":"",
    "provider":"© Reece Cheng/500px",
    "imageUrl":"/th?id=OSA.pfFS41jcab0yuA&pid=SatAns&w=100&h=100&c=8&rs=1","primaryImageUrl":"http://hpimges.blob.core.chinacloudapi.cn/coverstory/watermark_tingsakura_zh-cn14945610051_1920x1080.jpg",
    "Country":"",
    "City":"",
    "Longitude":"",
    "Latitude":"",
    "Continent":"亚洲",
    "CityInEnglish":"Enter keyword",
    "CountryCode":""
}

所以综合这两个,我们就可以得到每日背景图片及故事。

至于Unsplash,大家可以参考Unsplash官网的说明去试试。【勤之时】暂时使用的是Bing的每日一图及故事来作为背景。

知道了需求,了解了内容的来源,接下来就是如何实现了。同样,iOS应用架构谈 网络层设计方案探讨了详细的方案。

最终的方案

  1. 使用delegate来做数据对接
  2. 交付NSDictionary给业务层,使用Const字符串作为Key来保持可读性

此外,【勤之时】的需求涉及到同步问题,可以发现,我们的操作为

  1. 访问http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1 获取Json数据
  2. 根据Json数据拼接获得每日图片的下载地址
  3. 下载图片
  4. 访问http://cn.bing.com/cnhp/coverstory/获取每日故事的内容。

可以发现,我们会发送3个HTTP异步请求,只有当三个请求全部成功返回后,我们才能认为这个下载任务完成。因此,需要使用dispatch_group_t, dispatch_group_enter, dispatch_group_leave,dispatch_group_notify来完成这个组合。

最终代码:

//  ILDNetwork.h

#import <Foundation/Foundation.h>

@protocol ILDNetworkDelegate <NSObject>

- (void)fetchStoryDataSuccess:(NSDictionary *)storyDataDictionary;
- (void)fetchStoryDataFail:(NSError * _Nonnull)error;

@end

@interface ILDNetwork : NSObject

@property (nonatomic,weak) id<ILDNetworkDelegate> delegate;

- (void)downloadStoryData;

@end

![
![网络层需求.png](http:https://img.haomeiwen.com/i1771779/726f82b81d60f3da.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)](http:https://img.haomeiwen.com/i1771779/541fcb4c8382a9f2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)//  ILDNetwork.m

#import "ILDNetwork.h"
#import "ILDNetworkConstants.h"
#import <UIKit/UIKit.h>
#import <AFNetworking/AFNetworking.h>

@interface ILDNetwork()

@property (nonatomic, strong) dispatch_group_t requestGroup;

@property (nonatomic, strong) NSString *storyTitle;
@property (nonatomic, strong) NSString *storyAttribute;
@property (nonatomic, strong) NSString *storyPara1;
@property (nonatomic, strong) UIImage *storyImage;
@property (nonatomic, strong) NSError *error;

@end


@implementation ILDNetwork

- (void)downloadStoryData {
    [self downloadImageData];
    [self downloadOtherData];
    
    dispatch_group_notify(self.requestGroup, dispatch_get_main_queue(), ^{
        if (!self.error) {
            [self.delegate fetchStoryDataFail:self.error];
        } else {
            NSDictionary *storyDataDictionary = @{
                                                  kBingStoryURLTitle:self.storyTitle,
                                                  kBingStoryURLAttribute:self.storyAttribute,
                                                  kBingStoryURLPara1:self.storyPara1,
                                                  kBingImageURLImageData:UIImageJPEGRepresentation(self.storyImage, 0.5)
                                                  };
            [self.delegate fetchStoryDataSuccess:storyDataDictionary];
        }
    });
}

- (void)downloadImageData {
    dispatch_group_enter(self.requestGroup);
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    
    NSURL *URL = [NSURL URLWithString:kBingImageURL];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            self.error = error;
        } else {
            NSDictionary *responseDict = (NSDictionary *)responseObject[kBingImageURLImages][0];
            NSString *imageURLString = [NSString stringWithFormat:kBingImageFullPathFormat, responseDict[kBingImageURLUrlBase], kImageTypes];
            [self downloadImageData:imageURLString];
        }
        dispatch_group_leave(self.requestGroup);
    }];
    
    [dataTask resume];
}

- (void)downloadImageData:(NSString *)imageUrlString {
    dispatch_group_enter(self.requestGroup);
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    manager.responseSerializer = [AFImageResponseSerializer serializer];
    
    NSURL *URL = [NSURL URLWithString:imageUrlString];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            self.error = error;
        } else {
            self.storyImage = responseObject;
        }
        dispatch_group_leave(self.requestGroup);
    }];
    
    [dataTask resume];
}

- (void)downloadOtherData {
    dispatch_group_enter(self.requestGroup);
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
    
    NSURL *URL = [NSURL URLWithString:kBingStoryURL];
    NSURLRequest *request = [NSURLRequest requestWithURL:URL];
    
    NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
        if (error) {
            self.error = error;
        } else {
            NSDictionary *responseDict = (NSDictionary *)responseObject;
            self.storyTitle = responseDict[kBingStoryURLTitle];
            self.storyAttribute = responseDict[kBingStoryURLAttribute];
            self.storyPara1 = responseDict[kBingStoryURLPara1];
        }
        dispatch_group_leave(self.requestGroup);
    }];
    
    [dataTask resume];
}

- (dispatch_group_t)requestGroup {
    if (!_requestGroup) {
        _requestGroup = dispatch_group_create();
    }
    
    return _requestGroup;
}

@end

上一篇 下一篇

猜你喜欢

热点阅读