[英]Stop CFRunLoop of background thread
Anyone know how to stop run loop of background thread from main thread ? 有谁知道如何从主线程停止后台线程的运行循环?
I have a class which has function for download file from server. 我有一个具有从服务器下载文件功能的类。 From main thread I am calling function sendHttpRequest in background thread to download file from server. 从主线程我在后台线程中调用函数sendHttpRequest从服务器下载文件。
[self performSelectorInBackground:@selector(sendHttpRequest:) withObject:file];
I have used CFRunLoopRun(); 我用过CFRunLoopRun(); to receive callbacks and avoid exiting thread and stopped run loop using CFRunLoopStop(CFRunLoopGetCurrent()); 接收回调并避免使用CFRunLoopStop(CFRunLoopGetCurrent())退出线程并停止运行循环; after downloading completed. 下载完成后。
But I require to stop downloading when it is in downloading data, how can I stop run loop ? 但是我需要在下载数据时停止下载,如何停止运行循环?
Any help.... 任何帮助...。
Here is my code: 这是我的代码:
#import "HTTPHandler.h"
@implementation HTTPHandler
@synthesize fileName;
NSURLConnection *urlConnection;
NSMutableData *receivedData;
NSInteger receivedStatusCode;
- (id)initHttpHandler
{
self = [super init];
httpEvent = nil;
return self;
}
- (void)downloadFile:(NSString *)file
{
NSLog(@"Download file : %@", file);
fileName = file;
NSString *url = [NSString stringWithFormat:@"http://temporaryServerUrl&fileName=%@", fileName];
NSLog(@"URL : %@", url);
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:10.0];
// create the connection with the request and start loading the data
[request setHTTPMethod:@"GET"];
[request setValue:[NSString stringWithFormat:@"text/plain,application/xml"] forHTTPHeaderField:@"Accept"];
urlConnection =[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (urlConnection)
{
// Create the NSMutableData to hold the received data.
receivedData = [[NSMutableData data] retain];
}
else
{
NSLog(@"HTTP connection failed to download file.");
}
NSLog(@"Run loop started");
CFRunLoopRun(); // Avoid thread exiting
NSLog(@"Run loop stoped");
}
- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace (NSURLProtectionSpace *)protectionSpace
{
if ([NSURLAuthenticationMethodHTTPDigest compare:[protectionSpace authenticationMethod]] == NSOrderedSame)
{
return YES;
}
else
{
NSLog(@"Warning: Unsupported HTTP authentication method.");
}
return NO;
}
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge (NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0)
{
NSURLCredential *newCredential;
newCredential = [NSURLCredential credentialWithUser:@"admin" password:@"1234" persistence:NSURLCredentialPersistenceNone];
[[challenge sender] useCredential:newCredential forAuthenticationChallenge:challenge];
}
else
{
NSLog(@"Going to cancel the authentication challenge.");
[[challenge sender] cancelAuthenticationChallenge:challenge];
// inform the user that the user name and password in the preferences are incorrect
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
[receivedData setLength:0];
receivedStatusCode = httpResponse.statusCode;
if (httpResponse.statusCode == 200)
{
NSLog(@"200 ok received");
}
else
{
// We can also add condition that status code >= 400 for failure.
NSLog(@"%d status code is received.", httpResponse.statusCode);
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData. receivedData is an instance variable declared elsewhere.
if ([urlConnection isEqual:connection])
{
[receivedData appendData:data];
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
// receivedData is declared as a method instance elsewhere
[receivedData release];
// inform the user
NSLog(@"Connection failed! Error domain - %@, error code %d, error discryption - %@", [error domain], [error code], [error localizedDescription]);
// stop a CFRunLoop from running.
CFRunLoopStop(CFRunLoopGetCurrent());
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([urlConnection isEqual:connection] && (receivedStatusCode == 200))
{
NSString *filePath;
NSString *rootPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
filePath = [rootPath stringByAppendingPathComponent:fileName];
NSLog(@"File Path %@", filePath);
NSString *data = [[[NSString alloc] initWithData:receivedData encoding:NSISOLatin1StringEncoding] autorelease];
NSLog(@"Data : %@", data);
[data writeToFile:filePath atomically:YES encoding:NSISOLatin1StringEncoding error:NULL];
}
else
{
}
[urlConnection release];
[receivedData release];
// stop a CFRunLoop from running.
CFRunLoopStop(CFRunLoopGetCurrent());
}
@end
Communication between threads is a very commong problem and there is a lot of possible solutions. 线程之间的通信是一个非常普遍的问题,并且有很多可能的解决方案。
One solution I see is not using performSelectorInBackground:
but instead creating a NSThread
instance, save the thread reference and call start
. 我看到的一种解决方案不是使用performSelectorInBackground:
而是创建一个NSThread
实例,保存线程引用并调用start
。 Then you can use one of the [NSObject performSelector:onThread:...]
methods to call the stop method (don't forget to actually cancel the request before stopping the loop). 然后,您可以使用[NSObject performSelector:onThread:...]
方法之一来调用stop方法(不要忘记在停止循环之前实际取消请求)。
Another solution could be to call CFRunLoopRun
with a timeout inside a while
cycle, waiting for some condition to happen. 另一种解决方案是在一段while
周期内调用CFRunLoopRun
并超时,以等待某些情况发生。 See the answer in iPhone: how to use performSelector:onThread:withObject:waitUntilDone: method? 请参阅iPhone中的答案:如何使用performSelector:onThread:withObject:waitUntilDone:方法? . 。
Another solution is to use local notifications ( NSNotificationCenter
). 另一种解决方案是使用本地通知( NSNotificationCenter
)。 The background thread can register itself for notification and the main thread can send them when a condition happens. 后台线程可以自行注册以进行通知,而主线程可以在条件发生时发送它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.