2013-04-24 79 views
0

任何人都知道如何停止从主线程运行循环的后台线程?停止后台线程的CFRunLoop

我有一个类,它具有从服务器下载文件的功能。从主线程我调用函数sendHttpRequest在后台线程从服务器下载文件。

[self performSelectorInBackground:@selector(sendHttpRequest:) withObject:file]; 

我已经使用CFRunLoopRun();接收回调并避免使用CFRunLoopStop(CFRunLoopGetCurrent())退出线程并停止运行循环;下载完成后。

但是我在下载数据时需要停止下载,如何停止运行循环?

任何帮助....

这里是我的代码:

#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 

回答

1

线程之间的通信是一个非常commong问题,有很多可能的解决方案

我看到的一种解决方案是不使用performSelectorInBackground:,而是创建一个NSThread实例,保存线程引用并致电start。然后,您可以使用[NSObject performSelector:onThread:...]方法之一调用停止方法(不要忘记在停止循环之前实际取消请求)。

另一种解决方案可能是在while周期内调用CFRunLoopRun,并等待发生某种情况。请参阅iPhone: how to use performSelector:onThread:withObject:waitUntilDone: method?中的答案。

另一种解决方案是使用本地通知(NSNotificationCenter)。后台线程可以注册自己的通知,并且主线程可以在情况发生时发送它们。

+0

假设我使用你的第一个选项,那么我该如何继续该线程?使用一个标志和while循环? – 2013-04-24 10:13:49

+0

@Mdroid“继续”是什么意思?当你停下来时,线程将会结束。 – Sulthan 2013-04-24 10:56:14

+0

您可以提供链接或最后一个选项的任何示例(使用本地通知)。我发现[this](http://www.cocoawithlove.com/2009/08/safe-threaded-design-and-inter-thread.html)和[此文档](http://developer.apple.com/ library/ios /#documentation/Cocoa/Conceptual/Notifications/Articles/Threading.html#// apple_ref/doc/uid/20001289-CEGJFDFG) – 2013-04-25 04:23:50