我使用 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/