Ios 在NSThread或NSOperation内部使用NSUrlConnection
我正在开发一个静态库,它需要在后台做一些事情,而不需要与主线程交互。为了给您一个想法,可以考虑只记录一些用户事件。库必须一直这样做,直到用户退出应用程序或将其发送到后台(按下home按钮)——换句话说,它需要在循环中继续这样做 主应用程序线程和衍生线程之间的唯一交互是,偶尔主应用程序线程会将一些内容(事件对象)放入衍生线程可以读取/使用的队列中。除此之外,生成的线程会一直运行,直到应用程序存在或出现 生成的线程需要做的部分工作(尽管不是全部)包括向HTTP服务器发送数据。我本以为可以很容易地将NSThread子类化,重写其主方法,然后在连接上使用某种超时对NSUrlConnection进行同步调用,这样线程就不会永远挂起。例如,在Java/Android中,我们只是对Thread进行子类化,重写start()方法并调用同步HTTP GET方法(比如从Apache的HttpClient类)。这是非常容易和工作良好。但从我在这里和其他地方看到的情况来看,显然在iOS上,它比这复杂得多,我有点困惑,到底什么才是最有效的方法Ios 在NSThread或NSOperation内部使用NSUrlConnection,ios,nsurlconnection,nsthread,nsoperation,synchronous,Ios,Nsurlconnection,Nsthread,Nsoperation,Synchronous,我正在开发一个静态库,它需要在后台做一些事情,而不需要与主线程交互。为了给您一个想法,可以考虑只记录一些用户事件。库必须一直这样做,直到用户退出应用程序或将其发送到后台(按下home按钮)——换句话说,它需要在循环中继续这样做 主应用程序线程和衍生线程之间的唯一交互是,偶尔主应用程序线程会将一些内容(事件对象)放入衍生线程可以读取/使用的队列中。除此之外,生成的线程会一直运行,直到应用程序存在或出现 生成的线程需要做的部分工作(尽管不是全部)包括向HTTP服务器发送数据。我本以为可以很容易地将N
那么,我应该将NSThread子类化并以某种方式使用NSUrlConnection吗?异步NSUrlConnection似乎在NSThread内不起作用,因为委托方法不会被调用,但是同步方法呢?我是否需要使用和配置RunLoop并设置自动释放池?还是应该使用NSO操作?在我看来,我正在尝试做的事情是非常常见的-有没有人有一个如何正确执行此操作的工作示例?据我所知,要异步使用
NSURLConnection
,您需要一个runloop。即使您使用NSOperation
,您仍然需要一个runloop
我看到的所有示例都使用主线程
来启动NSURLConnection
,它有一个runloop。使用NSOperation
的示例设置为Concurrent
,告诉NSOperationQueue
不要提供自己的线程,然后确保在主线程上启动NSURLConnection
,例如通过调用performselectornmainthread:
以下是一个例子:
您还可以在苹果文档中搜索LinkedImageFetcher
示例中的QRunLoopOperation
,该示例类显示了此类内容的一些细节
(虽然我不确定我是否真的看到过任何示例中显示如何运行自己的runloop的代码,但这个示例同样依赖于主线程。)我使用了grand central dispatch(GCD)方法来实现这一点。下面是一个在简单测试应用程序中对我有用的示例(我不确定它是否适用于静态库,但可能值得一看)。我用的是ARC 在本例中,我将从viewDidLoad方法开始一些背景工作,但您可以从任何地方开始。关键是“dispatch_async(dispatch_get_global_queue…”在后台线程中运行块。有关该方法的详细说明,请参阅此答案: 以下是我的viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, (unsigned long)NULL),
^(void) {
[self doStuffInBackground];
});
}
doStuffInBackground方法此时正在后台运行,因此您可以同步使用NSURLConnection。在我这里的示例中,该方法循环进行网络调用,直到可能有其他代码集backgroundStuffShouldRun=false。网络调用超时10秒。调用后,我正在更新UI标签just以显示进度。请注意,UI更新是使用“dispatch_async(dispatch_get_main_queue()…”执行的。这将根据需要在UI线程上运行UI更新
此后台工作的一个潜在问题是:无法取消http请求本身。但是,如果超时10秒,则在外部人员(可能是UI中的某个事件)设置backgroundStuffShouldRun=false后,您最多需要等待10秒,线程才会自行中止
- (void)doStuffInBackground
{
while (backgroundStuffShouldRun) {
// prepare for network call...
NSURL* url = [[NSURL alloc] initWithString:@"http://maps.google.com/maps/geo"];
// set a 10 second timeout on the request
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLCacheStorageAllowed timeoutInterval:10];
NSError* error = nil;
NSURLResponse *response = nil;
// make the request
NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
// were we asked to stop the background processing?
if (!backgroundStuffShouldRun) {
return;
}
// process response...
NSString* status = @"Success";
if (error) {
if (error.code == NSURLErrorTimedOut) {
// handle timeout...
status = @"Timed out";
}
else {
// handle other errors...
status = @"Other error";
}
}
else {
// success, handle the response body
NSString *dataAsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", dataAsString);
}
// update the UI with our status
dispatch_async(dispatch_get_main_queue(), ^{
[statusLabel setText:[NSString stringWithFormat:@"completed network call %d, status = %@", callCount, status]];
});
callCount++;
sleep(1); // 1 second breather. not necessary, but good idea for testing
}
}