暂停和恢复 ASINetworkQueue

发布于 2024-12-29 15:09:13 字数 421 浏览 2 评论 0原文

我正在使用 ASINetworkQueue 在 iPad 应用程序中下载大约 50 个文件。我正在寻找一种允许用户暂停和恢复队列的方法。

ASIHTTP 文档提到,

[request setAllowResumeForFileDownloads:YES];

但这在单个请求级别运行,而不是在队列级别运行。由于 ASINetworkQueue 是 NSOperationQueue 的子类,我也尝试过

[queue setSuspended:YES];

,虽然这会暂停队列,但它不会影响正在进行的下载,它只是等待下载完成,然后暂停队列,在我的情况下这意味着很多秒在用户按下按钮和队列实际暂停之间,这不是我想要的 UI 体验。

谁能建议另一种方法来解决这个问题?

I'm using an ASINetworkQueue to download around 50 files in an iPad app. I'm looking for a way of allowing the user to pause and resume the queue.

The ASIHTTP docs refer to

[request setAllowResumeForFileDownloads:YES];

but this operates at an individual request level, not at the queue level. As ASINetworkQueue is a subclass of NSOperationQueue I've also tried

[queue setSuspended:YES];

and while this will pause a queue, it does not affect the downloads in progress, it just waits until they've finished and then pauses the queue, which in my case means many seconds between the user pressing the button and the queue actually pausing, which is not the UI experience I want.

Can anyone suggest another way of solving this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倾城泪 2025-01-05 15:09:13

我的解决方案..

- (void) pause
{
    if(self.queue && self.queue.requestsCount>0)
    {
        NSLog(@"%@", self.queue.operations);

        for (ASIHTTPRequest * req in self.queue.operations) {
            req.userInfo = [NSDictionary dictionaryWithObject:@"1" forKey:@"ignore"];
        }

        [self.queue.operations makeObjectsPerformSelector:@selector(cancel)];

        [self.queue setSuspended:YES];

        for (ASIHTTPRequest * req in self.queue.operations) {
            ASIHTTPRequest * newReq = [[ASIHTTPRequest alloc] initWithURL:req.url];
            [newReq setDownloadDestinationPath:req.downloadDestinationPath];
            [newReq setTemporaryFileDownloadPath:req.temporaryFileDownloadPath];
//            [newReq setAllowResumeForFileDownloads:YES];
            [newReq setUserInfo:req.userInfo];
            [self.queue addOperation:newReq];

        }

    }
}

- (void) resume
{
    if(self.queue && self.queue.requestsCount>0)
    {
        [self _setupQueue];
        [self.queue go];
    }
}

- (void) _setupQueue
{
    [self.queue setShouldCancelAllRequestsOnFailure:NO];
    [self.queue setRequestDidStartSelector:@selector(downloadDidStart:)];
    [self.queue setRequestDidFinishSelector:@selector(downloadDidComplete:)];
    [self.queue setRequestDidFailSelector:@selector(downloadDidFailed:)];
    [self.queue setQueueDidFinishSelector:@selector(queueDidFinished:)];
    [self.queue setDownloadProgressDelegate:self.downloadProgress];
    [self.queue setDelegate:self];
    self.queue.maxConcurrentOperationCount = 3;
//    self.queue.showAccurateProgress = YES;
}

首先,暂停函数取消所有正在运行的操作,并重新创建新请求将它们推入队列。
然后恢复函数取消暂停队列。
注意,请求不要设置setAllowResumeForFileDownloads:YES,否则totalBytesToDownload会计算错误。如果allowResumeForFileDownloads=NO,其值将与队列中的请求数相同。

这是我的请求失败处理程序,我在文件下载失败时添加重试。但我不希望取消请求时会调用重试机制,因此我将 userInfo(ignore:true) 设置为 request 对象以防止发生这种情况。

- (void) downloadDidFailed:(ASIHTTPRequest *)req
{
    NSLog(@"request failed");
    NSLog(@"%d", self.queue.requestsCount);

    if(![self.queue showAccurateProgress])
    {
        [self.queue setTotalBytesToDownload:[self.queue totalBytesToDownload]-1];
        NSLog(@"totalBytesToDownload=%lld", self.queue.totalBytesToDownload);
    }

    NSDictionary * userInfo = req.userInfo;
    if([[userInfo valueForKey:@"ignore"] boolValue]) return; // ignore retry

    int retryTimes = [[req.userInfo objectForKey:@"retryTimes"] intValue];
    if(retryTimes<kMU_MaxRetry)
    {
        ++ retryTimes;
        NSLog(@"retry %d", retryTimes);
        ASIHTTPRequest * newReq = [ASIHTTPRequest requestWithURL:req.url];
        [newReq setDownloadDestinationPath:req.downloadDestinationPath];
        [newReq setTemporaryFileDownloadPath:req.temporaryFileDownloadPath];
        newReq.userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", retryTimes] forKey:@"retryTimes"];
        [self.queue addOperation:newReq];

        NSLog(@"%d", self.queue.requestsCount);
    }else{  // reach max retry, fail it
        [self.failures addObject:req];
    }
}

不知道有没有更好的解决办法,希望可以帮到你。

My solution..

- (void) pause
{
    if(self.queue && self.queue.requestsCount>0)
    {
        NSLog(@"%@", self.queue.operations);

        for (ASIHTTPRequest * req in self.queue.operations) {
            req.userInfo = [NSDictionary dictionaryWithObject:@"1" forKey:@"ignore"];
        }

        [self.queue.operations makeObjectsPerformSelector:@selector(cancel)];

        [self.queue setSuspended:YES];

        for (ASIHTTPRequest * req in self.queue.operations) {
            ASIHTTPRequest * newReq = [[ASIHTTPRequest alloc] initWithURL:req.url];
            [newReq setDownloadDestinationPath:req.downloadDestinationPath];
            [newReq setTemporaryFileDownloadPath:req.temporaryFileDownloadPath];
//            [newReq setAllowResumeForFileDownloads:YES];
            [newReq setUserInfo:req.userInfo];
            [self.queue addOperation:newReq];

        }

    }
}

- (void) resume
{
    if(self.queue && self.queue.requestsCount>0)
    {
        [self _setupQueue];
        [self.queue go];
    }
}

- (void) _setupQueue
{
    [self.queue setShouldCancelAllRequestsOnFailure:NO];
    [self.queue setRequestDidStartSelector:@selector(downloadDidStart:)];
    [self.queue setRequestDidFinishSelector:@selector(downloadDidComplete:)];
    [self.queue setRequestDidFailSelector:@selector(downloadDidFailed:)];
    [self.queue setQueueDidFinishSelector:@selector(queueDidFinished:)];
    [self.queue setDownloadProgressDelegate:self.downloadProgress];
    [self.queue setDelegate:self];
    self.queue.maxConcurrentOperationCount = 3;
//    self.queue.showAccurateProgress = YES;
}

First, pause function cancel all running operations, and recreate new requests push them into queue.
Then resume function unsuspends the queue.
Be noticed, request should not set setAllowResumeForFileDownloads:YES, otherwise the totalBytesToDownload will calculate wrong..If allowResumeForFileDownloads=NO, its value will be same as the count of requests in queue.

Here is my request fail handler, I add retry when file download fail. But I don't whant when I cancel a request, the retry mechanism will be invoked, so I set userInfo(ignore:true) to request object to prevent it happens.

- (void) downloadDidFailed:(ASIHTTPRequest *)req
{
    NSLog(@"request failed");
    NSLog(@"%d", self.queue.requestsCount);

    if(![self.queue showAccurateProgress])
    {
        [self.queue setTotalBytesToDownload:[self.queue totalBytesToDownload]-1];
        NSLog(@"totalBytesToDownload=%lld", self.queue.totalBytesToDownload);
    }

    NSDictionary * userInfo = req.userInfo;
    if([[userInfo valueForKey:@"ignore"] boolValue]) return; // ignore retry

    int retryTimes = [[req.userInfo objectForKey:@"retryTimes"] intValue];
    if(retryTimes<kMU_MaxRetry)
    {
        ++ retryTimes;
        NSLog(@"retry %d", retryTimes);
        ASIHTTPRequest * newReq = [ASIHTTPRequest requestWithURL:req.url];
        [newReq setDownloadDestinationPath:req.downloadDestinationPath];
        [newReq setTemporaryFileDownloadPath:req.temporaryFileDownloadPath];
        newReq.userInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"%d", retryTimes] forKey:@"retryTimes"];
        [self.queue addOperation:newReq];

        NSLog(@"%d", self.queue.requestsCount);
    }else{  // reach max retry, fail it
        [self.failures addObject:req];
    }
}

I am not sure if there is a better solution, hope it can help you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文