xcode iOS - NSOperation 中的异步 NSURLConnection

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15066532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 02:50:51  来源:igfitidea点击:

iOS - Async NSURLConnection inside NSOperation

iosxcodecocoa-touchnsurlconnectionnsoperation

提问by Oleg

I know this question was asked many times on SO, but I didn't manage to make it work in my project...

我知道这个问题在 SO 上被问过很多次,但我没有设法让它在我的项目中工作......

So, I want to subclass NSOperationand make it download a file using NSURLConnection. What is the right way to do it? here is my code which doesn't work: First, I'm adding all my operations in a loop:

所以,我想子类化NSOperation并使用NSURLConnection. 正确的做法是什么?这是我的代码不起作用:首先,我将所有操作添加到循环中:

DownloadFileOperation *operation;
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
for (int i=0; i<10; i++) {
operation = [[DownloadFileOperation alloc] init];
operation.urlString = pdfUrlString;
[queue addOperation:operation];
operation = nil; }

And here is my subclass:

这是我的子类:

@interface DownloadHandbookOperation : NSOperation <NSURLConnectionDelegate>
{

}

@property (strong, nonatomic) NSString *urlString;

@end


@implementation DownloadHandbookOperation
{
    NSString *filePath;
    NSFileHandle *file;
    NSURLConnection * connection;
}

- (void)start
{
    if (![NSThread isMainThread])
    {
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }

    NSURL *url = [[NSURL alloc] initWithString:[self.urlString stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];

    NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
    [req addValue:@"Basic ***=" forHTTPHeaderField:@"Authorization"];
    connection = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:YES];

}

- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response
{
    NSString *filename = [[conn.originalRequest.URL absoluteString] lastPathComponent];
    filename = [filename stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:filename];
    [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];

    file = [NSFileHandle fileHandleForUpdatingAtPath:filePath] ;
    if (file)
    {
        [file seekToEndOfFile];
    }
    else
        [self finish];
}

- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data
{
    if (file) {
        [file seekToEndOfFile];
    }
    [file writeData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
    [file closeFile];
    [self finish];
}

- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error
{
    connection = nil;

    [self finish];
}

- (void)cancel
{
    [super cancel];
    [connection cancel];
}


- (void)finish
{
    NSLog(@"operationfinished.");
}


@end

What am I doing wrong?

我究竟做错了什么?

采纳答案by Rory O'Bryan

You need to properly configure your operation to execute as a "concurrent operation"

您需要正确配置您的操作以作为“并发操作”执行

Concurrency Programming Guide: Configuring Operations for Concurrent Execution

并发编程指南:配置并发执行操作

You need to return isConcurrent = YESand properly manage the other state flags, isExecutingand isFinishedin a KVO compliant manner.

您需要返回isConcurrent = YES并妥善管理其他国家的标志,isExecutingisFinished在韩国国际志愿者组织合规的方式。



To illustrate the general idea here is a post from the engineers at Pulse that describes their solution with some easy to follow demo code you can download and review.

为了说明这里的总体思路,Pulse 工程师发表了一篇文章,其中描述了他们的解决方案,并附有一些易于理解的演示代码,您可以下载和查看。

Pulse Engineering Blog: Concurrent Downloads using NSOperationQueues**

Pulse Engineering 博客:使用 NSOperationQueues 进行并发下载**

This code also handles the requirement that NSURLConnection is started on a thread with an active runloop by ensuring that it starts it on the main thread.

此代码还通过确保在主线程上启动 NSURLConnection 来处理在具有活动 runloop 的线程上启动 NSURLConnection 的要求。

(** link is now to archive.org, I think pulse was acquired and have taken their old site down)

(** 链接现在指向 archive.org,我认为 Pulse 已被收购并已关闭他们的旧网站)