title: TableView not retrieving/displaying all records from SQLite database
body: <p>Recently modified my app to include a tab view controller. I'm now unable to load all of the categories that are in my SQLite database when the app launches and goes to the Categories table view nav controller on app load (CategoriesViewController). There are 6 category names that it should display; sometimes the app displays 0 rows, other times it displays 4. Modifying the XML file that this pulls data from, I got it to pull 6 categories (after a few times of 0 and fast execution speed). Leads me to think this has to do with timing of execution vs. time until the table view is loaded with data. Any ideas on what I need to change to get CategoriesViewController to display the table only after all data is read? Here's the code; please let me know if there's anything else that you'd need to see. Thanks!</p>
  
  <p>CategoriesViewController.h</p>
  
  <pre><code>#import &lt;UIKit/UIKit.h&gt;
  
  @interface CategoriesViewController : UITableViewController
  
  @property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; 
  
  - (void)fetch; // Fetches categories from data store
  
  @end
  </code></pre>
  
  <p>CategoriesViewController.m</p>
  
  <pre><code>#import "CategoriesViewController.h"
  #import "ProductsViewController.h"
  #import "Category.h"
  #import "AppDelegate.h"
  
  @interface CategoriesViewController () // Categories View Controller interface
  
  @property (nonatomic, strong) ProductsViewController *productController;
  @property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
  @property (weak, nonatomic) IBOutlet UIImageView *logoImageView;
  
  @end
  
  #pragma mark -
  
  @implementation CategoriesViewController
  
  - (void)viewDidLoad {
      [super viewDidLoad];
  
      _logoImageView.image = [UIImage imageNamed:@"company.jpg"];
  
      [self fetch]; // Fetch categories from our data store
  }
  
  - (void)fetch {
      NSError *error = nil;
      BOOL success = [self.fetchedResultsController performFetch:&amp;error]; // Fetch results; if error, assign error code, output message
      NSAssert2(success, @"Unhandled error performing fetch at CategoriessViewController.m, line %d: %@", __LINE__, [error localizedDescription]);
  }
  
  - (NSFetchedResultsController *)fetchedResultsController {
      if (_fetchedResultsController == nil) {
          NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
          AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
          [fetchRequest setEntity:[NSEntityDescription entityForName:@"Category" inManagedObjectContext:app.managedObjectContext]]; // Fetch categories
          NSArray *sortDescriptors = nil;
          NSString *sectionNameKeyPath = nil;
          sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"order" ascending:YES]];
          [fetchRequest setSortDescriptors:sortDescriptors];
  
          _fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                          managedObjectContext:app.managedObjectContext
                                                                            sectionNameKeyPath:sectionNameKeyPath
                                                                                     cacheName:nil];
              }
      return _fetchedResultsController;
  }
  
  #pragma mark - UITableViewDataSource
  
  - (NSInteger)numberOfSectionsInTableView:(UITableView *)table {
      return [[self.fetchedResultsController sections] count];
  }
  
  - (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section {
      id &lt;NSFetchedResultsSectionInfo&gt; sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
      return [sectionInfo numberOfObjects];
  }
  
  - (UITableViewCell *)tableView:(UITableView *)table cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      static NSString *kCellIdentifier = @"CategoryCell";
  
      UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];
      Category *category = [self.fetchedResultsController objectAtIndexPath:indexPath];
      cell.textLabel.text = [NSString stringWithFormat:NSLocalizedString(@"%@", @"%@"), category.name];
      return cell;
  }
  
  // Pass managed object to ProductsViewController
  - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
      if ([[segue identifier] isEqualToString:@"showProducts"]) {
          ProductsViewController *detailsController = (ProductsViewController *)[segue destinationViewController];
          NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];
  
          detailsController.category = [self.fetchedResultsController objectAtIndexPath:selectedIndexPath];
  
          AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
          [[segue destinationViewController] setManagedObjectContext:app.managedObjectContext];
      }
  }
  
  @end
  </code></pre>
  
  <p>AppDelegate.h</p>
  
  <pre><code>#import &lt;UIKit/UIKit.h&gt;
  #import "companyXMLImporter.h"
  
  @interface AppDelegate : NSObject &lt;UIApplicationDelegate, companyXMLImporterDelegate&gt;
  
  @property (nonatomic, strong) UIWindow *window;
  @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
  @property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
  
  - (NSDate *)lasModificationDateOfFileAtURL:(NSURL *)url;
  
  @end
  </code></pre>
  
  <p>AppDelegate.m</p>
  
  <pre><code>#import "AppDelegate.h"
  #import "ProductsViewController.h"
  #import "CategoriesViewController.h"
  
  @interface AppDelegate()
  
  @property (nonatomic, strong) ProductsViewController *productsViewController;
  @property (nonatomic, strong) CategoriesViewController *categoriesViewController;
  
  // Properties for the importer and its background processing
  @property (nonatomic, strong) companyXMLImporter *importer;
  @property (nonatomic, strong) NSOperationQueue *operationQueue;
  
  @property (nonatomic, strong) NSString *persistentStorePath;
  
  @end
  
  @implementation AppDelegate
  
  static NSString * const kLastStoreUpdateKey = @"LastStoreUpdate"; // Identifies update object in user defaults storage
  
  static NSTimeInterval const kRefreshTimeInterval = 3600;
  
  - (void)applicationDidFinishLaunching:(UIApplication *)application {
      NSDate *lastUpdate = [[NSUserDefaults standardUserDefaults] objectForKey:kLastStoreUpdateKey];
      NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:NSLocalizedString(@"Products XML", @"Products XML")]];
      NSDate *lastModifiedDate = [self lasModificationDateOfFileAtURL:url];
      if (lastUpdate == nil || lastModifiedDate &gt;= lastUpdate ||  -[lastUpdate timeIntervalSinceNow] &gt; kRefreshTimeInterval) {
          if ([[NSFileManager defaultManager] fileExistsAtPath:self.persistentStorePath]) {
              NSError *error = nil;
              BOOL oldStoreRemovalSuccess = [[NSFileManager defaultManager] removeItemAtPath:self.persistentStorePath error:&amp;error];
              NSAssert3(oldStoreRemovalSuccess, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
          }
  
          // Object to retrieve, parse, and import into CoreData store
          self.importer = [[companyXMLImporter alloc] init];
          self.importer.delegate = self;
  
          // pass coordinator so importer can create its own managed object context
          self.importer.persistentStoreCoordinator = self.persistentStoreCoordinator;
  
          // URL for products XML file
          self.importer.companyURL = [NSURL URLWithString:[NSString stringWithFormat:NSLocalizedString(@"Products XML", @"Products XML")]];
          [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
  
          [self.operationQueue addOperation:self.importer];
      }
  }
  
  - (NSOperationQueue *)operationQueue {
      if (_operationQueue == nil) {
          _operationQueue = [[NSOperationQueue alloc] init];
      }
      return _operationQueue;
  }
  
  - (NSDate *)lasModificationDateOfFileAtURL:(NSURL *)url {
      NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
  
      // Get only header
      request.HTTPMethod = @"HEAD";
      NSHTTPURLResponse *response = nil;
      NSError *error = nil;
      [NSURLConnection sendSynchronousRequest:request
                            returningResponse:&amp;response
                                        error:&amp;error];
  
      if (error) {
          NSLog(@"Error: %@", error.localizedDescription);
          return nil;
      } else if([response respondsToSelector:@selector(allHeaderFields)]) {
          NSDictionary *headerFields = [response allHeaderFields];
          NSString *lastModification = [headerFields objectForKey:@"Last-Modified"];
  
          NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
          [formatter setDateFormat:@"EEE, dd MMM yyyy HH:mm:ss zzz"];
          return [formatter dateFromString:lastModification];
      }
      return nil;
  }
  
  - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
      if (_persistentStoreCoordinator == nil) {
          NSURL *storeUrl = [NSURL fileURLWithPath:self.persistentStorePath];
          _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];
          NSError *error = nil;
          NSPersistentStore *persistentStore = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&amp;error];
          NSAssert3(persistentStore != nil, @"Unhandled error adding persistent store in %s at line %d: %@", __FUNCTION__, __LINE__, [error localizedDescription]);
      }
      return _persistentStoreCoordinator;
  }
  
  - (NSManagedObjectContext *)managedObjectContext {
      if (_managedObjectContext == nil) {
          _managedObjectContext = [[NSManagedObjectContext alloc] init];
          [self.managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
      }
      return _managedObjectContext;
  }
  
  - (NSString *)persistentStorePath {
      if (_persistentStorePath == nil) {
          NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
          NSString *documentsDirectory = [paths lastObject];
          _persistentStorePath = [documentsDirectory stringByAppendingPathComponent:@"Company.sqlite"];
      }
      return _persistentStorePath;
  }
  
  - (void)importerDidSave:(NSNotification *)saveNotification {
      if ([NSThread isMainThread]) {
          [self.managedObjectContext mergeChangesFromContextDidSaveNotification:saveNotification];
  //        [self.categoriesViewController fetch];
          [self.productsViewController fetch];
      } else {
          [self performSelectorOnMainThread:@selector(importerDidSave:) withObject:saveNotification waitUntilDone:NO];
      }
  }
  
  // Main-thread import completion processing
  - (void)handleImportCompletion {
      [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:kLastStoreUpdateKey];
      [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
      self.importer = nil;
  }
  
  - (void)importerDidFinishParsingData:(companyXMLImporter *)importer {
      [self performSelectorOnMainThread:@selector(handleImportCompletion) withObject:nil waitUntilDone:NO];
  }
  
  // Process errors received in delegate callback
  - (void)handleImportError:(NSError *)error {
      [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
      self.importer = nil;
  
      NSString *errorMessage = [error localizedDescription];
      NSString *alertTitle = NSLocalizedString(@"Error", @"Title for alert displayed when download or parse error occurs.");
      NSString *okTitle = NSLocalizedString(@"OK ", @"OK Title for alert displayed when download or parse error occurs.");
  
      UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:alertTitle
                                                          message:errorMessage
                                                         delegate:nil
                                                cancelButtonTitle:okTitle
                                                otherButtonTitles:nil];
      [alertView show];
  }
  
  - (void)importer:(companyXMLImporter *)importer didFailWithError:(NSError *)error {
      [self performSelectorOnMainThread:@selector(handleImportError:) withObject:error waitUntilDone:NO];
  }
  
  @end
  </code></pre>
  
  <p>companyXMLImporter.h</p>
  
  <pre><code>#import &lt;UIKit/UIKit.h&gt;
  #import &lt;libxml/tree.h&gt;
  
  @class companyXMLImporter, Product, Category, CategoryCache;
  
  @protocol companyXMLImporterDelegate &lt;NSObject&gt;
  
  @optional
  
  - (void)importerDidSave:(NSNotification *)saveNotification; // Posted when saved
  - (void)importerDidFinishParsingData:(companyXMLImporter *)importer; // Called when parsing is finished
  - (void)importer:(companyXMLImporter *)importer didFailWithError:(NSError *)error; // Called if error
  
  @end
  
  @interface companyXMLImporter : NSOperation {
  @private
      id &lt;companyXMLImporterDelegate&gt; __unsafe_unretained delegate;
  
      // Reference to the libxml parser context
      xmlParserCtxtPtr context;
      NSURLConnection *xmlConnection;
  
      BOOL done;
  
      BOOL parsingAProduct;
  
      // Used for getting character data from XML elements
      BOOL storingCharacters;
      NSMutableData *characterBuffer;
  
      Product *currentProduct;
  
      NSUInteger countForCurrentBatch;
      NSManagedObjectContext *insertionContext;
      NSPersistentStoreCoordinator *persistentStoreCoordinator;
      NSEntityDescription *productEntityDescription;
      CategoryCache *theCache;
      NSURL *companyURL;
  }
  
  @property (nonatomic, retain) NSURL *companyURL;
  @property (nonatomic, assign) id &lt;companyXMLImporterDelegate&gt; delegate;
  @property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;
  @property (nonatomic, retain, readonly) NSManagedObjectContext *insertionContext;
  @property (nonatomic, retain, readonly) NSEntityDescription *productEntityDescription;
  @property (nonatomic, retain, readonly) CategoryCache *theCache;
  
  - (void)main;
  
  @end
  </code></pre>
  
  <p>companyXMLImporter.m</p>
  
  <pre><code>#import "companyXMLImporter.h"
  #import "Product.h"
  #import "Category.h"
  #import "CategoryCache.h"
  #import &lt;libxml/tree.h&gt;
  
  // Function prototypes for SAX callbacks
  static void startElementSAX(void *context, 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 *context, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI);
  static void charactersFoundSAX(void *context, const xmlChar *characters, int length);
  static void errorEncounteredSAX(void *context, const char *errorMessage, ...);
  
  static xmlSAXHandler simpleSAXHandlerStruct; // Forward reference. Structure defined in full at end of file
  
  @interface companyXMLImporter ()
  
  @property BOOL storingCharacters;
  @property (nonatomic, retain) NSMutableData *characterBuffer;
  @property BOOL done;
  @property BOOL parsingAProduct;
  @property NSUInteger countForCurrentBatch;
  @property (nonatomic, retain) Product *currentProduct;
  @property (nonatomic, retain) NSURLConnection *xmlConnection;
  @property (nonatomic, retain) NSDateFormatter *dateFormatter;
  
  @end
  
  static double lookuptime = 0;
  
  @implementation companyXMLImporter
  
  @synthesize companyURL, delegate, persistentStoreCoordinator;
  @synthesize xmlConnection, done, parsingAProduct, storingCharacters, currentProduct, countForCurrentBatch, characterBuffer;
  
  - (void)main {
      if (delegate &amp;&amp; [delegate respondsToSelector:@selector(importerDidSave:)]) {
          [[NSNotificationCenter defaultCenter] addObserver:delegate selector:@selector(importerDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
      }
      done = NO;
      self.characterBuffer = [NSMutableData data];
      NSURLRequest *theRequest = [NSURLRequest requestWithURL:companyURL];
  
      xmlConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self]; // create connection with request and start loading data
  
      context = xmlCreatePushParserCtxt(&amp;simpleSAXHandlerStruct, (__bridge void *)(self), NULL, 0, NULL);
      if (xmlConnection != nil) {
          do {
              [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
          } while (!done);
      }
  
      // Release thread resources
      xmlFreeParserCtxt(context);
      self.characterBuffer = nil;
      self.dateFormatter = nil;
      self.xmlConnection = nil;
      self.currentProduct = nil;
      theCache = nil;
  
      NSError *saveError = nil;
      NSAssert1([insertionContext save:&amp;saveError], @"Unhandled error saving managed object context in import thread: %@", [saveError localizedDescription]);
      if (delegate &amp;&amp; [delegate respondsToSelector:@selector(importerDidSave:)]) {
          [[NSNotificationCenter defaultCenter] removeObserver:delegate name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
      }
      if (self.delegate != nil &amp;&amp; [self.delegate respondsToSelector:@selector(importerDidFinishParsingData:)]) {
          [self.delegate importerDidFinishParsingData:self];
      }
  }
  
  - (NSManagedObjectContext *)insertionContext {
      if (insertionContext == nil) {
          insertionContext = [[NSManagedObjectContext alloc] init];
          [insertionContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
      }
      return insertionContext;
  }
  
  - (void)forwardError:(NSError *)error {
      if (self.delegate != nil &amp;&amp; [self.delegate respondsToSelector:@selector(importer:didFailWithError:)]) {
          [self.delegate importer:self didFailWithError:error];
      }
  }
  
  - (NSEntityDescription *)productEntityDescription {
      if (productEntityDescription == nil) {
          productEntityDescription = [NSEntityDescription entityForName:@"Product" inManagedObjectContext:self.insertionContext];
      }
      return productEntityDescription;
  }
  
  - (CategoryCache *)theCache {
      if (theCache == nil) {
          theCache = [[CategoryCache alloc] init];
          theCache.managedObjectContext = self.insertionContext;
      }
      return theCache;
  }
  
  - (Product *)currentProduct {
      if (currentProduct == nil) {
          currentProduct = [[Product alloc] initWithEntity:self.productEntityDescription insertIntoManagedObjectContext:self.insertionContext];
      }
      return currentProduct;
  }
  
  // Forward errors to delegate
  - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
      [self performSelectorOnMainThread:@selector(forwardError:) withObject:error waitUntilDone:NO];
      done = YES; // End run loop
  }
  
  // Called when a chunk of data has been downloaded
  - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
      // Process downloaded chunk of data
      xmlParseChunk(context, (const char *)[data bytes], [data length], 0);
  }
  
  - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
      // Signal the context that parsing is complete by passing "1" as last parameter
      xmlParseChunk(context, NULL, 0, 1);
      context = NULL;
      done = YES; // End the loop
  }
  
  static const NSUInteger kImportBatchSize = 20;
  
  - (void)finishedCurrentProduct {
      parsingAProduct = NO;
      self.currentProduct = nil;
      countForCurrentBatch++;
  
      if (countForCurrentBatch == kImportBatchSize) {
          NSError *saveError = nil;
          NSAssert1([insertionContext save:&amp;saveError], @"Unhandled error saving managed object context in import thread: %@", [saveError localizedDescription]);
          countForCurrentBatch = 0;
      }
  }
  
  // Character data appended to a buffer until current element ends.
  - (void)appendCharacters:(const char *)charactersFound length:(NSInteger)length {
      [characterBuffer appendBytes:charactersFound length:length];
  }
  
  - (NSString *)currentString {
      // Create a string with character data using UTF-8 encoding
      NSString *currentString = [[NSString alloc] initWithData:characterBuffer encoding:NSUTF8StringEncoding];
      [characterBuffer setLength:0];
      return currentString;
  }
  
  @end
  
  // XML element names, string lengths for parsing
  static const char *kName_App = "App"; // Product container tag
  static const NSUInteger kLength_App = 4;
  static const char *kName_Sku = "prod_sku";
  static const NSUInteger kLength_Sku = 9;
  static const char *kName_Name = "prod_name";
  static const NSUInteger kLength_Name = 10;
  static const char *kName_Description = "prod_description";
  static const NSUInteger kLength_Description = 17;
  static const char *kName_Category = "prod_category";
  static const NSUInteger kLength_Category = 14;
  static const char *kName_Upc = "prod_upc";
  static const NSUInteger kLength_Upc = 9;
  static const char *kName_CountryCode = "prod_code_destination";
  static const NSUInteger kLength_CountryCode = 22;
  static const char *kName_Webpage = "prod_html_link";
  static const NSUInteger kLength_Webpage = 15;
  static const char *kName_Manual = "prod_manual";
  static const NSUInteger kLength_Manual = 12;
  static const char *kName_QuickStart = "prod_quick_start";
  static const NSUInteger kLength_QuickStart = 17;
  static const char *kName_Thumbnail = "prod_thumbnail";
  static const NSUInteger kLength_Thumbnail = 15;
  static const char *kName_MainImage = "prod_image_main";
  static const NSUInteger kLength_MainImage = 16;
  static const char *kName_SecondaryImage = "prod_image_secondary";
  static const NSUInteger kLength_SecondaryImage = 21;
  
  // Invoked when importer finds beginning of a node
  static void startElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
                              int nb_namespaces, const xmlChar **namespaces, int nb_attributes, int nb_defaulted, const xmlChar **attributes) {
  
      companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
  
      if (!strncmp((const char *)localname, kName_App, kLength_App)) {
          importer.parsingAProduct = YES;
          } else if (importer.parsingAProduct &amp;&amp; ((!strncmp((const char *)localname, kName_Sku, kLength_Sku) || !strncmp((const char *)localname, kName_Name, kLength_Name) || !strncmp((const char *)localname, kName_Description, kLength_Description) || !strncmp((const char *)localname, kName_Category, kLength_Category) || !strncmp((const char *)localname, kName_Upc, kLength_Upc) || !strncmp((const char *)localname, kName_CountryCode, kLength_CountryCode) || !strncmp((const char *)localname, kName_Webpage, kLength_Webpage) || !strncmp((const char *)localname, kName_Manual, kLength_Manual) || !strncmp((const char *)localname, kName_QuickStart, kLength_QuickStart) || !strncmp((const char *)localname, kName_Thumbnail, kLength_Thumbnail) || !strncmp((const char *)localname, kName_MainImage, kLength_MainImage) || !strncmp((const char *)localname, kName_SecondaryImage, kLength_SecondaryImage)))
                     ) {
          importer.storingCharacters = YES;
      }
  }
  
  // Invoked when parse reaches end of a node
  static void endElementSAX(void *parsingContext, const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI) {
      companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
  
      if (importer.parsingAProduct == NO) return;
      if (!strncmp((const char *)localname, kName_App, kLength_App)) {
          [importer finishedCurrentProduct];
      } else if (!strncmp((const char *)localname, kName_Name, kLength_Name)) {
          importer.currentProduct.name = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Category, kLength_Category)) {
          double before = [NSDate timeIntervalSinceReferenceDate];
          Category *category = [importer.theCache categoryWithName:importer.currentString];
          double delta = [NSDate timeIntervalSinceReferenceDate] - before;
          lookuptime += delta;
          importer.currentProduct.category = category;
      } else if (!strncmp((const char *)localname, kName_Sku, kLength_Sku)) {
          importer.currentProduct.sku = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Description, kLength_Description)) {
          importer.currentProduct.prodDescription = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Upc, kLength_Upc)) {
          importer.currentProduct.upc = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_CountryCode, kLength_CountryCode)) {
          importer.currentProduct.countryCode = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Webpage, kLength_Webpage)) {
          importer.currentProduct.webpage = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Manual, kLength_Manual)) {
          importer.currentProduct.manual = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_QuickStart, kLength_QuickStart)) {
          importer.currentProduct.quickStart = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_Thumbnail, kLength_Thumbnail)) {
          importer.currentProduct.thumbURLString = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_MainImage, kLength_MainImage)) {
          importer.currentProduct.mainImgURLString = importer.currentString;
      } else if (!strncmp((const char *)localname, kName_SecondaryImage, kLength_SecondaryImage)) {
          importer.currentProduct.secondaryImgURLString = importer.currentString;
      }
      importer.storingCharacters = NO;
  }
  
  // Invoked when parser encounters character data inside a node
  static void charactersFoundSAX(void *parsingContext, const xmlChar *characterArray, int numberOfCharacters) {
      companyXMLImporter *importer = (__bridge companyXMLImporter *)parsingContext;
  
      // storingCharacters set when nodes of interest begin/end – determines whether character data handled/ignored
      if (importer.storingCharacters == NO) return;
      [importer appendCharacters:(const char *)characterArray length:numberOfCharacters];
  }
  
  // Error handling
  static void errorEncounteredSAX(void *parsingContext, const char *errorMessage, ...) {
      // Handle errors as appropriate
      NSCAssert(NO, @"Unhandled error encountered during SAX parse.");
  }
  
  static xmlSAXHandler simpleSAXHandlerStruct = {
      NULL, /* internalSubset */
      NULL, /* isStandalone   */
      NULL, /* hasInternalSubset */
      NULL, /* hasExternalSubset */
      NULL, /* resolveEntity */
      NULL, /* getEntity */
      NULL, /* entityDecl */
      NULL, /* notationDecl */
      NULL, /* attributeDecl */
      NULL, /* elementDecl */
      NULL, /* unparsedEntityDecl */
      NULL, /* setDocumentLocator */
      NULL, /* startDocument */
      NULL, /* endDocument */
      NULL, /* startElement*/
      NULL, /* endElement */
      NULL, /* reference */
      charactersFoundSAX, /* characters */
      NULL, /* ignorableWhitespace */
      NULL, /* processingInstruction */
      NULL, /* comment */
      NULL, /* warning */
      errorEncounteredSAX, /* error */
      NULL,/* fatalError //: unused error() get all the errors */
      NULL, /* getParameterEntity */
      NULL, /* cdataBlock */
      NULL, /* externalSubset */
      XML_SAX2_MAGIC, //
      NULL,
      startElementSAX, /* startElementNs */
      endElementSAX, /* endElementNs */
      NULL, /* serror */
  };
  </code></pre>