gpt4 book ai didi

ios - 如何在另一个线程上正确打开和关闭 NSStream

转载 作者:行者123 更新时间:2023-12-01 15:18:41 24 4
gpt4 key购买 nike

我有一个应用程序在另一个线程上使用 NSStream 连接到服务器。如果用户决定注销,应用程序也会关闭连接。问题是我永远无法在用户断开连接后成功关闭流或线程。下面是关于如何为网络创建线程并尝试关闭流的代码示例:

+ (NSThread*)networkThread
{
static NSThread *networkThread = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
networkThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkThreadMain:) object:nil];

[networkThread start];
});

return networkThread;
}

+ (void)networkThreadMain:(id)sender
{
while (YES)
{
@autoreleasepool {
[[NSRunLoop currentRunLoop] run];
}
}
}

- (void)scheduleInThread:(id)sender
{
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[inputStream open];
}

- (void)closeThread
{
[inputStream close];
[inputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[inputStream release];
inputStream = nil;
}

尝试连接输入流时调用:
[self performSelector:@selector(scheduleInThread:) onThread:[[self class] networkThread] withObject:nil waitUntilDone:YES];

任何意见是极大的赞赏。

最佳答案

您混合静态变量和实例变量的方式令人困惑。你结婚就这样吗?如果你把它放在一个 NSOperation 中并使用一个 NSOperationQueue 运行它,我认为你会得到更清晰的封装。该操作将管理自己的异步线程,因此您不必这样做。另外,如果可以的话,我强烈建议使用 ARC。
几点注意事项:

  • 确保设置流的委托(delegate)并处理委托(delegate)事件。您可能应该在操作中执行此操作(使操作成为委托(delegate))并在必要时关闭流并完成操作。
  • 除了 NSStreamStatusClosed 之外,流可能还有其他失败情况,例如 NSStreamStatusNotOpen 等。您可能需要添加额外的处理,这可以通过监听委托(delegate)方法来完成。
  • 您的代码可能无法正常工作,主要是因为您的 while 循环永远运行 runloop。你必须具备爆发的条件。 NSOperation 为您提供了一些非常好的标准化方法。
  • #import <Foundation/Foundation.h>

    NS_ASSUME_NONNULL_BEGIN

    @interface AsyncStreamOperation : NSOperation

    @end

    NS_ASSUME_NONNULL_END
    #import "AsyncStreamOperation.h"

    @interface AsyncStreamOperation ()

    @property (atomic, strong) AsyncStreamOperation *config;

    @property (atomic, strong) NSInputStream *stream;

    @property (atomic, assign, getter=isExecuting) BOOL executing;
    @property (atomic, assign, getter=isFinished) BOOL finished;

    @end

    @implementation AsyncStreamOperation

    @synthesize executing = _executing;
    @synthesize finished = _finished;

    - (instancetype)initWithStream:(NSInputStream *)stream
    {
    self = [super init];

    if(self) {
    _stream = stream;
    }

    return self;
    }

    - (BOOL)isAsynchronous
    {
    return YES;
    }

    - (BOOL)isExecuting
    {
    @synchronized (self) {
    return _executing;
    }
    }

    - (void)setExecuting:(BOOL)executing
    {
    @synchronized (self) {
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
    }
    }

    - (BOOL)isFinished
    {
    @synchronized (self) {
    return _finished;
    }
    }

    - (void)setFinished:(BOOL)finished
    {
    @synchronized (self) {
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
    }
    }

    - (void)start
    {
    // Get runloop
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

    // Schedule stream
    [self.stream scheduleInRunLoop:runLoop forMode:NSDefaultRunLoopMode];
    [self.stream open];

    // Loop until finished
    // NOTE: If -cancel is not called, you need to add your own logic to close the stream so this loop ends and the operation completes
    while(self.executing && !self.finished && !self.cancelled && self.stream.streamStatus != NSStreamStatusClosed) {
    @autoreleasepool {
    // Maximum speed once per second or CPU goes through the roof
    [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
    }
    }

    self.executing = NO;
    self.finished = YES;
    }

    - (void)cancel
    {
    [super cancel];

    [self.stream close];

    self.executing = NO;
    self.finished = YES;
    }

    @end

    关于ios - 如何在另一个线程上正确打开和关闭 NSStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10980874/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com