應(yīng)用很早就上線了,歡迎大家下載使用:http://itunes.apple.com/app/id1206687109
源碼已經(jīng)公開纹份,大家可以去https://github.com/Inspirelife96/ILDiligence下載抵恋。 喜歡的話Fork或者給個Star果漾,非常感謝大渤。
下面是這一系列的全部帖子:
想法和原型
勤之時 - 架構(gòu)與工程組織結(jié)構(gòu)
勤之時 - 數(shù)據(jù)持久層的實現(xiàn)
勤之時 - 網(wǎng)絡(luò)層的實現(xiàn)
勤之時 - 業(yè)務(wù)邏輯層
勤之時 - Info.plist的改動
勤之時 - 表示層(一)
勤之時 - 表示層(二)
勤之時 - 表示層(三)
勤之時 - 表示層(四)
勤之時 - 表示層(五)
事實上缰盏,【勤之時】一個本地應(yīng)用惑芭,基本上沒有什么網(wǎng)絡(luò)請求坠狡,或者需要從服務(wù)器端下載數(shù)據(jù)。不過為了美觀遂跟,每天的背景圖片會變化逃沿,并且會有一個每日故事的分享頁面,也就是說幻锁,每天一圖凯亮。
那么具體這個圖片怎么來?當(dāng)然可以自己搭建服務(wù)器哄尔,然后提供圖片假消。不過這樣相對來說比較復(fù)雜,不但要搭建服務(wù)器岭接,還要自己準(zhǔn)備圖片富拗。所以最簡單的是看有沒有現(xiàn)成的API 服務(wù),我找到了兩個:
Bing的每日一圖并不是API服務(wù)鸣戴,不過通過抓包啃沪,可以發(fā)現(xiàn)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追驴,經(jīng)過測試,bing提供了1080x1920的圖片疏之,其后綴為_1080x1920.jpg殿雪,所以最后無水印圖片的下載地址為http://www.bing.com/urlbase_1080x1920.jpg。
那么當(dāng)前圖片對應(yīng)的故事在哪里呢体捏?同樣發(fā)現(xiàn)了API接口http://cn.bing.com/cnhp/coverstory/冠摄,不過這里的圖片是有水印的糯崎。
{
"date":"March 20",
"title":"碧玉妝 綠絲絳",
"attribute":"枝頭嬉戲的綠繡眼",
"para1":"古代的春分分為三候:“一候玄鳥至,二候雷乃發(fā)聲河泳,三候始電沃呢。”便是說春分日后拆挥,燕子便從南方飛來了薄霜,下雨時天空便要打雷并發(fā)出閃電。春分后纸兔,中國南方大部分地區(qū)越冬作物進(jìn)入春季生長階段惰瓜,氣溫也繼續(xù)回升,真正的春天來了汉矿,你也開始一個全新的自己吧崎坊!",
"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官網(wǎng)的說明去試試「承【勤之時】暫時使用的是Bing的每日一圖及故事來作為背景男翰。
知道了需求,了解了內(nèi)容的來源纽乱,接下來就是如何實現(xiàn)了蛾绎。同樣,iOS應(yīng)用架構(gòu)談 網(wǎng)絡(luò)層設(shè)計方案探討了詳細(xì)的方案鸦列。
最終的方案
- 使用delegate來做數(shù)據(jù)對接
- 交付NSDictionary給業(yè)務(wù)層租冠,使用Const字符串作為Key來保持可讀性
此外,【勤之時】的需求涉及到同步問題敛熬,可以發(fā)現(xiàn)肺稀,我們的操作為
- 訪問http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1 獲取Json數(shù)據(jù)
- 根據(jù)Json數(shù)據(jù)拼接獲得每日圖片的下載地址
- 下載圖片
- 訪問http://cn.bing.com/cnhp/coverstory/獲取每日故事的內(nèi)容第股。
可以發(fā)現(xiàn)应民,我們會發(fā)送3個HTTP異步請求,只有當(dāng)三個請求全部成功返回后夕吻,我們才能認(rèn)為這個下載任務(wù)完成诲锹。因此,需要使用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
![
![網(wǎng)絡(luò)層需求.png](http://upload-images.jianshu.io/upload_images/1771779-726f82b81d60f3da.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)](http://upload-images.jianshu.io/upload_images/1771779-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