在后台线程中运行NSStream

4

我目前正在尝试将整个网络操作放在后台线程中运行,因为当前的情况是当服务器不可用时(例如),它会阻塞主线程。

我目前通过以下代码创建网络连接。有没有简单的方法可以在新的后台线程中运行它?

如何将接收到的消息传递回主线程?如何通过后台线程发送消息?

CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)ipAdress, port, &readStream, &writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[inputStream open];
[outputStream open];

由于您正在使用运行循环而不是轮询流,您认为将其推送到后台线程中可以解决特定的问题吗? - 一二三
嗨,我不确定,因为我对Objective-C中的线程和协作不是很熟悉。我愿意听取其他建议。有没有好的教程可以解决这个问题?谢谢! - Lukas
问题是什么?为什么你想要使用一个单独的线程? - 一二三
问题在于如果服务器不可用,我的连接会阻塞主线程约30秒钟。我使用了苹果的可达性类来检查连接是否可用,但我认为这不是一个好的方法。 - Lukas
我刚刚更新了我的答案,使其更易读。如果这正是你要找的,请告诉我。 - abbood
谢谢!我会在晚上查看并告诉你! :) - Lukas
1个回答

5

这里有一个教程,可以满足您所需的要求。虽然它更侧重于音频流,但原则上是完全相同的(例如生成工作线程,使其与父线程进行通信等等)。

想法很简单..您创建一个新线程,并让它处理流媒体工作,然后将流阅读器安排到刚刚创建的线程所属的运行循环中。当发生某些事件时(例如获取一些数据,连接超时等),流媒体将具有回调函数,它们将被触发。在回调方法中,您可以警报或与主线程(即处理UI的线程)通信。

这里是一些代码帮助您朝正确的方向前进,但如果您从上面的教程中下载代码并跟随操作,就能懂得了:

// create a new thread
internalThread =
                [[NSThread alloc]
                    initWithTarget:self
                    selector:@selector(startInternal)
                    object:nil];
            [internalThread start];

// creating a stream inside the 'startInternal' thread*
stream = CFReadStreamCreateForHTTPRequest(NULL, message);

// open stream
CFReadStreamOpen(stream) 

// set callback functions
// ie say: if there are bites available in the stream, fire a callback etc
CFStreamClientContext context = {0, self, NULL, NULL, NULL};
CFReadStreamSetClient(
        stream,
        kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
        ASReadStreamCallBack,
        &context);

// schedule stream in current thread runloop, so that we DON'T block the mainthread
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);

// create the callback function to handle reading from stream
// NOTE: see where else in the code this function is named (ie CFReadStreamSetClient)
static void ASReadStreamCallBack
(
   CFReadStreamRef aStream,
   CFStreamEventType eventType,
   void* inClientInfo
)
{
    //handle events you registered above
    // ie
    if (eventType == kCFStreamEventHasBytesAvailable) {
        // handle network data here..
        ..
        // if something goes wrong, create an alert and run it through the main thread:
        UIAlertView *alert = [
            [[UIAlertView alloc]
                initWithTitle:title
                message:message
                delegate:self
                cancelButtonTitle:NSLocalizedString(@"OK", @"")
                otherButtonTitles: nil]
            autorelease];
            [alert
                performSelector:@selector(show)
                onThread:[NSThread mainThread]
                withObject:nil
                waitUntilDone:NO];        
    }          
}

感谢您的帮助,但不是我正在寻找的。最终我通过遵循以下指南解决了问题。http://benincosa.com/blog/?p=449 无论如何,还是要感谢您的努力! - Lukas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接