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

这篇文章是针对斯坦福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 *)application
handleEventsForBackgroundURLSession:(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 *)downloadTask
didFinishDownloadingToURL:(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 *)task
didCompleteWithError:(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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值