您混合静态变量和实例变量的方式令人困惑。你结婚就这样吗?如果你把它放在一个 NSOperation 中并使用一个 NSOperationQueue 运行它,我认为你会得到更清晰的封装。该操作将管理自己的异步线程,因此您不必这样做。另外,如果可以的话,我强烈建议使用 ARC。
几点注意事项:
- 确保设置流的委托并处理委托事件。您可能应该在操作中执行此操作(使操作成为委托)并在必要时关闭流并完成操作。
- 除了 NSStreamStatusClosed 之外,流可能还有其他失败情况,例如 NSStreamStatusNotOpen 等。您可能需要添加额外的处理,这可以通过侦听委托方法来完成。
- 您的代码可能无法正常工作,主要是因为您的 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