TableView无法从SQLite数据库

时间:2016-06-20 05:36:08

标签: ios objective-c sqlite uitableview

最近修改了我的应用程序以包含选项卡视图控制器。我现在无法在应用程序启动时加载我的SQLite数据库中的所有类别,并转到应用程序加载(CategoriesViewController)上的Categories表视图导航控制器。它应该显示6个类别名称;有时应用程序显示0行,有时显示4行。修改从中提取数据的XML文件,我得到它来拉6个类别(经过几次0和快速执行速度)。引导我认为这与执行时间与时间直到表视图加载数据有关。有关我需要更改的任何想法,以使CategoriesViewController仅在读取所有数据后显示表格?这是代码;如果您还需要查看其他内容,请告诉我。谢谢!

CategoriesViewController.h

#import <UIKit/UIKit.h>

@interface CategoriesViewController : UITableViewController

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; 

- (void)fetch; // Fetches categories from data store

@end

CategoriesViewController.m

#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:&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 <NSFetchedResultsSectionInfo> 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

AppDelegate.h

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

@interface AppDelegate : NSObject <UIApplicationDelegate, companyXMLImporterDelegate>

@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (NSDate *)lasModificationDateOfFileAtURL:(NSURL *)url;

@end

AppDelegate.m

#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 >= lastUpdate ||  -[lastUpdate timeIntervalSinceNow] > kRefreshTimeInterval) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:self.persistentStorePath]) {
            NSError *error = nil;
            BOOL oldStoreRemovalSuccess = [[NSFileManager defaultManager] removeItemAtPath:self.persistentStorePath error:&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:&response
                                      error:&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:&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

companyXMLImporter.h

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

@class companyXMLImporter, Product, Category, CategoryCache;

@protocol companyXMLImporterDelegate <NSObject>

@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 <companyXMLImporterDelegate> __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 <companyXMLImporterDelegate> 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

companyXMLImporter.m

#import "companyXMLImporter.h"
#import "Product.h"
#import "Category.h"
#import "CategoryCache.h"
#import <libxml/tree.h>

// 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 && [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(&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:&saveError], @"Unhandled error saving managed object context in import thread: %@", [saveError localizedDescription]);
    if (delegate && [delegate respondsToSelector:@selector(importerDidSave:)]) {
        [[NSNotificationCenter defaultCenter] removeObserver:delegate name:NSManagedObjectContextDidSaveNotification object:self.insertionContext];
    }
    if (self.delegate != nil && [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 && [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:&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 && ((!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 */
};

1 个答案:

答案 0 :(得分:0)

您根本不需要调用reloadData来获取要在表中显示的数据...并且您在viewDidLoad和fetch中调用它两次。我会摆脱这些。

听起来好像有时间问题。您能解释一下数据如何进入数据库吗?当你说,

  

修改此数据库从...中提取数据的XML文件

我认为您的意思是,当您的应用启动时,它会从您的应用程序打包的XML文件中读取,并将此信息写入Core Data / Sqlite。如果这确实是你做的,那么可能问题是这个过程试图在你的CategoriesViewController加载的同时运行。将XML读入Core Data / Sqlite的代码在哪里?你在哪里叫它?是同步还是异步调用?