1,从输入流中读取:
1) 创建和初始化一个 NSInputStream实例
2)Schedule流对象到一个run loop并打开流
3)处理流对象的事件--使用代理
4)当没有数据可读时,销毁流对象。
1)准备流对象:需要有一个文件,一个NSData 或 一个网络socket
Listing 1 Creating and initializing an NSInputStream object
- (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];
}
2)处理流事件:
在流对象open之后,你就刻意查看其状态、是否有可用的字节可读和任何原始错误信息等,如下所示:
streamStatus
hasBytesAvailable
streamError
streamStatus返回的状态是一个 NSStreamStatus常量,指示流是opening、reading,还是到了流的末尾,等等。
streamError返回的错误信息是一个NSError对象,封装了错误发生的位置。
最重要的是,一旦流打开了,他就开始持续发送 stream:handleEvent:消息给其代理,直到其遇到流的末尾。这些消息包括一个参数,是一个 NSStreamEvent常量,用来指示事件类型。对于NSInputStream来说,最常见的事件类型是 NSStreamEventOpenCompleted, NSStreamEventHasBytesAvailable,和 NSStreamEventEndEncountered。代理一般最感兴趣 NSStreamEventHasBytesAvailable。下面是一个例子:
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
3)销毁流对象:
- (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 ...
}
}
二,向输入流写入:
1)创建并初始化一个NSOutputStream,并设置一个代理
2)安排流对象到一个run loop并打开。
3)处理事件
4)如果流对象已经将数据写入内存,通过键NSStreamDataWritenToMemoryStreamKey来获得数据。
5)当没有更多的数据需要写时,销毁流对象。
1)准备流对象:必须给输入流指定一个目标,刻意是一个文件,一个C buffer,应用程序内存,或一个网络socket
创建并初始化输出流到内存的例子:
- (void)createOutputStream {
NSLog(@"Creating and opening NSOutputStream...");
// oStream is an instance variable
oStream = [[NSOutputStream alloc] initToMemory];
[oStream setDelegate:self];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[oStream open];
}
2)在流open之后,你可以获取
streamStatus
hasSpaceAvailable
streamError
状态为一个NSStreamStatus枚举,指示流是opening,writing,流的末尾 等等
代理同样是stream:handleEvent: event也是NSStreamEvent枚举,一半是NSStreamEventOpenCompleted.NSStreamEventHasSpaceAvailable,和NSStreamEventEndEncountered。
Listing 2 Handling a space-available event
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode) {
case NSStreamEventHasSpaceAvailable:
{
uint8_t *readBytes = (uint8_t *)[_data mutableBytes];
readBytes += byteIndex; // instance variable to move pointer
int data_len = [_data length];
unsigned int len = ((data_len - byteIndex >= 1024) ?
1024 : (data_len-byteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [stream write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
break;
}
// continued ...
}
}
3)销毁流对象;
Listing 3 Closing and releasing the NSInputStream object
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode) {
case NSStreamEventEndEncountered:
{
NSData *newData = [oStream propertyForKey:
NSStreamDataWrittenToMemoryStreamKey];
if (!newData) {
NSLog(@"No data written to memory!");
} else {
[self processData:newData];
}
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[stream release];
oStream = nil; // oStream is instance variable
break;
}
// continued ...
}
}
通过给NSOutputStream对象发送一个propertyForKey:消息,指定键为NSStreamDataWrittenToMemoryStreamKey,可以获得其写入内存的数据,返回一个NSData对象。
三、Polling Versus Run-Loop Scheduling
四、处理流错误
五、Setting up Socket Streams:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Streams/Articles/PollingVersusRunloop.html#//apple_ref/doc/uid/20002275-CJBEDDBG
1) 创建和初始化一个 NSInputStream实例
2)Schedule流对象到一个run loop并打开流
3)处理流对象的事件--使用代理
4)当没有数据可读时,销毁流对象。
1)准备流对象:需要有一个文件,一个NSData 或 一个网络socket
Listing 1 Creating and initializing an NSInputStream object
- (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];
}
2)处理流事件:
在流对象open之后,你就刻意查看其状态、是否有可用的字节可读和任何原始错误信息等,如下所示:
streamStatus
hasBytesAvailable
streamError
streamStatus返回的状态是一个 NSStreamStatus常量,指示流是opening、reading,还是到了流的末尾,等等。
streamError返回的错误信息是一个NSError对象,封装了错误发生的位置。
最重要的是,一旦流打开了,他就开始持续发送 stream:handleEvent:消息给其代理,直到其遇到流的末尾。这些消息包括一个参数,是一个 NSStreamEvent常量,用来指示事件类型。对于NSInputStream来说,最常见的事件类型是 NSStreamEventOpenCompleted, NSStreamEventHasBytesAvailable,和 NSStreamEventEndEncountered。代理一般最感兴趣 NSStreamEventHasBytesAvailable。下面是一个例子:
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
3)销毁流对象:
- (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 ...
}
}
二,向输入流写入:
1)创建并初始化一个NSOutputStream,并设置一个代理
2)安排流对象到一个run loop并打开。
3)处理事件
4)如果流对象已经将数据写入内存,通过键NSStreamDataWritenToMemoryStreamKey来获得数据。
5)当没有更多的数据需要写时,销毁流对象。
1)准备流对象:必须给输入流指定一个目标,刻意是一个文件,一个C buffer,应用程序内存,或一个网络socket
创建并初始化输出流到内存的例子:
- (void)createOutputStream {
NSLog(@"Creating and opening NSOutputStream...");
// oStream is an instance variable
oStream = [[NSOutputStream alloc] initToMemory];
[oStream setDelegate:self];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[oStream open];
}
2)在流open之后,你可以获取
streamStatus
hasSpaceAvailable
streamError
状态为一个NSStreamStatus枚举,指示流是opening,writing,流的末尾 等等
代理同样是stream:handleEvent: event也是NSStreamEvent枚举,一半是NSStreamEventOpenCompleted.NSStreamEventHasSpaceAvailable,和NSStreamEventEndEncountered。
Listing 2 Handling a space-available event
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode) {
case NSStreamEventHasSpaceAvailable:
{
uint8_t *readBytes = (uint8_t *)[_data mutableBytes];
readBytes += byteIndex; // instance variable to move pointer
int data_len = [_data length];
unsigned int len = ((data_len - byteIndex >= 1024) ?
1024 : (data_len-byteIndex));
uint8_t buf[len];
(void)memcpy(buf, readBytes, len);
len = [stream write:(const uint8_t *)buf maxLength:len];
byteIndex += len;
break;
}
// continued ...
}
}
3)销毁流对象;
Listing 3 Closing and releasing the NSInputStream object
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch(eventCode) {
case NSStreamEventEndEncountered:
{
NSData *newData = [oStream propertyForKey:
NSStreamDataWrittenToMemoryStreamKey];
if (!newData) {
NSLog(@"No data written to memory!");
} else {
[self processData:newData];
}
[stream close];
[stream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[stream release];
oStream = nil; // oStream is instance variable
break;
}
// continued ...
}
}
通过给NSOutputStream对象发送一个propertyForKey:消息,指定键为NSStreamDataWrittenToMemoryStreamKey,可以获得其写入内存的数据,返回一个NSData对象。
三、Polling Versus Run-Loop Scheduling
四、处理流错误
五、Setting up Socket Streams:
http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/Streams/Articles/PollingVersusRunloop.html#//apple_ref/doc/uid/20002275-CJBEDDBG