利用libcurl进度数据

时间:2013-04-19 12:52:38

标签: c++ xcode cocoa libcurl

在Xcode中设置了一堆curl_easy_setopt函数,用于将文件上传到服务器/ API,并且(经过大量的试验和错误)它都像魅力一样。经过其他几个Q& As之后我还设法设置了一个简单的CURLOPT_PROGRESSFUNCTION,如下所示:

static int my_progress_func(void *p,
                        double t,
                        double d,
                        double ultotal,
                        double ulnow)
{
printf("(%g %%)\n", ulnow*100.0/ultotal);
// globalProgressNumber = ulnow*100.0/ultotal;
return 0;
}

随着上传的进行,“0%.. 16%.. 58%.. 100%”输出到控制台;灿烂。 我无法做的是实际使用这个数据(globalProgressNumber),例如。对于我的NSProgressIndicator; CURL类型劫持我的应用程序,并且在进度完成之前不允许任何其他输入/输出。

我尝试从my_progress_func更新IBOutlets(例如[_myLabel setStringValue:globalProgressNumber];)但是静态int函数不允许这样做。 也不允许[自我],因此无法发布到NSNotificationCenter:     [[NSNotificationCenter defaultCenter] postNotificationName:@"Progressing" object:self];

我的curl函数从我的主类/窗口(NSPanel)运行。

关于如何在我的.xib上实现实时/更新元素的任何好建议?

1 个答案:

答案 0 :(得分:1)

  

CURL [...]在进度完成之前不允许任何其他输入/输出。

你是从主线程调用curl_easy_perform吗?如果是,则不应该这样做,因为此函数是同步的,即它会在传输完成之前阻塞。

换句话说,长时间运行的任务(例如网络I / O)必须在单独的线程上运行,而UI代码(例如更新标签的文本)必须在主线程上运行。

  

如何实现实时/更新元素

你一定要注意在一个单独的线程中执行卷曲传输。

通过使用自定义协议将其包装到NSOperation以通知代表进度(例如视图控制器),可以轻松实现这一点:

  • 将您的操作推送到NSOperationQueue
  • 操作队列将负责分离传输并将其运行到另一个线程
  • 在操作方面,您仍然应该使用progress函数并通过CURLOPT_PROGRESSDATA curl选项将操作对象设置为不透明对象。通过这样做,每次调用progress函数时,您都可以通过强制转换void *clientp不透明指针来检索操作对象。然后通知代理当前进度在主线程中(例如performSelectorOnMainThread),以确保您可以执行UI更新,例如刷新NSProgressIndicator

作为NSOperation的替代方案,您还可以使用Grand Central Dispatch(GCD)和阻止。如果可能,我强烈建议您使用BBHTTP,这是iOS 5+和OSX 10.7+的libcurl客户端(BBHTTP使用GCD和块)。

仅供参考:这是一个example from BBHTTP,它说明了如何使用上传进度块轻松执行文件上传 - 这适用于iOS,但应该可以直接重用于OS X.