首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSURLSessionDataTask与线程化

NSURLSessionDataTask与线程化
EN

Stack Overflow用户
提问于 2015-04-30 16:00:03
回答 1查看 413关注 0票数 0

我正在使用NSURLSessionDataTask获得一个JSON提要,并在共享存储区(即单例存储)中填充一个NSMutableArray。外部世界可以通过一个将NSMutableArray转换为NSArray的getter来访问它。

getter调用一个刷新方法,该方法轮询JSON提要并填充NSMutableArray,如下所示:

代码语言:javascript
复制
- (NSArray *)articles
{

    if ([_articles count] == 0) {

        [self refreshArticles];

    }
    return _articles;
}

下面是其中的一些方法:

代码语言:javascript
复制
NSURLRequest *request = [NSURLRequest requestWithURL:feedURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:4.0];

NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request
                                             completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){

                                                 if (!error && response != nil) {

                                                     // decode JSON and add resultant objects to _articles

                                                     dispatch_async(dispatch_get_main_queue(), ^{
                                                         NSLog(@"Updated feed");
                                                         [nc postNotificationName:@"MLNArticleStoreFeedDidUpdate" object:self];
                                                     });
                                                 } else if (response == nil) {
                                                     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
                                                     [nc postNotificationName:@"MLNNetworkError" object:self];
                                                 }

                                             }];

[task resume];

这是可行的,但每次调用getter时,提要都会刷新7次。我认为这与getter的if子句有关,而feed下载则继续为真。我已经用dispatch_once减轻了这种情况,但是我觉得这是不对的。

下面是代码的内容:

代码语言:javascript
复制
- (NSMutableArray *)articles
{

    if ([_articles count] == 0) {
        static dispatch_once_t onceToken;

        dispatch_once(&onceToken, ^{
            [self refreshArticles];
        });
    }
    return _articles;
}

但我的意思是:“如果没有文章,去拿一些,然后然后回来”。有更好的方法吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-04-30 16:48:02

以这种方式使用的dispatch_once不会做您想要做的事情。这里真正的问题是,您几乎可以肯定,不希望在返回之前等待网络活动。如果你像这样阻止主线程,操作系统会杀死你的应用程序。

代码语言:javascript
复制
- (NSArray *)articles
{    
    if ([_articles count] == 0) {
        [self refreshArticlesFromNetwork];
    }
    return _articles;
}

- (void)refreshArticlesFromNetwork
{
    if (self.networkRefreshInProgress)
        return;

    self.networkRefreshInProgress = YES;
    [self showNetworkLoadingUI];

    NSURLRequest *request = [NSURLRequest requestWithURL:feedURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:4.0];
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error){
        NSMutableArray* localArray = [NSMutableArray array];

        if (!error && response != nil) {
            // decode JSON and add resultant objects to local array
            [localArray addObject: ... ];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            _articles = [localArray copy];
            self.networkRefreshInProgress = NO;
            [self hideNetworkLoadingUI];
            NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
            if (!error && response != nil) {
                [nc postNotificationName:@"MLNArticleStoreFeedDidUpdate" object:self];
            } else if (response == nil) {
                [nc postNotificationName:@"MLNNetworkError" object:self];
            }
            NSLog(@"Updated feed");
        });
    }];

    [task resume];
}

这里的重点是:

  • 显示一些“装载.”用户界面,而不是阻塞主线程。
  • 如果相同的更新已经在进行中,则不要触发其他更新。
  • 不要修改用于从后台线程填充UI的模型状态。
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29972508

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档