斯坦福iOS7 2013-2014秋Assignment 6的一种答案 #2

来源:互联网 发布:it桔子网 编辑:程序博客网 时间:2024/05/29 05:56

这篇文章是针对斯坦福iOS7 2013-1014的公开课Assignment 6 Top Regions所进行的解答的第二部分。

7.Fetch the URLforRecentGeoreferencedPhotos from Flickr periodically (a few times an hour when your application is in the foreground and whenever the system will allow when it is in the background using the background fetching API in iOS). You must load this data into a Core Data database with whatever schema you feel you need to do the rest of this assignment.

有两个要求,1是能间断性地在foreground或者background下fetch图片信息,2是把数据存储到coreData里,本节只完成第一个。

首先打开Capability—>Background Modes —>background fetch,保证可以允许后台下载。

在这里我们先单独建一个FLickrHelper的类,在其中实现fetch。它有两个public 方法

+ (void)startBackgroundDownloadRecentPhotosOnCompletion:(void (^)(NSArray *photos, void(^whenDone)()))completionHandler;+ (void)handleEventsForBackgroundURLSession:(NSString *)identifier                          completionHandler:(void (^)())completionHandler;
在AppDelegate中使用其中的background方法,这里我们只需要在background事件产生的时候,告诉AppDelegate实现下面的方法。

- (void)application:(UIApplication *)applicationhandleEventsForBackgroundURLSession:(NSString *)identifier  completionHandler:(void (^)())completionHandler{    [FlickrHelper handleEventsForBackgroundURLSession:identifier                                    completionHandler:completionHandler];}


在FlickrHelper.m中,首先检查有没有下载的进程,没有的话就添加这个下载任务设置taskDescription(以后会用它识别不同的任务),然后保存completion handler

#define FLICKR_FETCH_RECENT_PHOTOS @"Flickr Download Task to Download Recent Photos" + (void)startBackgroundDownloadRecentPhotosOnCompletion:(void (^)(NSArray *photos, void(^whenDone)()))completionHandler{    FlickrHelper *fh = [FlickrHelper sharedFlickrHelper];       [fh.downloadSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {        if (![downloadTasks count]) {            NSURLSessionDownloadTask *task = [fh.downloadSession downloadTaskWithURL:[FlickrFetcher URLforRecentGeoreferencedPhotos]];            task.taskDescription = FLICKR_FETCH_RECENT_PHOTOS;            fh.recentPhotosCompletionHandler = completionHandler;            [task resume];        } else {            for (NSURLSessionDownloadTask *task in downloadTasks) [task resume];        }    }];}

这里使用的是后台下载的session,并设置它的委托为FlickrHelper,并设置completion handler属性

@property (strong, nonatomic) NSURLSession *downloadSession;
<div class="container"><div class="line number1 index0 alt2"><code class="objc keyword">@property</code> <code class="objc plain">(</code><code class="objc keyword">copy</code><code class="objc plain">, </code><code class="objc keyword">nonatomic</code><code class="objc plain">) </code><code class="objc datatypes">void</code> <code class="objc plain">(^recentPhotosCompletionHandler)(</code><code class="objc keyword">NSArray</code> <code class="objc plain">*photos, </code><code class="objc datatypes">void</code><code class="objc plain">(^whenDone)());</code></div></div>...#define FLICKR_FETCH @"Flickr Download Session" - (NSURLSession *)downloadSession{    if (!_downloadSession) {        static dispatch_once_t onceToken;        dispatch_once(&onceToken, ^{            _downloadSession = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration backgroundSessionConfiguration:FLICKR_FETCH]                                                             delegate:self                                                        delegateQueue:nil];        });    }    return _downloadSession;}


使用单例这样可以在别的地方调用session实例

+ (FlickrHelper *)sharedFlickrHelper{    static dispatch_once_t pred = 0;    __strong static FlickrHelper *_sharedFlickrHelper = nil;    dispatch_once(&pred, ^{        _sharedFlickrHelper = [[self alloc] init];    });    return _sharedFlickrHelper;}

第二个public方法只需要存储appdelegate事件传递过来的download completion handler

@property (copy, nonatomic) void (^downloadBackgroundURLSessionCompletionHandler)();...+ (void)handleEventsForBackgroundURLSession:(NSString *)identifier                          completionHandler:(void (^)())completionHandler{    if ([identifier isEqualToString:FLICKR_FETCH]) {        FlickrHelper *fh = [FlickrHelper sharedFlickrHelper];        fh.downloadBackgroundURLSessionCompletionHandler = completionHandler;    }}

下面实现delegate中NSURLSessionDownloadDelegate的required方法,当下载任务完成后,检查是否是我们要处理的(使用之前设置的taskDescription,解析传过来的json文件,并把它传递到之前第一个方法的completion handler

- (void)URLSession:(NSURLSession *)session      downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location{    if ([downloadTask.taskDescription isEqualToString:FLICKR_FETCH_RECENT_PHOTOS]) {        NSDictionary *flickrPropertyList;        NSData *flickrJSONData = [NSData dataWithContentsOfURL:location];        if (flickrJSONData) {            flickrPropertyList = [NSJSONSerialization JSONObjectWithData:flickrJSONData                                                                 options:0                                                                   error:NULL];        }        NSArray *photos = [flickrPropertyList valueForKeyPath:FLICKR_RESULTS_PHOTOS];                 self.recentPhotosCompletionHandler(photos, ^{            [self downloadTasksMightBeComplete];        });    }}
不管下载出错或者正常,只需要重置并调用completionhandler即可

- (void)URLSession:(NSURLSession *)session              task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error{    if (error && (session == self.downloadSession)) {        NSLog(@"Flickr background download session failed: %@", error.localizedDescription);        [self downloadTasksMightBeComplete];    }}- (void)downloadTasksMightBeComplete{    if (self.downloadBackgroundURLSessionCompletionHandler) {        [self.downloadSession getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {            if (![downloadTasks count]) {                void (^completionHandler)() = self.downloadBackgroundURLSessionCompletionHandler;                self.downloadBackgroundURLSessionCompletionHandler = nil;                if (completionHandler) {                    completionHandler();                }            }        }];    }}

运行一下,然后马上点击Debug ->Simulate Background Fetch ,可以看到在后台时output窗口依然会出现#1里的log。



0 0
原创粉丝点击