【问题标题】:How can I wait until NSXMLParserDelegate methods finished?我怎样才能等到 NSXMLParserDelegate 方法完成?
【发布时间】:2014-09-25 23:55:36
【问题描述】:

我想用解析的 xml 结果创建对象,但它总是返回 null。我认为它在 nsxmlparser 委托未完成之前完成。

这是我的代码。

@interface ParserOperation () <NSXMLParserDelegate, NSURLConnectionDelegate> {
    NSString *soapResults;
    NSXMLParser *xmlParser;
    NSMutableData *responseData;
}

- (void)main {

    NSError *error;
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self];
    if (connection)
        responseData = [NSMutableData data];
    else
        NSLog(@"NSURLConnection initWithRequest: Failed to return a connection.");

    if ([self isCancelled]) {
        return;
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        if (error) {
            self.callbackBlock(NO, error);
            NSLog(@"error %@", error);
        } else {
            self.callbackBlock(YES, self.results);
            NSLog(@"else %@", soapResults);
        }
    });
}

当 NSURLConnection 委托方法完成时,XML 解析器开始。

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    NSLog(@"Completed, Received Bytes:%lu",(unsigned long)[responseData length]);

    xmlParser = [[NSXMLParser alloc] initWithData: responseData];
    xmlParser.delegate = self;
    [xmlParser setShouldResolveExternalEntities:YES];
    [xmlParser parse];
}

- (void)parser:(NSXMLParser *) parser didStartElement:(NSString *) elementName namespaceURI:(NSString *) namespaceURI qualifiedName:(NSString *) qName attributes:(NSDictionary *)attributeDict {

    soapResults = [[NSString alloc] init];
}

- (void)parser:(NSXMLParser *) parser foundCharacters:(NSString *)string {
    soapResults = [soapResults stringByAppendingString:string];
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {

    if ([elementName isEqualToString:self.resultName]) {
        if ([soapResults isEqualToString:@""]) {
            NSLog(@"error");
        }
        else {
            NSData *jsonData = [soapResults dataUsingEncoding:NSUTF8StringEncoding];
            NSError *e;
            self.results = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&e];
            NSLog(@"Parsed Object: %@", self.results);
            NSLog(@"soap: %@", soapResults);
        }
    }
}

【问题讨论】:

  • 代码看起来没问题。会发生什么?
  • soapreselts 和 self.results 为零。
  • 我没有看到这些变量/属性。你看到问题了吗?你没有发布足够的代码。
  • 我添加了属性和 xmlparser 委托方法。

标签: ios nsurlconnection nsxmlparser


【解决方案1】:

有两个问题:

  1. Wain 是绝对正确的,这是异步网络请求,因此您需要将其设为并发操作 (+1),如果还没有的话。确保 (a) isConcurrent 返回 YES; (b) 实现您自己的 isExecutingisFinished 方法(或定义将为您合成这些 getter 的 BOOL 属性); (c) 确保在更改值时手动发布 isFinishedisExecuting 的 KVN。所有这些都在并发编程指南Operation Queue 章节中进行了讨论。请参阅标题为“为并发执行配置操作”的部分。

    顺便说一句,正如 Wain 所指出的,因为这是一个异步网络请求,所以您要确保在解析 connectDidFinishLoading 之后发起回调。

  2. 如果不将此请求安排在运行循环上,您也不能在操作上使用基于委托的NSURLConnection(假设此操作正在操作队列上运行)。最简单的解决方案是在主运行循环上安排连接:

    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
    [connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
    [connection start];
    

    您还可以为NSURLConnection 创建自己的专用线程(就像 AFNetworking 一样)并安排您的操作,但这会增加一些复杂性。

我看到人们采用的另一种方法(它解决了并发操作问题和运行循环问题)是将其保留为非并发操作,但让main 不仅安排操作,还可以创建自己的运行循环。我不喜欢这种技术,但它也很有效。

【讨论】:

    【解决方案2】:

    解析器是同步的,但下载不是。完成块的调用方法与开始下载的方法相同,因此它将始终在下载完成之前运行。

    只有在出现错误时才应该在该方法中调用完成块。应在 [xmlParser parse]; 之后为成功案例调用完成块,因为那是处理数据的时间。

    【讨论】:

      猜你喜欢
      • 2011-12-14
      • 2016-05-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多