译自:Writing To Output Streams
使用NSOutputStream实例需要以下几个步骤:
1,使用存储写入数据的存储库创建和初始化一个NSOutputSteam实例,并且设置它的delegate。
2,将这个流对象布置在一个runloop上并且open the stream。
3,处理流对象向其delegate发送的事件消息。
4,如果流对象向内存中写入了数据,那么可以通过使用NSStreamDataWrittenToMemoryStreamKey属性获取数据。
5,当没有数据可供写入时,清理流对象。
一,使用流对象的准备工作
使用NSOutputStream对象之前你必须指定数据写入的流的目标位置,输出流对象的目标位置可以是file,C buffer, application memory,network socket。
NSOutputStream的初始化方法和工厂方法可以使用a file,a buffer, memory来创建和初始化实例,下面的代码初始化了一个NSOutputStream实例,用来向 application memory 写入数据。
- (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];
}
当你在open the stream对象之前,向流对象发送scheduleInRunLoop:forMode:消息使其在一个runloop上可以接收到stream events,这样,当流对象不能接收更多数据的时候,可以使delegate避免阻塞。当streaming发生在另外一个线程时,你必须将流对象布置在那个线程的run loop上,You should never attempt to access a scheduled stream from a thread different than the one owning the stream’s run loop. 最后 open the stream 开始数据向 NSOutputStream对象传送。
二,处理 Stream Events
当你向流对象发送open消息之后,你可以通过以下消息获取到流对象的状态,比如说当前是否有空间可供数据写入以及其他错误信息的属性。
streamStatus
hasSpaceAvailable
streamError
返回的状态是NSStreamStatus常量,它指示流当前的状态是opening,writing,at the end of the stream等等,返回的错误是NSError对象,它封装的是所有错误的信息。
重要的是,一旦open the stream,只要delegate持续想流对象写入数据,流对象就是一直向其delegate发送stream:handleEvent:消息,直到到达了流的末尾。这些消息中包含一个NSStreamEvent常量参数来指示事件的类型。对于一个NSOutputStream对象,最常见的事件类型是NSStreamEventOpenCompleted,NSStreamEventHasSpaceAvailable,NSStreamEventEndEncountered,delegate通常对NSStreamEventHasSpaceAvaliable事件最感兴趣。下面的代码就是处理NSStreamEventHasSpaceAvaliable事件的一种方法:
- (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 ...
}
}
在stream:handleEvent:的实现中使用switch语句来判别NSStreamEvent常量,当这个常量是NSStreamEventHasSpacesAvailable的时候,delegate从NSMutableData对象_data中获取数据,并且将其指针转化为适合当前操作的类型u_int8.下一步计算即将进行写操作的字节数(是1024还是所有剩余的字节数),声明一段相应大小的buffer,向该buffer写入相应大小的数据,然后delegate调用流对象write:maxLength:方法将buffer中的数据置入output stream中,最后更新byteIndex用于下一次的读取操作。
如果delegate收到NSStreamEventHasSpacesAvailable事件消息但是没有向stream里写入任何数据,它不会从runloop再接收到space-available的事件消息直到NSOutputStream对象接收到数据,这样由于space-available事件该run loop会重新启动。如果这种情况很有可能在你的程序设计中出现,在收到NSStreamEventHasSpaceAvailable消息并且没有向该stream中写入数据时可以在delegate中设置一个标志位flag,之后,当存在更多的数据需要写入时,先检查该标志位,如果该标志位被设置,那么直接向output-stream实例写入数据。
对于一次向output-stream实例中写入多少数据没有严格的限定,一般情况下使用一些合理值,如512Bytes,1kB,4kB(一个页面大小)。
当在向stream中写数据时NSOutputStream对象发生错误,它会停止streaming并且使用NSStreamEventErrorOccurred消息通知其delegate。
三,清理 Stream Object
当一个NSOutputStream对象结束向一个output stream写入数据,它通过stream:handleEvent:消息向delegate发送NSStreamEventEndEncountered事件消息,这个时候delegate应该清理 stream object,先关闭该stream object,从run loop中移除,释放该stream object。此外,如果NSOutputStream对象的目的存储库是application memory(也就是,你通过initToMemory方法或者其工厂方法outputStreamToMemory创建的该对象),现在就可以从内存中获取数据了。下面的代码实现的清理 stream 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 ...
}
}
转自:http://blog.csdn.net/caryaliu/article/details/7658536