ios - NSURLSessionDataTask 和线程

标签 ios objective-c grand-central-dispatch

我使用 NSURLSessionDataTask 获取 JSON 提要,并填充位于共享存储(单例)内的 NSMutableArray。外部世界可以通过将其转换为 NSArray 的 getter 来访问 NSMutableArray。

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

- (NSArray *)articles
{

    if ([_articles count] == 0) {

        [self refreshArticles];

    }
    return _articles;
}

这是其中的一些方法:

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 下载时继续为 true 有关。我已经用 dispatch_once 缓解了这个问题,它有效,但我觉得这是不对的。

现在的代码是这样的:

- (NSMutableArray *)articles
{

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

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

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

最佳答案

dispatch_once,以这种方式使用,不会做你想做的事。这里的真实情况是您几乎可以肯定不想在返回之前等待网络事件。如果您像那样阻塞主线程,操作系统将终止您的应用。

- (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 的模型状态。

关于ios - NSURLSessionDataTask 和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29972508/

相关文章:

ios - iOS Mobile Safari滚动:减速时的DOM操作?

objective-c - dealloc 调用后台 GCD 队列崩溃用 ARC 构建的应用程序

c++ - djinni - C++ 和 swift/objective C/java 之间的指针和循环引用

ios - 制作自定义导航,最好的方法是什么?

multithreading - Cocoa NSApplication 线程模型

swift - 我正在尝试使用调度背景在 Collection View 中使用本地标识符来获取 Assets ,但加载需要太多时间并且单元格为空

ios - 我该如何修复 "Data(contentsOf: url) crashing app"?

具有不同语言的 iPhone 应用程序

ios - 如何从服务器获取 AFNetworking 中的完整响应字符串?

objective-c - 仅当拖动到应用程序图标时才打开图像文件