У меня 2 класса: NSObject
класс DataParser
и ViewController
. В классе DataParser
у меня есть несколько методов, которые анализируют XML, и результаты сохраняются в массиве, который является свойством класса DataParser
. Я хочу показать результаты пользователю в моем ViewController
. У меня есть это свойство @property (strong, nonatomic) DataParser *parser;
, а в методе viewWillAppear
я создал экземпляр класса DataParser
, и я пытаюсь получить массив с результатами таким образом
self.parser = [[DataParser alloc] init];
[self.parser downloadBooksXML];
NSLog(@"%@", self.parser.array);
Но я все еще получаю ноль. Кто-нибудь знает, в чем может быть проблема?
- (void)downloadBooksXML
{
NSURL *url = [NSURL URLWithString:@"http://..."];
[self downloadDataFromURL:url withCompletionHandler:^(NSData *data) {
if (data) {
self.xmlParser = [[NSXMLParser alloc] initWithData:data];
self.xmlParser.delegate = self;
self.foundValue = [[NSMutableString alloc] init];
[self.xmlParser parse];
} else {
NSLog(@"Error");
}
}];
}
РЕДАКТИРОВАТЬ: Когда я использую массив nslog в классе DataParser
в методе parserDidEndDocument
, он содержит данные
3 ответа
Когда [self.parser downloadBooksXML]
возвращается, self.parser.array
еще не установлен, потому что данные не были загружены и проанализированы.
Данные будут доступны после завершения синтаксического анализа документа, который вы можете проверить с помощью метода делегата:
- (void)parserDidEndDocument:(NSXMLParser *)parser {
NSLog(@"%@", self.parser.array);
}
Поэтому вы можете использовать такой шаблон:
- (void) viewDidLoad {
[super viewDidLoad];
self.parser = [[DataParser alloc] init];
[self.parser downloadBooksXML];
}
- (void) dataFinished {
NSLog(@"%@", self.parser.array);
// update the user interface
}
- (void)parserDidEndDocument:(NSXMLParser *)parser {
[self dataFinished];
}
В зависимости от реализации вашего другого кода вам может потребоваться переключиться в основную очередь для обновления пользовательского интерфейса:
- (void) dataFinished {
NSLog(@"%@", self.parser.array);
dispatch_async(dispatch_get_main_queue(), ^(void){
// update the user interface
});
}
NSXMLParser - это синтаксический анализатор XML (синтаксический анализатор типа SAX). Он начинает читать ваш XML с самого начала и каждый раз, когда находит новый элемент, закрывающий элемент или символьные данные, сообщает вам об этом. При синтаксическом анализе вашего примера XML он будет называть его делегатами:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
if (elementName == @"YourElement") {
// save the elements of attributeDict in your array! This is the place where you add the object to your property self.parser.array!
}
}
PS: Если голосующий (-1) может сказать мне, что было не так в моем ответе?
Учитывая, что вы, вероятно, устанавливаете свойство массива DataParser где-нибудь в своем XML-анализаторе и что downloadBooksXML выполняет загрузку и синтаксический анализ асинхронно, вы обнаружите нулевое значение сразу после возврата вызова к downloadBooksXML
.
Шаблон делегирования, предложенный @Aaron, работает. Вы также можете подумать о добавлении собственного обработчика завершения в свой метод downloadBooksXML
, примерно так:
typedef void (^DownloadBooksCompletionHandler)();
- (void)downloadBooksXMLWithCompletionHandler:(DownloadBooksCompletionHandler)completionHandler
{
NSURL *url = [NSURL URLWithString:@"http://..."];
[self downloadDataFromURL:url withCompletionHandler:^(NSData *data) {
if (data) {
self.xmlParser = [[NSXMLParser alloc] initWithData:data];
self.xmlParser.delegate = self;
self.foundValue = [[NSMutableString alloc] init];
[self.xmlParser parse];
} else {
NSLog(@"Error");
}
completionHandler(); // <-- call the completionHandler!
}];
}
Тогда вы можете «уведомить» вызывающего абонента о завершении загрузки, вызвав completionHandler()
, получить доступ к массиву и обновить свой пользовательский интерфейс.
[self.parser downloadBooksXMLWithCompletionHandler:^()
{
// now OK to access array property and update your UI
}];
Вы также можете рассмотреть возможность передачи NSError * обработчику завершения в качестве средства передачи информации об ошибке.
Наконец, остерегайтесь проблем с потоками ... completionHandler()
будет выполняться в потоке, вызываемом вашим обработчиком завершения downloadDataFromURL. В зависимости от вашей реализации это может быть или не быть потоком пользовательского интерфейса.
Похожие вопросы
Новые вопросы
ios
iOS - мобильная операционная система, работающая на Apple iPhone, iPod touch и iPad. Используйте этот тег [ios] для вопросов, связанных с программированием на платформе iOS. Используйте связанные теги [target-c] и [swift] для проблем, характерных для этих языков программирования.