我开始开发一个 iphone 应用程序,我需要一些关于 NSURLSession 以及如何正确管理我的数据的下载和解析的建议。
我刚刚完成了在 nsurlsession 中下载我的数据的错误,但是关于我发现理解这些异步请求有多么困难,我认为我的解决方案并不是很好...... 下载错误也出现在 2 种不同的下载解决方案中,这让我觉得我忘了做某事...
在我的项目中,我下载了不同的 xml 文件(有时还有一些带有图片的 zip 文件),我需要在显示它们的信息之前对其进行解析。这些信息可能会快速变化,所以如果我再次加载我的页面,我想再次下载它们。 我一直在寻找一种简单的方法来以相同的方式管理所有下载,这样我就不必重新编写大量代码。
我找到了这个project首先。
有了它,我只需要使用该代码来管理下载:
NSString *downloadUrl = @"https://www.url.com";
NSURL *location = [NSURL URLWithString:downloadUrl];
// DownloadManager is my version of the CTSessionOperation of the github project
DownloadManager *operation = [DownloadManager new];
operation.downloadUrl = downloadUrl;
operation.completionAction = ^(NSURL *xmlUrl, BOOL success){
dispatch_async(dispatch_get_main_queue(), ^{
if (success){
regions = [[TeamChoiceManager sharedManager] parseRegions:[NSData dataWithContentsOfURL:location]];
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:Nil waitUntilDone:YES];
}
});
};
operation.isBackground = YES;
[operation enqueueOperation];
此代码在我第一次下载时完美运行。但是如果我尝试再次启动下载,下载不会启动(所以没有错误,只是,这个代码下载一次就这样)。
我通过修改 CTSessionOperation
/DownloadManager
中的方法 (NSURLSession *)session
来纠正这个错误。我在评论中添加了“dispatch_once”以使其工作,但我认为这不是好的解决方案...
我尝试了导致相同错误的其他解决方案。我使用此代码管理下载:
NSString *regionsUrl= @"url";
NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];
// My solution to the bug
/*NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration
backgroundSessionConfiguration:[NSString stringWithFormat:@"com.captech.mysupersession.BackgroundSession%d",numBGSession]]; */
// numBGSession++; this is a static NSInteger
NSURLSession *session =
[NSURLSession sessionWithConfiguration:backgroundConfiguration
delegate:teamChoiceDetailViewController
delegateQueue:nil];
NSURLSessionDownloadTask *sessDLTask =
[session downloadTaskWithURL:[NSURL URLWithString:regionsUrl]];
[sessDLTask resume];
在委托(delegate)中:
-(void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
dispatch_async(dispatch_get_main_queue(), ^{
self.regions = [[TeamChoiceManager sharedManager] parseRegions:[NSData dataWithContentsOfURL:location]];
[self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:Nil waitUntilDone:YES];
});
}
使用此解决方案,我通过在每次尝试下载时创建自定义 NSURLSessionConfiguration
来避免错误。
所以我们开始吧。我对这两种解决方案感到很困惑。我不知道它们是否是管理下载的正确方法,我不认为我正确地纠正了错误,而且我一定是错过了 NSURLSession
的逻辑。
您对改进这些解决方案有什么建议吗?或者您认为其中一个比另一个好得多?
最佳答案
编辑:如果有人正在寻找更通用的解决方案来轻松正确地管理网络事务,您可以查看 AFNetworking它有一些魔力(另外你可以找到很多教程)。
我放弃了开发适用于每种情况的东西(特别是如果它是后台 session ,因为我不需要它)。 最后我刚刚创建了一个带有静态 session 的类,用于管理下载的委托(delegate),以及我在 didFinishDownloadingToURL 中使用的 block 来管理下载的数据。 当然不完美,但目前已经足够好了。
typedef void (^CTCompletionBlock)(NSURL *location, NSError* err);
@interface DownloadManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, retain) NSURLSessionDownloadTask *dlTask;
@property (nonatomic, retain) NSString *location;
@property (strong) CTCompletionBlock afterDLBlock;
+ (DownloadManager *)sharedManager;
-(void)downloadTask;
@end
//
// DownloadManager.m
// MVCTest
//
// Created by
//
#import "DownloadManager.h"
#import "AppDelegate.h"
static DownloadManager *instance = nil;
static NSURLSession *session = nil;
@implementation DownloadManager
+ (DownloadManager *)sharedManager {
if (instance == nil) {
//session = [DownloadManager sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
instance = [DownloadManager new];
}
return instance;
}
+ (id)new
{
return [[self alloc] init];
}
- (id)init{
self = [super init];
session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
return self;
}
-(void)downloadTask{
self.dlTask = [session downloadTaskWithURL:[NSURL URLWithString:self.location]];
[self.dlTask resume];
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
NSError *error;
if (self.afterDLBlock){
self.afterDLBlock(location, error);
}
}
//i still have to manage the delegate...
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes {}
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {}
-(void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error{}
#pragma mark - NSURLSessionDelegate
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {}
@end
有了这个类,我只需要编写这段代码来管理下载的数据:
typeof(self) __weak weakSelf = self;
NSString *downloadUrl = @"http://www.whatyouwant.com";
[DownloadManager sharedManager].location = downloadUrl;
[DownloadManager sharedManager].afterDLBlock = ^(NSURL *location, NSError *error) {
weakSelf.regions = [[TeamChoiceManager sharedManager] parseRegions:[NSData dataWithContentsOfURL:location]];
dispatch_sync(dispatch_get_main_queue(), ^{
[weakSelf.activityViewIndicator stopAnimating];
[weakSelf.tableView reloadData];
});
};
[[DownloadManager sharedManager] downloadTask];
我仍然需要管理错误和委托(delegate),但是有了 taht 解决方案,我将不需要编写很多代码来下载一些数据
关于ios - 正确管理 NSURLSession 的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22189299/