使用NSXMLParser initWithStream:没有接收到解析器委托方法 [英] Using NSXMLParser initWithStream: no parser delegate methods received

查看:138
本文介绍了使用NSXMLParser initWithStream:没有接收到解析器委托方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我工作的基本问题是使用 NSStream 类来解析传入的增量XML数据。数据永远不是一个完整的XML文档,但我想根据插槽可以读取多少来接收和处理它。增加的块数。

The basic problem I'm working on is using the NSStream classes to parse incoming incremental XML data. The data is never a complete XML Document, but I want to receive and process it in incremental chunks based off how much ever the socket can read.

查看文档 NSXMLParser ,它似乎是 initWithStream:方法来初始化 NSXMLParser 将是我的问题的完美解决方案。我可以用 NSInputStream 初始化解析器,然后在上调用 parse 方法NSXMLParser 每当我通过我的套接字接收数据,然后应该调用 NSXMLParser 代理。

Looking at the documentation for NSXMLParser, it seems like the initWithStream: method to initialize a NSXMLParser would be the perfect solution to my problem. I can initialize the parser with a NSInputStream and then call the parse method on NSXMLParser whenever I receive data over my socket which should in turn call the NSXMLParser delegates.

,我没有看到任何代理被调用,唯一的方法,我看到被调用是流委托 stream:handleEvent:。从苹果或其他开发人员看来,这个API似乎没有什么例子。任何想法,我做错了或如何使用 initWithStream:正确?

However, I'm not seeing any of the delegates being called, the only method I see being called is the stream delegate stream:handleEvent:. There seems to be little to no examples of this API from Apple or other developers. Any ideas on what I'm doing wrong or how to use initWithStream: correctly?

ContentParser.h

@interface ContentParser : NSObject <NSStreamDelegate, 
                                     NSXMLParserDelegate>
{
   NSInputStream *inputStream;
   NSOutputStream *outputStream;
   NSMutableData *receivedData;
   NSXMLParser *xmlParser;
}
- (void)initStream;

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


推荐答案

我想出了问题是什么,并回答这里的任何人遇到这个问题在未来,因为 + [NSXMLParser initWithStream]

I figured out what the problem was and answering it here incase anyone else runs into this problem in the future since +[NSXMLParser initWithStream] doesn't have a lot lot of documentation out there.

我需要调用 - [NSXMLParser parse] 我分配 NSXMLParser 并将自己设置为委托。但是因为它是一个同步函数,我需要调用它另一个线程,所以我不阻塞当前线程,它可以接收 NSStream 事件。我也不需要让自己成为 NSInputStream 的委托。

I needed to call -[NSXMLParser parse] right after I allocate NSXMLParser and set myself as delegate. But because it's a synchronous function, I need to call it another thread so I don't block the current thread and it can receive the NSStream events. I also don't need to make myself the delegate for NSInputStream.

这可以很简单地使用Grand中央调度(GCD)如下:

This can be done pretty simply using Grand Central Dispatch (GCD) like so:

// 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);

这里是完整的工作示例,只是因为任何人都无法跟上我发布的。

And here is the complete working example, just incase anyone wasn't able to follow what I posted above.

ContentParser.h

@interface ContentParser : NSObject <NSStreamDelegate, 
                                     NSXMLParserDelegate>
{
   NSInputStream *inputStream;
   NSOutputStream *outputStream;
   NSMutableData *receivedData;
   NSXMLParser *xmlParser;
}
- (void)initStream;

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

这篇关于使用NSXMLParser initWithStream:没有接收到解析器委托方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆