Cocoa Stream 系列2---NSInputStream的使用

在Cocoa 里面,使用 NSInputStream  实例变量,包括一些几个步骤:

     1.从一个数据源创建并初始化一个 NSInputStream 对象

     2.将第一步创建的流对象安排到当前的run loop中,并开启流对象。

     3.处理代理对象汇报的事件

     4.数据读取完毕时,dispose 流对象.

下面的介绍会详细说明上面的步骤。

准备流对象Preparing the Stream Object

使用 NSInputStream 对象之前,你必须有一个数据源,这个数据源可以是文件,an NSData object, 或者网络套接字接口 。

NSInputStream  初始化和类方法,从NSData或者文件,允许创建初始化变量,示例一从文件创建NSInputStream变量。

 

Listing 1  创建并初始化一个NSInputStream 对象
- (void)setUpStreamForFile:(NSString *)path {
    // iStream is NSInputStream instance variable
    iStream = [[NSInputStream alloc] initWithFileAtPath:path];
    [iStream setDelegate:self];
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
        forMode:NSDefaultRunLoopMode];
    [iStream open];
}

如示例所示,创建完对象,需要设置代理,当对象安排到run loop中,并有数据流相关的事件进行汇报的时候,代理接受到stream:handleEvent: 信息 ,比如当有数据流信息需要读取的时候。

在开启数据流之前,需要发送scheduleInRunLoop:forMode:信息给数据流对象,以安排其接受数据流事件,通过这个,你可以帮助代理实现避免堵塞当没有数据进行读取的时候。当数据流在其他线程发生时,确保将数据流对象安排在对应的线程的run loop 中。你绝对不能从其他不属于当前线程的run loop获取数据流。最后,发送open 信息给数据流对象,开启数据流的输入。

Handling Stream Events

数据流开启后,你可以获取到它的状态,是否有可读取的二进制流,错误信息和以下信息:

  • streamStatus

  • hasBytesAvailable

  • streamError

返回数据流当前的状态是一个NSStreamStatus常量,是否开启,正在读取中,读取到文件的最后等等。返回的错误是一个  NSError 对象,包含错误信息。

更重要的是,一旦数据流开启,它一直发送 stream:handleEvent:信息给它的代理直到其访问到文件的最后,这些信息包含一个参数,是一个 NSStreamEvent常量 ,标识着事件的类型。对于NSInputStream 对象,常用的事件类型为 are NSStreamEventOpenCompletedNSStreamEventHasBytesAvailable, and NSStreamEventEndEncountered. 代理最感兴趣的是NSStreamEventHasBytesAvailable 事件.

 示例2 介绍了一个很好的处理该事件的方法

Listing 2  Handling a bytes-available event

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
 
    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
            if(!_data) {
                _data = [[NSMutableData data] retain];
            }
            uint8_t buf[1024];
            unsigned int len = 0;
            len = [(NSInputStream *)stream read:buf maxLength:1024];
            if(len) {
                [_data appendBytes:(const void *)buf length:len];
                // bytesRead is an instance variable of type NSNumber.
                [bytesRead setIntValue:[bytesRead intValue]+len];
            } else {
                NSLog(@"no buffer!");
            }
            break;
        }
        // continued

在这个代理方法的实现中,stream:handleEvent:,使用了switch 语句,区分NSStreamEvent 变量,如果变量是 NSStreamEventHasBytesAvailable,代理首先创建一个  NSMutableData 对象(_data) 来保存获取到的二进制流,然后声明一个一定大小的缓冲区buffer(这里是1024字节),然后调用数据流对象的方法  read:maxLength: , 通过这个方法可以填充缓冲区,如果读取操作成功获取到数据流,代理会将数据流添加给 NSMutableData对象.

这里没有统一的规定关于一次性读取多少字节的数据,甚至可以一次性读取全部的数据,这取决于数据流的大小,设备和套接字接口的特点。最好的方法是使用合理的缓冲区大小,比如512字节,1M,或者4M.

如果数据流对象在处理数据的时候发生错误,会停止处理,并告知代理aNSStreamEventErrorOccurred.代理需要按照“Handling Stream Errors.”处理错误。

Disposing of the Stream Object

当数据流对象访问到数据的最后的时候,需要发送给代理a NSStreamEventEndEncountered 事件通过代理方法stream:handleEvent:发送信息. 代理需要按照创建代理相反的方法处理数据流对象。换句话说,就是关闭数据流,从 run loop中移除,最后 release 。

 示例3 展示了如何处理

Listing 3  Closing and releasing the NSInputStream object

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
    switch(eventCode) {
        case NSStreamEventEndEncountered:
        {
            [stream close];
            [stream removeFromRunLoop:[NSRunLoop currentRunLoop]
                forMode:NSDefaultRunLoopMode];
            [stream release];
            stream = nil; // stream is ivar, so reinit it
            break;
        }
        // continued ...
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值