cocoa - 写入问题 `NSOutputStream` 。

标签 cocoa macos objective-c++ nsstream

我有一个基本问题, 在使用 NSOutputStream 时,我们是否应该等待 NSStreamEventHasSpaceAvailable 发送数据包,以便我们可以在需要时调用,[NSOutputStream write] ,

我相信 NSStream 应该负责写入功能...

如果这是不正确的,那么请提供您对以下逻辑的看法,

===== 在 NSOutputStream 上写入 ================= 有队列添加要发送的数据包 //StreamQueue.h

@interface StreamQueue : NSObject <NSCoding>
{
    NSMutableArray * data;
    NSRecursiveLock * theLock;
}

#pragma mark �Initialization & Deallocation�
- (id)init;
- (id)initWithQueue:(CommQueue *)queue;
- (id)initWithCoder:(NSCoder *)coder;
- (void)dealloc;
- (void)encodeWithCoder:(NSCoder *)coder;

#pragma mark
#pragma mark �Accessor Methods�
- (int)size;
- (BOOL)isEmpty;
- (id)top;
- (NSArray *)data;

#pragma mark
#pragma mark �Modifier Methods�
- (void)enqueue:(id)object;
- (id)dequeue;
- (void)removeAll;
@end

及其实现

#import "StreamQueue.h"


@implementation StreamQueue
#pragma mark �Initialization & Deallocation�
- (id)init
{
    if (self = [super init]) {
        data = [[NSMutableArray alloc] init];
        theLock = [[NSRecursiveLock alloc] init];
    }
    return self;
}

- (id)initWithQueue:(StreamQueue *)queue
{
    if (self = [super init]) {
        data = [[NSMutableArray alloc] initWithArray:[queue data]];
        theLock = [[NSRecursiveLock alloc] init];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)coder
{
    if (self = [super init]) {
        data = [[NSMutableArray alloc] initWithArray:[coder decodeObject]];
        theLock = [[NSRecursiveLock alloc] init];
    }
    return self;
}

- (void)dealloc
{
    [data release];
    [theLock release];
    [super dealloc];
}

- (void)encodeWithCoder:(NSCoder *)coder;
{
    [coder encodeObject:data];
}

#pragma mark
#pragma mark �Accessor Methods�
- (int)size
{
    int size;
    [theLock lock];
    size = [data count];
    [theLock unlock];
    return size;
}

- (BOOL)isEmpty
{
    BOOL empty;
    [theLock lock];
    empty = ([data count] == 0);
    [theLock unlock];
    return empty;
}

- (id)top
{
    id object = nil;
    [theLock lock];
    if (![self isEmpty])
        object = [data objectAtIndex:0];
    [theLock unlock];
    return object;
}

- (NSArray *)data
{
    NSArray * array;
    [theLock lock];
    array = [NSArray arrayWithArray:data];
    [theLock unlock];
    return array;
}

#pragma mark
#pragma mark �Modifier Methods�
- (void)enqueue:(id)object
{
    [theLock lock];
    [data addObject:object];
    [theLock unlock];
}

- (id)dequeue
{
    id object = [self top];
    if (object != nil) {
        [theLock lock];
        [object retain];
        [data removeObjectAtIndex:0];
        [theLock unlock];
    }
    return [object autorelease];
}

- (void)removeAll
{
    [theLock lock];
    while (![self isEmpty])
        [data removeObjectAtIndex:0];
    [theLock unlock];
}
@end

现在,当应用程序有东西要通过套接字(NSStream)发送时,它应该将其添加到队列中,

-(bool)sendRawData:(const uint8_t *)data length:(int)len{

    // if still negotiating then don't send data
    assert(!networkConnected);

    NSData *pData  = [NSData dataWithBytes:(const void *)data length:len];

    // pToSendPacket is of type StreamQueue 
    [pToSendPacket enqueue:pData];

    return;
}

当我们得到NSHasSpaceAvailableEvent时这段代码

-(void)gotSpaceAvailable{
    // is there any pending packets that to be send. 
    NSData *pData = (NSData *)[pToSendPacket dequeue];

    if(pData == nil){
        // no pending packets.. 
        return;
    }

    const uint8_t *data = (const uint8_t *)[pData bytes];
    int len = [pData length];

    int sendlength = [pOutputStream write:data maxLength:len];

    if(sendlength == -1 ){
        NSError *theError = [pOutputStream streamError];
        NSString *pString = [theError localizedDescription];
        int errorCode = [theError code];
        return ;
    }
}

我期望每当 OutputStream 发送数据时应用程序将继续接收事件,但我只收到一次......:( 请帮忙...

最佳答案

如果不等待该事件,写入调用将阻塞,直到有可用空间为止。一般来说,您希望将代码设计为异步工作,因此等待 NSStreamEventHasSpaceAvailable 是最好的解决方案。

至于您何时收到可用空间通知,see the documentation here :

If the delegate receives an NSStreamEventHasSpaceAvailable event and does not write anything to the stream, it does not receive further space-available events from the run loop until the NSOutputStream object receives more bytes. When this happens, the run loop is restarted for space-available events. If this scenario is likely in your implementation, you can have the delegate set a flag when it doesn’t write to the stream upon receiving an NSStreamEventHasSpaceAvailable event. Later, when your program has more bytes to write, it can check this flag and, if set, write to the output-stream instance directly.

There is no firm guideline on how many bytes to write at one time. Although it may be possible to write all the data to the stream in one event, this depends on external factors, such as the behavior of the kernel and device and socket characteristics. The best approach is to use some reasonable buffer size, such as 512 bytes, one kilobyte (as in the example above), or a page size (four kilobytes).

因此,只要您为每个事件写入数据,您就应该定期获取 NSStreamEventHasSpaceAvailable 事件。

关于cocoa - 写入问题 `NSOutputStream` 。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7038380/

相关文章:

objective-c - 为什么文本字段中闪烁的光标会导致调用 drawRect?

objective-c - 如何在自定义 View 中禁用用户交互

javascript - JXA NSFileManager createDirectoryAtPathWithIntermediateDirectoriesAttributesError 异常

c++ - 在 Objective C++ .mm 文件中包含 POCO 头文件会导致 Xcode 6 出现编译错误

macos - NSSplitViewController 导致包含的 View 绘制在窗口角上

php - 从 PHP 中的 RNCryptor AES 256 header 中检索 IV

cocoa - 问题: Rendering stops with OpenGL on Mac OS X 10. 6

macOS X Lion 上的 Java UI

ios - 无法识别的选择器发送到实例 - UIViewController

objective-c - 声明包含 C++ 类类型 ivar 的 obj-c 类接口(interface)