UITableViewController: анализ данных, но `numberOfRowsInSection:` возвращает NULL. - PullRequest
2 голосов
/ 01 июля 2011

У меня есть UITableView, заполненный данными, проанализированными из xml. Разбор работает, но таблица остается пустой.

Консоль показывает, что xml-форма URL-адреса анализируется, и показывает ее компоненты. Он также показывает количество объектов, которое должно быть в строках таблицы при запросе в другой функции, но numberOfRowsInSection: возвращает Null. Поэтому tableView в симуляторе остается пустым.

Вот мой код. Это простой код из учебника:

+++++++++++++++++ RootViewController.h ++++++++++++++++++++++

#import < UIKit/UIKit.h >

@interface RootViewController : UITableViewController < NSXMLParserDelegate >{

    IBOutlet UITableView *newsTable;
    UIActivityIndicatorView *activityIndicator;
    CGSize cellSize;
    NSXMLParser *rssParser;
    NSMutableArray *stories;
    NSMutableDictionary *item;
    NSString *currentElement;
    NSMutableString *currentTitle, *currentDate, *currentSummary, *currentLink; 
}

@property (nonatomic, retain) NSMutableArray *stories;

@property (nonatomic, retain) IBOutlet UITableView *newsTable;

-(void)parseXMLFileAtURL:(NSString *)URL;

@end


+++++++++++++++++++++++++++ RootViewController.m ++++++++++++++++++++++++++++++++++++++

#import "RootViewController.h"


@implementation RootViewController
@synthesize newsTable, stories;


-(void)viewDidLoad {

    [super viewDidLoad];

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.

    // self.navigationItem.rightBarButtonItem = self.editButtonItem;
}


-(void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    [newsTable reloadData];
}


-(void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    if([stories count] == 0){
        NSString *path = @"http://feeds.feedburner.com/TheAppleBlog";

        [self parseXMLFileAtURL:path];      
    }

    cellSize = CGSizeMake([newsTable bounds].size.width, 60);

}

// Customize the number of sections in the table view.

-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 1;
}


-(void)parseXMLFileAtURL:(NSString *)URL {

    stories = [[NSMutableArray alloc] init];

    NSURL *xmlURL = [NSURL URLWithString:URL];

    rssParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];

    [rssParser setDelegate:self];

    [rssParser setShouldProcessNamespaces:NO];

    [rssParser setShouldReportNamespacePrefixes:NO];

        [rssParser setShouldResolveExternalEntities:NO];

    [rssParser parse];
}

-(void)parserDidStartDocument:(NSXMLParser *)parser{

    NSLog(@"Found file and started parsing");
}

-(void) parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{

    NSString *errorString = [NSString stringWithFormat:@"Unable to download story feed from the website (error code %i)", [parseError code]];

    NSLog(@"error parsing XML: %@", errorString);

    UIAlertView *errorAlert = [[UIAlertView alloc]:@"Error loading content" message:errorString delegate:self cancelButtonTitle:@"OK" otherButtonTitle:nil];

    [errorAlert show];
}

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

    NSLog(@"Found this Element %@", elementName);
    currentElement = [elementName copy];


    if ([elementName isEqualToString:@"item"]) {

        item = [[NSMutableDictionary alloc] init];

        currentTitle = [[NSMutableString alloc] init];
        currentDate = [[NSMutableString alloc] init];
        currentSummary = [[NSMutableString alloc] init];
        currentLink = [[NSMutableString alloc] init];               
    }
}

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

    NSLog(@"End this Element %@", elementName);

    if ([elementName isEqualToString:@"item"]) {

        [item setObject:currentTitle forKey:@"title"];
        [item setObject:currentLink forKey:@"link"];
        [item setObject:currentSummary forKey:@"summary"];
        [item setObject:currentDate forKey:@"date"];

        [stories addObject:[item copy]];
        NSLog(@"adding Story : %@",currentTitle);
    }

}

// Customize the number of rows in the table view.

-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    NSLog(@"Count  is = %@", [stories count]);

    return [stories count];
}


-(void)parser:(NSXMLParser *)parser  foundCharacters:(NSString *)string{

    NSLog(@"Found characters: %@", string);

    if([currentElement isEqualToString:@"title"]){

        [currentTitle appendString:string];
        NSLog(@"The Title is : %@", currentTitle);
    }   
    else if([currentElement isEqualToString:@"link"]){
        [currentLink appendString:string];
        NSLog(@"The Link is : %@", currentLink);
    }
    else if([currentElement isEqualToString:@"description"]){
        [currentSummary appendString:string];
        NSLog(@"The summary is : %@", currentSummary);
    }
    else if([currentElement isEqualToString:@"pubDate"]){
        [currentDate appendString:string];
        NSLog(@"The Date is : %@", currentDate);
    }

}

-(void)parserDidEndDocument:(NSXMLParser *)parser{

    [activityIndicator stopAnimating];

    [activityIndicator removeFromSuperview];

    NSLog(@"Stories array has %d items", [stories count]);

    NSLog(@"Stories are : %@",stories);
}


// Customize the appearance of table view cells.

-(UITableViewCell *)tableView:(UITableView *)tableView  cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *MyIdentifier = @"MyIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];

    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
    }

    // Configure the cell.

    cell.textLabel.text = (NSString *)[[stories objectAtIndex:indexPath.row] objectForKey:@"title"];

    return cell;
}

-(void)dealloc {

     [super dealloc];

    [newsTable release];
    [currentDate release];
    [currentElement release];
    [currentSummary release];
    [currentLink release];
    [stories release];
    [item release];
    [currentTitle release];
    [rssParser release];
}

Ответы [ 3 ]

2 голосов
/ 01 июля 2011

Вы должны сообщить табличному представлению, что есть новые данные, вызвав reloadData после того, как вы проанализировали XML.

0 голосов
/ 02 июля 2011

Чтобы развернуть правильный ответ @ omz:

Метод numberOfRowsInSection возвращает не NULL, а ноль. (В Objective-C nil == ноль, а Null - одноэлементный объект.)

Единственная причина, по которой он возвращает ноль, - это если [stories count] возвращает ноль, а единственная причина, по которой [stories count] возвращает ноль, - это если у него нет элементов. Поскольку вы подтвердили, что синтаксический анализ работает, а stories имеет элементы, то табличное представление должно искать данные, прежде чем произойдет анализ.

Этот метод вызывается первым, и это единственное место, где вы перезагружаете данные:

-(void)viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];

    [newsTable reloadData]; 
    // You trigger the tableview to call numberOfRowsInSection before stories is populated.
}

Этот метод вызывается только после того, как табличное представление появилось на экране, и только после того, как табличное представление появляется, вы заполняете stories.

-(void)viewDidAppear:(BOOL)animated {

    [super viewDidAppear:animated];

    if([stories count] == 0){
        NSString *path = @"http://feeds.feedburner.com/TheAppleBlog";

        [self parseXMLFileAtURL:path];      
    }

    cellSize = CGSizeMake([newsTable bounds].size.width, 60);

}

Тем не менее, ничто не заставляет табличное представление снова вызывать numberOfRowsInSection, поэтому табличное представление остается пустым. Простое перемещение заполненных историй в viewWillAppear: решит проблему.

Каждый раз, когда вы изменяете данные, от которых зависит представление таблицы (независимо от причины), вы должны вызывать reloadData, иначе представление таблицы не будет знать, что оно больше не отображает текущий набор данных.

В качестве отступления, вы должны использовать точечную нотацию при обращении к свойствам, чтобы убедиться, что они правильно сохранены. Вы должны использовать self.stories для ссылки на свойство stories. В противном случае он может быть выпущен случайным образом, что приведет к такой же случайной аварии.

0 голосов
/ 01 июля 2011

Правильно ли подключен выход newsTable к представлению таблицы в IB? И установлена ​​ли в dataSource розетка стола ваш контроллер вида?

...