0

在 Xcode 中设置了一堆 curl_easy_setopt-functions 用于将文件上传到服务器/API,并且(经过大量试验和错误)它就像一个魅力。在经历了其他几个问答之后,我还设法设置了一个简单的 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 函数不允许这样做。[self] 也不允许,因此无法发布到 NSNotificationCenter: [[NSNotificationCenter defaultCenter] postNotificationName:@"Progressing" object:self];

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

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

4

1 回答 1

1

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

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

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

如何实现实时/更新元素

您绝对应该注意在单独的线程中执行卷曲传输。

这可以通过将其包装成NSOperation一个自定义协议来通知委托进度(例如您的视图控制器)来轻松实现:

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

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

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

于 2013-04-20T15:38:47.260 回答