Joh*_*ake 4 cocoa objective-c nsxmlparser nsinputstream nsstream
我正在处理的基本问题是使用NSStream类来解析传入的增量XML数据.数据永远不是一个完整的XML文档,但我希望根据套接字可以读取的内容以增量块的形式接收和处理它.
看一下文档NSXMLParser,似乎initWithStream:初始化a 的方法NSXMLParser将是我问题的完美解决方案.我可以使用a初始化解析器,NSInputStream然后在我通过套接字接收数据时调用该parse方法,然后NSXMLParser应该调用NSXMLParser委托.
但是,我没有看到任何被调用的委托,我看到被调用的唯一方法是流委托stream:handleEvent:.Apple或其他开发人员似乎很少或没有此API的示例.关于我做错了什么或如何initWithStream:正确使用的任何想法?
ContentParser.h
@interface ContentParser : NSObject <NSStreamDelegate,
NSXMLParserDelegate>
{
NSInputStream *inputStream;
NSOutputStream *outputStream;
NSMutableData *receivedData;
NSXMLParser *xmlParser;
}
- (void)initStream;
Run Code Online (Sandbox Code Playgroud)
ContentParser.m
@implementation ContentParser
- (void)initStream
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef)@"<hostname>",
<port>,
&readStream,
&writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
inputStream.delegate = self;
outputStream.delegate = self;
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
xmlParser = [[NSXMLParser alloc] initWithStream:inputStream];
[xmlParser setDelegate:self];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
NSLog(@"didStartElement: %@, attributeDict: %@", elementName, attributeDict);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
NSLog(@"foundCharacters: %@", string);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
NSLog(@"didEndElement: %@", elementName);
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(@"Error %ld, Description: %@, Line: %ld, Column: %ld",
[parseError code], [[parser parserError] localizedDescription],
[parser lineNumber], [parser columnNumber]);
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventHasBytesAvailable:
{
if (stream == inputStream) {
NSInputStream *is = (NSInputStream *)stream;
if (receivedData == nil) {
receivedData = [[NSMutableData alloc] init];
}
uint8_t buf[1024];
NSInteger bytesRead = [is read:buf maxLength:1024];
if (bytesRead == -1) {
NSLog(@"Network read error");
} else if (bytesRead == 0) {
NSLog(@"No buffer received");
} else {
[receivedData appendBytes:buf length:bytesRead];
BOOL parserResult = [xmlParser parse];
if (parserResult == NO) {
NSLog(@"Unable to parse XML");
}
}
}
break;
}
default:
break;
}
}
@end
Run Code Online (Sandbox Code Playgroud)
我弄清楚问题是什么,并在这里回答它,因为将来+[NSXMLParser initWithStream]有其他人遇到这个问题,因为那里没有很多文档.
我需要-[NSXMLParser parse]在分配NSXMLParser并将自己设置为委托后立即致电.但因为它是一个同步函数,我需要将它称为另一个线程,所以我不阻止当前线程,它可以接收NSStream事件.我也不需要让自己成为代表NSInputStream.
这可以很简单地使用Grand Central Dispatch(GCD)完成,如下所示:
// alloc and init the xml parser
xmlParser = [[NSXMLParser alloc] initWithStream:inputStream];
[xmlParser setDelegate:self];
// block to execute
dispatch_block_t dispatch_block = ^(void)
{
[xmlParser parse];
};
// create a queue with a unique name
dispatch_queue_t dispatch_queue = dispatch_queue_create("parser.queue", NULL);
// dispatch queue
dispatch_async(dispatch_queue, dispatch_block);
// cleanup
dispatch_release(dispatch_queue);
Run Code Online (Sandbox Code Playgroud)
这是完整的工作示例,只是因为任何人都无法按照我上面发布的内容.
ContentParser.h
@interface ContentParser : NSObject <NSStreamDelegate,
NSXMLParserDelegate>
{
NSInputStream *inputStream;
NSOutputStream *outputStream;
NSMutableData *receivedData;
NSXMLParser *xmlParser;
}
- (void)initStream;
Run Code Online (Sandbox Code Playgroud)
ContentParser.m
@implementation ContentParser
- (void)initStream
{
CFReadStreamRef readStream;
CFWriteStreamRef writeStream;
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
(CFStringRef)@"<hostname>",
<port>,
&readStream,
&writeStream);
inputStream = (__bridge NSInputStream *)readStream;
outputStream = (__bridge NSOutputStream *)writeStream;
outputStream.delegate = self;
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];
xmlParser = [[NSXMLParser alloc] initWithStream:inputStream];
[xmlParser setDelegate:self];
dispatch_block_t dispatch_block = ^(void)
{
[xmlParser parse];
};
dispatch_queue_t dispatch_queue = dispatch_queue_create("parser.queue", NULL);
dispatch_async(dispatch_queue, dispatch_block);
dispatch_release(dispatch_queue);
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
attributes:(NSDictionary *)attributeDict
{
dispatch_block_t dispatch_block = ^(void)
{
NSLog(@"didStartElement: %@, attributeDict: %@",
elementName, attributeDict);
};
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, dispatch_block);
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
dispatch_block_t dispatch_block = ^(void)
{
NSLog(@"foundCharacters: %@", string);
};
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, dispatch_block);
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName
namespaceURI:(NSString *)namespaceURI
qualifiedName:(NSString *)qName
{
dispatch_block_t dispatch_block = ^(void)
{
NSLog(@"didEndElement: %@", elementName);
};
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, dispatch_block);
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
dispatch_block_t dispatch_block = ^(void)
{
NSLog(@"Error %ld, Description: %@, Line: %ld, Column: %ld",
[parseError code], [[parser parserError] localizedDescription],
[parser lineNumber], [parser columnNumber]);
};
dispatch_queue_t main_queue = dispatch_get_main_queue();
dispatch_async(main_queue, dispatch_block);
}
- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventHasSpaceAvailable:
{
/* write bytes to socket */
break;
}
default:
break;
}
}
@end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2493 次 |
| 最近记录: |