2010-04-06 4 views
2

У меня есть UITableView, который настроен в Interface Builder и правильно подключен к его классу в Xcode. У меня также есть класс «Импортер», который загружает и анализирует канал RSS и сохраняет информацию в NSMutableArray.UITableView не отображает проанализированные данные

Однако я проверил, что синтаксический анализ работает правильно (используя точки останова и NSlog), но данные не отображаются в UITable View. Какие-нибудь идеи относительно проблемы? Я почти из них.

Он основан на примере производительности XML Apple.

Update 2: ИТАК после работы через информацию ниже, вот что я знаю:

  • В didParseIncidents: (NSArray *) parsedIncidents не вызывается, но читайте дальше, как, почему.
  • Когда я запустить приложение и загрузите данные (аннулируются) parsedIncident: (Incident *) инцидент бежит, но пропускает точки останова, если (self.delegate = ноль & & [self.delegate respondsToSelector: @selector (парсер: didParseIncidents :)]) { [self.delegate parser: self didParseIncidents: parsedIncidents];
  • Я подозреваю, мои проблемы табличные исходят из того, что приведенный выше код не работает должным образом - в образце с точки останова, если (self.delegate = ноль & & [self.delegate respondsToSelector: @selector (парсер: didParseIncidents :)]) { [self.delegate parser: self didParseIncidents: parsedIncidents]; прогонов
  • Ведение П.О. parsedIncidents здесь приводит к ошибке «Не удается получить доступ к 0x0 памяти», в то время как в образце приложение дает NS массив
  • На самом деле, кажется, что рассчитывать parsedIncidents 0 - но не могу понять, почему ,

Update: Хорошо так вот результаты:

«ро инцидентов» на контрольной точке parserDidEndParsingData дал мне ответ «не может получить доступ к памяти по адресу 0x0».

ро [сам] Tableview отображает «> Текущего языка: авто; в настоящее время Objective-C»

В контрольной точке под номером строк в секциях, я получил следующее «) (» сообщение.

Элементы IB, которые я проверил, и все были, как вы сказали. Я подозреваю, что массив не загружается из вышеперечисленных ошибок?

Я также добавил код анализа, если это помогает.

Вот код TableView.h:

#import <UIKit/UIKit.h> 
#import "IncidentsImporter.h" 

@class SongDetailsController; 

@interface CurrentIncidentsTableViewController : UITableViewController <IncidentsImporterDelegate>{ 
    NSMutableArray *incidents; 
    SongDetailsController *detailController; 
    UITableView *ctableView; 
    IncidentsImporter *parser; 
} 

@property (nonatomic, retain) NSMutableArray *incidents; 
@property (nonatomic, retain, readonly) SongDetailsController *detailController; 
@property (nonatomic, retain) IncidentsImporter *parser; 
@property (nonatomic, retain) IBOutlet UITableView *ctableView; 

// Called by the ParserChoiceViewController based on the selected parser type. 
- (void)beginParsing; 

@end 

И код .m:

#import "CurrentIncidentsTableViewController.h" 
#import "SongDetailsController.h" 
#import "Incident.h" 

@implementation CurrentIncidentsTableViewController 

@synthesize ctableView, incidents, parser, detailController; 

#pragma mark - 
#pragma mark View lifecycle 


- (void)viewDidLoad { 
    [super viewDidLoad]; 

    self.parser = [[IncidentsImporter alloc] init];  
    parser.delegate = self; 
    [parser start]; 

    UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(beginParsing)]; 
    self.navigationItem.rightBarButtonItem = refreshButton; 
    [refreshButton release]; 

// Uncomment the following line to preserve selection between presentations. 
//self.clearsSelectionOnViewWillAppear = NO; 

// 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 { 
    NSIndexPath *selectedRowIndexPath = [ctableView indexPathForSelectedRow]; 
    if (selectedRowIndexPath != nil) { 
     [ctableView deselectRowAtIndexPath:selectedRowIndexPath animated:NO]; 
    } 
} 

// This method will be called repeatedly - once each time the user choses to parse. 
- (void)beginParsing { 
    NSLog(@"Parsing has begun"); 
    //self.navigationItem.rightBarButtonItem.enabled = NO; 
    // Allocate the array for song storage, or empty the results of previous parses 
    if (incidents == nil) { 
     NSLog(@"Grabbing array"); 
     self.incidents = [NSMutableArray array]; 
    } else { 
     [incidents removeAllObjects]; 
     [ctableView reloadData]; 
    } 
    // Create the parser, set its delegate, and start it. 
    self.parser = [[IncidentsImporter alloc] init];  
    parser.delegate = self; 
    [parser start]; 
} 

/* 
- (void)viewDidAppear:(BOOL)animated { 
[super viewDidAppear:animated]; 
} 
*/ 
/* 
- (void)viewWillDisappear:(BOOL)animated { 
[super viewWillDisappear:animated]; 
} 
*/ 
/* 
- (void)viewDidDisappear:(BOOL)animated { 
[super viewDidDisappear:animated]; 
} 
*/ 


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    // Override to allow orientations other than the default portrait orientation. 
    return YES; 
} 


#pragma mark - 
#pragma mark Table view data source 

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 
    // Return the number of sections. 
    return 1; 
} 


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 
    // Return the number of rows in the section. 
    return [incidents count]; 
} 


// Customize the appearance of table view cells. 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    NSLog(@"Table Cell Sought"); 

    static NSString *kCellIdentifier = @"MyCell"; 
    UITableViewCell *cell = [ctableView dequeueReusableCellWithIdentifier:kCellIdentifier]; 
    if (cell == nil) { 
     cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kCellIdentifier] autorelease]; 
     cell.textLabel.font = [UIFont boldSystemFontOfSize:14.0]; 
     cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
    } 
    cell.textLabel.text = @"Test";//[[incidents objectAtIndex:indexPath.row] title]; 
    return cell; 
} 


/* 
// Override to support conditional editing of the table view. 
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 
// Return NO if you do not want the specified item to be editable. 
return YES; 
} 
*/ 


/* 
// Override to support editing the table view. 
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 

if (editingStyle == UITableViewCellEditingStyleDelete) { 
// Delete the row from the data source 
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES]; 
} 
else if (editingStyle == UITableViewCellEditingStyleInsert) { 
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 
} 
} 
*/ 


/* 
// Override to support rearranging the table view. 
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 
} 
*/ 


/* 
// Override to support conditional rearranging of the table view. 
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 
// Return NO if you do not want the item to be re-orderable. 
return YES; 
} 
*/ 


#pragma mark - 
#pragma mark Table view delegate 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    self.detailController.incident = [incidents objectAtIndex:indexPath.row]; 
    [self.navigationController pushViewController:self.detailController animated:YES]; 
} 


#pragma mark - 
#pragma mark Memory management 

- (void)didReceiveMemoryWarning { 
    // Releases the view if it doesn't have a superview. 
    [super didReceiveMemoryWarning]; 

    // Relinquish ownership any cached data, images, etc that aren't in use. 
} 

- (void)viewDidUnload { 
    // Relinquish ownership of anything that can be recreated in viewDidLoad or on demand. 
    // For example: self.myOutlet = nil; 
} 

- (void)parserDidEndParsingData:(IncidentsImporter *)parser { 
    [ctableView reloadData]; 
    self.navigationItem.rightBarButtonItem.enabled = YES; 
    self.parser = nil; 
} 

- (void)parser:(IncidentsImporter *)parser didParseIncidents:(NSArray *)parsedIncidents { 
    //[incidents addObjectsFromArray: parsedIncidents]; 
    // Three scroll view properties are checked to keep the user interface smooth during parse. When new objects are delivered by the parser, the table view is reloaded to display them. If the table is reloaded while the user is scrolling, this can result in eratic behavior. dragging, tracking, and decelerating can be checked for this purpose. When the parser finishes, reloadData will be called in parserDidEndParsingData:, guaranteeing that all data will ultimately be displayed even if reloadData is not called in this method because of user interaction. 
    if (!ctableView.dragging && !ctableView.tracking && !ctableView.decelerating) { 
     self.title = [NSString stringWithFormat:NSLocalizedString(@"Top %d Songs", @"Top Songs format"), [parsedIncidents count]]; 
     [ctableView reloadData]; 
    } 
} 

- (void)parser:(IncidentsImporter *)parser didFailWithError:(NSError *)error { 
    // handle errors as appropriate to your application... 
} 


- (void)dealloc { 
    [super dealloc]; 
} 


@end 

Вот код для parser.h:

#import <UIKit/UIKit.h> 
#import <libxml/tree.h> 

@class IncidentsImporter, Incident; 

// Protocol for the parser to communicate with its delegate. 
@protocol IncidentsImporterDelegate <NSObject> 

@optional 
// Called by the parser when parsing is finished. 
- (void)parserDidEndParsingData:(IncidentsImporter *)parser; 
// Called by the parser in the case of an error. 
- (void)parser:(IncidentsImporter *)parser didFailWithError:(NSError *)error; 
// Called by the parser when one or more songs have been parsed. This method may be called multiple times. 
- (void)parser:(IncidentsImporter *)parser didParseIncidents:(NSArray *)parsedIncidents; 

@end 

// This approach to parsing uses NSURLConnection to asychronously retrieve the XML data. libxml's SAX parsing supports chunked parsing, with no requirement for the chunks to be discrete blocks of well formed XML. The primary purpose of this class is to start the download, configure the parser with a set of C callback functions, and pass downloaded data to it. In addition, the class maintains a number of state variables for the parsing. 
@interface IncidentsImporter : NSObject { 
    @private 
    id <IncidentsImporterDelegate> delegate; 
    // Reference to the libxml parser context 
    xmlParserCtxtPtr context; 
    NSURLConnection *rssConnection; 
    NSMutableArray *parsedIncidents; 
    // Overall state of the parser, used to exit the run loop. 
    BOOL done; 
    // State variable used to determine whether or not to ignore a given XML element 
    BOOL parsingAIncident; 
    // The following state variables deal with getting character data from XML elements. This is a potentially expensive 
    // operation. The character data in a given element may be delivered over the course of multiple callbacks, so that 
    // data must be appended to a buffer. The optimal way of doing this is to use a C string buffer that grows exponentially. 
    // When all the characters have been delivered, an NSString is constructed and the buffer is reset. 
    BOOL storingCharacters; 
    NSMutableData *characterBuffer; 
    // A reference to the current song the parser is working with. 
    Incident *currentIncident; 
    // The number of parsed songs is tracked so that the autorelease pool for the parsing thread can be periodically 
    // emptied to keep the memory footprint under control. 
    NSUInteger countOfParsedIncidents; 
    NSAutoreleasePool *downloadAndParsePool; 
    NSDateFormatter *parseFormatter; 
} 
@property (nonatomic, assign) id <IncidentsImporterDelegate> delegate; 
@property (nonatomic, retain) NSMutableArray *parsedIncidents; 
@property BOOL storingCharacters; 
@property (nonatomic, retain) NSMutableData *characterBuffer; 
@property BOOL done; 
@property BOOL parsingAIncident; 
@property NSUInteger countOfParsedIncidents; 
@property (nonatomic, retain) Incident *currentIncident; 
@property (nonatomic, retain) NSURLConnection *rssConnection; 
@property (nonatomic, retain) NSDateFormatter *parseFormatter; 
// The autorelease pool property is assign because autorelease pools cannot be retained. 
@property (nonatomic, assign) NSAutoreleasePool *downloadAndParsePool; 

- (void)downloadAndParse:(NSURL *)url; 
- (void)finishedCurrentIncident; 

- (void)start; 

- (void)downloadStarted; 
- (void)downloadEnded; 
- (void)parseEnded; 
- (void)parsedIncident:(Incident *)incident; 
- (void)parseError:(NSError *)error; 
- (void)addToParseDuration:(NSNumber *)duration; 

@end 

И парсер ,м:

#import "IncidentsImporter.h" 
#import "Incident.h" 
#import <libxml/tree.h> 

static NSUInteger kCountForNotification = 10; 

// Function prototypes for SAX callbacks. This sample implements a minimal subset of SAX callbacks. 
// Depending on your application's needs, you might want to implement more callbacks. 
static void startElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes); 
static void endElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI); 
static void charactersFoundSAX(void * ctx, const xmlChar * ch, int len); 
static void errorEncounteredSAX(void * ctx, const char * msg, ...); 

// Forward reference. The structure is defined in full at the end of the file. 
static xmlSAXHandler simpleSAXHandlerStruct; 

@implementation IncidentsImporter 

@synthesize delegate, rssConnection, done, parsingAIncident, parsedIncidents, storingCharacters, currentIncident, countOfParsedIncidents, characterBuffer, parseFormatter, downloadAndParsePool; 

- (void)start { 
    NSLog(@"URL Gained"); 
    [[NSURLCache sharedURLCache] removeAllCachedResponses]; 
    NSURL *url = [NSURL URLWithString:@"http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZStore.woa/wpa/MRSS/newreleases/limit=300/rss.xml"]; 
    [NSThread detachNewThreadSelector:@selector(downloadAndParse:) toTarget:self withObject:url]; 
} 

- (void)downloadStarted { 
    NSLog(@"Download has begun"); 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 
} 

- (void)downloadEnded { 
    NSLog(@"Download has ended"); 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 
} 

- (void)parseEnded { 
    NSLog(@"Parsing has ended"); 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
    if (self.delegate != nil && [self.delegate respondsToSelector:@selector(parser:didParseIncidents:)] && [parsedIncidents count] > 0) { 
     [self.delegate parser:self didParseIncidents:parsedIncidents]; 
    } 
    [self.parsedIncidents removeAllObjects]; 
    if (self.delegate != nil && [self.delegate respondsToSelector:@selector(parserDidEndParsingData:)]) { 
     [self.delegate parserDidEndParsingData:self]; 
    } 
} 

- (void)parsedIncident:(Incident *)incident { 
    NSLog(@"Parsing has begun on thread"); 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
    [self.parsedIncidents addObject:incident]; 
    if (self.parsedIncidents.count > kCountForNotification) { 
     if (self.delegate != nil && [self.delegate respondsToSelector:@selector(parser:didParseIncidents:)]) { 
      [self.delegate parser:self didParseIncidents:parsedIncidents]; 
     } 
     [self.parsedIncidents removeAllObjects]; 
    } 
} 

- (void)parseError:(NSError *)error { 
    NSLog(@"Parsing has an error"); 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
    if (self.delegate != nil && [self.delegate respondsToSelector:@selector(parser:didFailWithError:)]) { 
     [self.delegate parser:self didFailWithError:error]; 
    } 
} 

- (void)addToParseDuration:(NSNumber *)duration { 
    NSAssert2([NSThread isMainThread], @"%s at line %d called on secondary thread", __FUNCTION__, __LINE__); 
} 

/* 
This method is called on a secondary thread by the superclass. We have asynchronous work to do here with downloading and parsing data, so we will need a run loop to prevent the thread from exiting before we are finished. 
*/ 
- (void)downloadAndParse:(NSURL *)url { 
    NSLog(@"Downloading and Parsing"); 
    self.downloadAndParsePool = [[NSAutoreleasePool alloc] init]; 
    done = NO; 
    self.parseFormatter = [[[NSDateFormatter alloc] init] autorelease]; 
    [parseFormatter setDateStyle:NSDateFormatterLongStyle]; 
    [parseFormatter setTimeStyle:NSDateFormatterNoStyle]; 
    // necessary because iTunes RSS feed is not localized, so if the device region has been set to other than US 
    // the date formatter must be set to US locale in order to parse the dates 
    [parseFormatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"AU"] autorelease]]; 
    self.characterBuffer = [NSMutableData data]; 
    [[NSURLCache sharedURLCache] removeAllCachedResponses]; 
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:url]; 
    // create the connection with the request and start loading the data 
    rssConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; 
    // This creates a context for "push" parsing in which chunks of data that are not "well balanced" can be passed 
    // to the context for streaming parsing. The handler structure defined above will be used for all the parsing. 
    // The second argument, self, will be passed as user data to each of the SAX handlers. The last three arguments 
    // are left blank to avoid creating a tree in memory. 
    context = xmlCreatePushParserCtxt(&simpleSAXHandlerStruct, self, NULL, 0, NULL); 
    [self performSelectorOnMainThread:@selector(downloadStarted) withObject:nil waitUntilDone:NO]; 
    if (rssConnection != nil) { 
     do { 
      [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
     } while (!done); 
    } 
    // Release resources used only in this thread. 
    xmlFreeParserCtxt(context); 
    self.characterBuffer = nil; 
    self.parseFormatter = nil; 
    self.rssConnection = nil; 
    self.currentIncident = nil; 
    [downloadAndParsePool release]; 
    self.downloadAndParsePool = nil; 
} 

#pragma mark NSURLConnection Delegate methods 

/* 
Disable caching so that each time we run this app we are starting with a clean slate. You may not want to do this in your application. 
*/ 
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse { 
    return nil; 
} 

// Forward errors to the delegate. 
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 
    done = YES; 
    [self performSelectorOnMainThread:@selector(parseError:) withObject:error waitUntilDone:NO]; 
} 

// Called when a chunk of data has been downloaded. 
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    NSLog(@"Did receive data"); 
    NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; 
    // Process the downloaded chunk of data. 
    xmlParseChunk(context, (const char *)[data bytes], [data length], 0); 
    NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - start; 
    [self performSelectorOnMainThread:@selector(addToParseDuration:) withObject:[NSNumber numberWithDouble:duration] waitUntilDone:NO]; 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection { 
    NSLog(@"Connection done loading"); 
    [self performSelectorOnMainThread:@selector(downloadEnded) withObject:nil waitUntilDone:NO]; 
    NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate]; 
    // Signal the context that parsing is complete by passing "1" as the last parameter. 
    xmlParseChunk(context, NULL, 0, 1); 
    NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - start; 
    [self performSelectorOnMainThread:@selector(addToParseDuration:) withObject:[NSNumber numberWithDouble:duration] waitUntilDone:NO]; 
    [self performSelectorOnMainThread:@selector(parseEnded) withObject:nil waitUntilDone:NO]; 
    // Set the condition which ends the run loop. 
    done = YES; 
} 

#pragma mark Parsing support methods 

static const NSUInteger kAutoreleasePoolPurgeFrequency = 20; 

- (void)finishedCurrentIncident { 
    [self performSelectorOnMainThread:@selector(parsedIncident:) withObject:currentIncident waitUntilDone:NO]; 
    // performSelectorOnMainThread: will retain the object until the selector has been performed 
    // setting the local reference to nil ensures that the local reference will be released 
    self.currentIncident = nil; 
    countOfParsedIncidents++; 
    // Periodically purge the autorelease pool. The frequency of this action may need to be tuned according to the 
    // size of the objects being parsed. The goal is to keep the autorelease pool from growing too large, but 
    // taking this action too frequently would be wasteful and reduce performance. 
    if (countOfParsedIncidents == kAutoreleasePoolPurgeFrequency) { 
     [downloadAndParsePool release]; 
     self.downloadAndParsePool = [[NSAutoreleasePool alloc] init]; 
     countOfParsedIncidents = 0; 
    } 
} 

/* 
Character data is appended to a buffer until the current element ends. 
*/ 
- (void)appendCharacters:(const char *)charactersFound length:(NSInteger)length { 
    [characterBuffer appendBytes:charactersFound length:length]; 
} 

- (NSString *)currentString { 
    // Create a string with the character data using UTF-8 encoding. UTF-8 is the default XML data encoding. 
    NSString *currentString = [[[NSString alloc] initWithData:characterBuffer encoding:NSUTF8StringEncoding] autorelease]; 
    [characterBuffer setLength:0]; 
    return currentString; 
} 

@end 

#pragma mark SAX Parsing Callbacks 

// The following constants are the XML element names and their string lengths for parsing comparison. 
// The lengths include the null terminator, to ensure exact matches. 
static const char *kName_Item = "item"; 
static const NSUInteger kLength_Item = 5; 
static const char *kName_Title = "title"; 
static const NSUInteger kLength_Title = 6; 
static const char *kName_Category = "link"; 
static const NSUInteger kLength_Category = 9; 
static const char *kName_Itms = "itms"; 
static const NSUInteger kLength_Itms = 5; 
static const char *kName_Artist = "description"; 
static const NSUInteger kLength_Artist = 7; 
static const char *kName_Album = "guid"; 
static const NSUInteger kLength_Album = 6; 
static const char *kName_ReleaseDate = "pubDate"; 
static const NSUInteger kLength_ReleaseDate = 12; 

/* 
This callback is invoked when the parser finds the beginning of a node in the XML. For this application, 
out parsing needs are relatively modest - we need only match the node name. An "item" node is a record of 
data about a song. In that case we create a new Song object. The other nodes of interest are several of the 
child nodes of the Song currently being parsed. For those nodes we want to accumulate the character data 
in a buffer. Some of the child nodes use a namespace prefix. 
*/ 
static void startElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI, 
          int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) { 
    IncidentsImporter *parser = (IncidentsImporter *)ctx; 
    // The second parameter to strncmp is the name of the element, which we known from the XML schema of the feed. 
    // The third parameter to strncmp is the number of characters in the element name, plus 1 for the null terminator. 
    if (prefix == NULL && !strncmp((const char *)localname, kName_Item, kLength_Item)) { 
     NSLog(@"Found node"); 
     Incident *newIncident = [[Incident alloc] init]; 
     parser.currentIncident = newIncident; 
     [newIncident release]; 
     parser.parsingAIncident = YES; 
    } else if (parser.parsingAIncident && ((prefix == NULL && (!strncmp((const char *)localname, kName_Title, kLength_Title) || !strncmp((const char *)localname, kName_Category, kLength_Category))) || ((prefix != NULL && !strncmp((const char *)prefix, kName_Itms, kLength_Itms)) && (!strncmp((const char *)localname, kName_Artist, kLength_Artist) || !strncmp((const char *)localname, kName_Album, kLength_Album) || !strncmp((const char *)localname, kName_ReleaseDate, kLength_ReleaseDate))))) { 
     parser.storingCharacters = YES; 
    } 
} 

/* 
This callback is invoked when the parse reaches the end of a node. At that point we finish processing that node, 
if it is of interest to us. For "item" nodes, that means we have completed parsing a Song object. We pass the song 
to a method in the superclass which will eventually deliver it to the delegate. For the other nodes we 
care about, this means we have all the character data. The next step is to create an NSString using the buffer 
contents and store that with the current Song object. 
*/ 
static void endElementSAX(void *ctx, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI) {  
    IncidentsImporter *parser = (IncidentsImporter *)ctx; 
    if (parser.parsingAIncident == NO) return; 
    if (prefix == NULL) { 
     if (!strncmp((const char *)localname, kName_Item, kLength_Item)) { 
      [parser finishedCurrentIncident]; 
      parser.parsingAIncident = NO; 
     } else if (!strncmp((const char *)localname, kName_Title, kLength_Title)) { 
      NSLog(@"Parsing title"); 
      parser.currentIncident.title = [parser currentString]; 
     } else if (!strncmp((const char *)localname, kName_Category, kLength_Category)) { 
      NSLog(@"Parsing url"); 
      parser.currentIncident.link = [NSURL URLWithString: [parser currentString]]; 
     } 
     else if (!strncmp((const char *)localname, kName_Artist, kLength_Artist)) { 
      NSLog(@"Parsing description"); 
      parser.currentIncident.description = [parser currentString]; 
     } else if (!strncmp((const char *)localname, kName_Album, kLength_Album)) { 
      NSLog(@"Parsing guid"); 
      parser.currentIncident.guid = [parser currentString]; 
     } else if (!strncmp((const char *)localname, kName_ReleaseDate, kLength_ReleaseDate)) { 
      NSLog(@"Parsing date"); 
      NSString *dateString = [parser currentString]; 
      parser.currentIncident.pubDate = [parser.parseFormatter dateFromString:dateString]; 
     } 
    } 
    parser.storingCharacters = NO; 
} 

/* 
This callback is invo 

ответ

1

С этой линией прокомментировал, как вы получаете инциденты?

- (void)parser:(IncidentsImporter *)parser didParseIncidents:(NSArray *)parsedIncidents { 
    //[incidents addObjectsFromArray: parsedIncidents]; 

Вызов reloadData, когда инциденты не изменились, на самом деле ничего не делает.

В этой же функции вы вызываете reloadData только в том случае, если стол неподвижен. Если вы его не вызываете, вы должны установить флаг для вызова reloadData после того, как таблица будет неподвижной. Для обнаружения этого есть несколько обратных вызовов делегатов UIScrollView.

+0

OK Удалили ли линию (не уверен, почему я прокомментировал это в первую очередь), но все равно не повезло! Однако здесь я установил точку останова, и он не был вызван. Нехорошо, я подозреваю, и это может быть моя проблема. – Graeme

0

Некоторые вещи, чтобы проверить:

Если установить точку останова в parserDidEndParsingData :, это ctableView указывает на действительный объект UITableView, не ноль?

Если вы наберете «происшествия» в своем приглашении gdb на этой линии, все ваши инциденты загружены?

Если вы наберете «po [self tableView]», отобразит ли тот же объект, что и «po ctableView»?

Если вы установили точку останова в таблицеView: numberOfRowsInSection: и делаете ли вы «инциденты», все они загружены? (Он будет ударять по этой точке останова несколько раз, поэтому продолжайте нажимать на нее и убедитесь, что в итоге там обнаружились инциденты.)

Если у вас есть режим IB в режиме просмотра списка, ваш TableView должен выглядеть вложенным под ваш CurrentIncidentsTableViewController. Это указывает на то, что tableView подключен к свойству представления UITableViewController. (BTW, если у вас есть это настроенное свойство, вы можете получить доступ к tableView с вашего контроллера, используя self.tableView, поэтому вам технически не нужен ctableView.)

Свойства и свойства делегата tableView должны быть подключены к вашему CurrentIncidentsTableViewController в там же

+0

Хорошо, добавили результаты. Нехорошо я не думаю. Также добавил код парсера в случае, если это поможет. – Graeme

+0

Итак, инциденты ноль. Предполагается, что он будет создан в beginParsing. Установите там точку останова. Это когда-нибудь вызвано? Кроме того, у вас есть [инциденты addObjectsFromArray: parsedIncidents]; Замечено в парсере: didParseIncidents :. Вероятно, вам захочется раскомментировать, что, как только вы убедитесь, что массив действительно создается. – cduhn

+0

ОК. Раскопали это (не уверен, почему он был прокомментирован, но в любом случае) и установите точку останова в beginParsing. Интересно, когда он достигает утверждения IF, каждый раз, когда он принимает путь else, а не тот, если я подозреваю, что он должен взять if. Любые идеи, почему это не будет сделано? Я проверил в примере приложение, и он принимает вариант if, а не другой. – Graeme

0

Попробуйте перезагрузить стол после разбора.

[table reloadData]; 

table - это пример представления таблицы, созданного конструктором интерфейса.

Этот link дает образец программы для разбора xml и отображения ее содержимого в таблице. Посмотрите на это. Упование также помогает вам.

Все самое лучшее.

+0

Привет, у меня уже есть это, но все еще не работает. – Graeme

+0

загрузите образец проекта tabrss и замените ссылку на вашу ссылку. Используйте этот код для разбора xml. – Warrior

+0

Да, это отличный пример, но у меня уже есть приложение, которое делает это - я обновляю задний конец, потому что хочу использовать вторичный поток для синтаксического анализа, чтобы остановить зависание основного потока при загрузке данных. – Graeme

Смежные вопросы