iphone - 停止后台线程的CFRunLoop

标签 iphone ios nsurlconnection

有人知道如何从主线程停止后台线程的运行循环吗?

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

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

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

但是我要求在下载数据时停止下载,如何停止runloop?

任何帮助......

这是我的代码:

#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

最佳答案

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

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

另一个解决方案可能是调用 CFRunLoopRun while 内有超时循环,等待某些条件发生。请参阅 iPhone: how to use performSelector:onThread:withObject:waitUntilDone: method? 中的答案.

另一个解决方案是使用本地通知 ( NSNotificationCenter )。后台线程可以自行注册通知,主线程可以在条件发生时发送通知。

关于iphone - 停止后台线程的CFRunLoop,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16187664/

相关文章:

iphone - 比较 NSdate 时出现意外错误

ios - 为什么 NSURL Connection Received Data 包含字节,但在转换为 NSString 时,字符串为 Null?

iOS 分段上传照片

使用 MDM 的 iOS 配置文件更新流程

ios - 将 UIImagepicker 中的图像插入到 UICollectionViewCell Swift 中

ios - 是什么导致 NSURLConnection 在完成之前停止接收?

iphone - 测试网络访问受限的 iPhone 应用程序

iphone - 从 iPhone 上的流中获取 ID3 标签

iphone - 在按钮操作上传递参数 :@selector

ios - swift:重新加载 View 以在图表中显示新数据