Основният проблем, върху който работя, е използването на класовете NSStream
за анализиране на входящи инкрементални XML данни. Данните никога не са пълен XML документ, но искам да ги получавам и обработвам на постепенни парчета въз основа на това колко може да прочете сокетът.
Разглеждайки документацията за NSXMLParser
, изглежда, че методът initWithStream:
за инициализиране на NSXMLParser
би бил идеалното решение на моя проблем. Мога да инициализирам анализатора с NSInputStream
и след това да извикам метода parse
на NSXMLParser
всеки път, когато получа данни през моя сокет, което на свой ред трябва да извика NSXMLParser
делегатите.
Въпреки това не виждам нито един от делегатите да се извиква, единственият метод, който виждам да се извиква, е делегатът на потока stream:handleEvent:
. Изглежда, че има малко или никакви примери за този API от Apple или други разработчици. Някакви идеи какво правя грешно или как да използвам initWithStream:
правилно?
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
Невиртуалните методи се обвързват по време на компилиране, а не по време на изпълнение. По време на компилиране всичко, което може да се гарантира, е, че
T
еBase
, така че компилаторът обвързва инструмента за достъп на свойството къмBase
версията наCorrectName
и това няма да се промени по време на изпълнение. Вие извиквате метода сDerived
като параметър на типаT
, но други биха могли да го извикат с друг тип, наследен отBase
или дори от самияBase
.Виртуалните методи обаче ще проверят действителния тип време на изпълнение и ще извикат правилния заменен метод.
„Таблицата на истината“, която публикувахте, е неуместна тук, тъй като всички те се оценяват по време на изпълнение. За да докажете, че компилаторът оценява
- person   schedule 28.05.2012T
така, сякаш еBase
, опитайте следното:NSInputStream
. Има алтернативни решения, като директно използване наlibxml2
, но се надявах, че просто използвамNSXMLParser
неправилно. - person John Drake   schedule 28.05.2012-parse
, можете просто да разчитате на потока, за да прехвърлите данните в анализатора. Но ако получавате данни в-stream:handleEvent:
, тогава тези данни не отиват към анализатора надолу по веригата (NSXMLParser
), тъй като получавате потока, а неNSXMLParser
. Може да искате да разгледате cocoabuilder. com/archive/cocoa/ - person gaige   schedule 28.05.2012ContentParser
делегат наNSInputStream
, както и да премахна повикването-[NSXMLParser parse]
. Дори след тези промени делегатитеNSXMLParser
не се извикват. - person John Drake   schedule 28.05.2012