我正在将数据从SQL Server同步到iPad。数据以XML格式提供。数据大小为7.18MB。拉数据很快几秒钟,但我必须填充我的CoreData DB走XML。目前,在CoreData中插入数据和所有关系需要21分钟。我想改进这个并做了很多事情:
我想知道是否有人可以提出任何改进建议。我想要废除的一件事就是我已经在做的线程不再是因为它导致了解决的问题。
显示了4种方法。首先获取数据,第二个获取XML并处理主子节点,第三个保存上下文,最后一个是子节点处理方法之一,但是大多数数据占用整个时间超过80的方法。
提前致谢
- (void) performFullSync {
@autoreleasepool {
[Common LogInfo:@"Begin" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
AFPromoPortalHTTPClient *myClient = [AFPromoPortalHTTPClient sharedClient];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
AccountManager *am = appDelegate.accountManager;
if (appDelegate.syncInProgress) {
return;
}
appDelegate.syncInProgress = YES;
if (am != nil) {
NSString *urlMethodWithParameters = [NSString stringWithFormat: @"GetFullSyncData?accountManagerId=%@", am.userId];
[self updateUIProgressLabelWithText:@"Daten werden synchronisiert."];
[myClient getPath:urlMethodWithParameters parameters:nil
success:^(AFHTTPRequestOperation *operation, id responseObject) {
@autoreleasepool {
NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
// Create a background thread to process the XML data
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
[self processSyncData:responseString];
});
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
[Common LogError:[NSString stringWithFormat:@"Error calling GetFullSyncData webservice: %@",[error localizedDescription]] ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
NSLog(@"Daten konnte nicht synchronisiert werden: %@ ", error.userInfo);
[self updateUIProgressLabelWithText:@"Daten konnte nicht synchronisiert werden..."];
});
[self closeSyncProgress];
}];
}
[Common LogInfo:@"End" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
}
}
- (void) processSyncData: (NSString *)data {
[Common LogInfo:@"Begin" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
if (data.length != 0) {
// Create context on background thread
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.syncManagedObjectContext = [[NSManagedObjectContext alloc] init];
[self.syncManagedObjectContext setUndoManager:nil];
[self.syncManagedObjectContext setPersistentStoreCoordinator: [appDelegate persistentStoreCoordinator]];
[appDelegate registerContextDidSaveNotificationForManagedObjectContext:self.syncManagedObjectContext];
[self updateUIProgressLabelWithText:@"Daten werden geladen."];
NSError *__autoreleasing* error = nil;
//data = [data xmlSimpleUnescapeString];
data = [data stringByReplacingOccurrencesOfString:@"<" withString:@"<"];
data = [data stringByReplacingOccurrencesOfString:@">" withString:@">"];
// Read the full XML data
TBXML *tbxmlFullData = [TBXML newTBXMLWithXMLString: data error: error];
if (error == nil) {
// Get the root node
TBXMLElement *rtNode = [TBXML childElementNamed:@"rt" parentElement:tbxmlFullData.rootXMLElement];
if(rtNode != nil) {
@autoreleasepool {
// Process pricelist types
[self updateUIProgressLabelWithText:@"Preislisten werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *priceListTypeNode = [TBXML childElementNamed:@"plts" parentElement:rtNode];
if (priceListTypeNode != nil) {
priceListTypeNode = priceListTypeNode->firstChild;
[self createPriceListTypeFromNode:priceListTypeNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process products
[self updateUIProgressLabelWithText:@"Produktdaten werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *productsNode = [TBXML childElementNamed:@"ps" parentElement:rtNode];
if (productsNode != nil) {
productsNode = productsNode->firstChild;
[self createProductsFromNode:productsNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process promotions
[self updateUIProgressLabelWithText:@"Förderungdaten werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *promotionsNode = [TBXML childElementNamed:@"prs" parentElement:rtNode];
if (promotionsNode != nil) {
promotionsNode = promotionsNode->firstChild;
[self createPromotionsFromNode:promotionsNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process promotion products
[self updateUIProgressLabelWithText:@"Promotion-Produkte werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *promotionProductsNode = [TBXML childElementNamed:@"pps" parentElement:rtNode];
if (promotionProductsNode != nil) {
promotionProductsNode = promotionProductsNode->firstChild;
[self createPromotionAndProductRelationshipFromNode:promotionProductsNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process customers
[self updateUIProgressLabelWithText:@"Kundendaten werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *customerNode = [TBXML childElementNamed:@"cs" parentElement:rtNode];
if (customerNode != nil) {
customerNode = customerNode->firstChild;
[self createCustomersFromNode:customerNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process standard prices
[self updateUIProgressLabelWithText:@"Listenpreise werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *standardPriceNode = [TBXML childElementNamed:@"spps" parentElement:rtNode];
if (standardPriceNode != nil) {
standardPriceNode = standardPriceNode->firstChild;
[self createStandardPricesFromNode:standardPriceNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
// Process sales history
// if (self.syncType == StartUpSync) {
// // Process product sales history
// TBXMLElement *productSalesHistoryNode = [TBXML childElementNamed:@"sh" parentElement:rtNode];
// if (productSalesHistoryNode != nil) {
// productSalesHistoryNode = productSalesHistoryNode->firstChild;
// [self createProductSalesHistoryFromNode:productSalesHistoryNode inMOC:self.syncManagedObjectContext];
// }
// }
@autoreleasepool {
// Process Order Statuses
[self updateUIProgressLabelWithText:@"Auftragsstatus wird geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *orderStatusNode = [TBXML childElementNamed:@"oss" parentElement:rtNode];
if (orderStatusNode != nil) {
orderStatusNode = orderStatusNode->firstChild;
[self createOrderStatusesFromNode:orderStatusNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process order
[self updateUIProgressLabelWithText:@"Aufträge werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *orderNode = [TBXML childElementNamed:@"os" parentElement:rtNode];
if (orderNode != nil) {
orderNode = orderNode->firstChild;
[self createOrdersFromNode:orderNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
@autoreleasepool {
// Process customer prices
[self updateUIProgressLabelWithText:@"Kundenpreise werden geladen. Vielen Dank für Ihre Geduld..."];
TBXMLElement *customerPriceNode = [TBXML childElementNamed:@"cpps" parentElement:rtNode];
if (customerPriceNode != nil) {
customerPriceNode = customerPriceNode->firstChild;
[self createCustomerPricesFromNode:customerPriceNode inMOC:self.syncManagedObjectContext];
}
[self saveAndClearContext];
}
NSDate *lsd;
// Read the saver last synced date
TBXMLElement *lastSyncDateNode = [TBXML childElementNamed:@"sd" parentElement:rtNode];
if (lastSyncDateNode != nil) {
lastSyncDateNode = lastSyncDateNode->firstChild;
lsd = [self getDateFromString:[TBXML valueOfAttributeNamed:@"date" forElement:lastSyncDateNode] ];
NSLog(@"%@",lsd);
}
// Save the context.
NSError *error = nil;
[self updateUIProgressLabelWithText:@"Daten werden auf Ihrem iPad gespeichert."];
if (![self.syncManagedObjectContext save:&error]) {
NSLog(@"\nFehler! Daten konnten nicht auf Ihrem iPad gespeichert werden: %@", [error localizedDescription]);
[Common LogError:[NSString stringWithFormat:@"Error saving data: %@",[error localizedDescription]] ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
[self closeSyncProgress];
}
else {
[self updateUIProgressLabelWithText:@"Synchronisation abgeschlossen."];
[Common updateLastSynchedDate:lsd];
if (self.syncType!=StartUpSync) {
[self processPendingOrdersinMOC:self.syncManagedObjectContext];
}
else
[self closeSyncProgress];
}
}
else
[self closeSyncProgress];
}
}else
[self closeSyncProgress];
[Common LogInfo:@"End" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
}
-(void)saveAndClearContext{
NSError *error = nil;
if (![self.syncManagedObjectContext save:&error]) {
NSLog(@"\nFehler! Daten konnten nicht auf Ihrem iPad gespeichert werden: %@", [error localizedDescription]);
[Common LogError:[NSString stringWithFormat:@"Error saving data: %@",[error localizedDescription]] ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
}
else {
[self.syncManagedObjectContext reset];
}
}
- (void) createCustomerPricesFromNode: (TBXMLElement*)customerPriceNode inMOC: (NSManagedObjectContext*) moc {
[Common LogInfo:@"Begin" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
CustomerPrice *newCustomerPrice = nil;
Customer *c = nil;
while(customerPriceNode != nil) {
if (self.syncType == StartUpSync)
newCustomerPrice = (CustomerPrice *)[NSEntityDescription insertNewObjectForEntityForName:@"CustomerPrice" inManagedObjectContext:moc];
else
{
// Incremental sync
NSNumber *customerPriceId = [NSNumber numberWithInt: [[TBXML valueOfAttributeNamed:@"id" forElement:customerPriceNode] intValue]];
NSPredicate *pred = [NSPredicate predicateWithFormat: @"customerPriceId == %i", [customerPriceId intValue]];
newCustomerPrice = (CustomerPrice *)[Common getEntityWithName:@"CustomerPrice" usingPredicate:pred inManagedObjectContext:moc];
// New CustomerPrice found during Incremental sync
if (newCustomerPrice == nil) {
newCustomerPrice = (CustomerPrice *)[NSEntityDescription insertNewObjectForEntityForName:@"CustomerPrice" inManagedObjectContext:moc];
}
}
if (newCustomerPrice != nil) {
newCustomerPrice.customerPriceId = [NSNumber numberWithInt: [[TBXML valueOfAttributeNamed:@"id" forElement:customerPriceNode] intValue]];
newCustomerPrice.validFrom = [self getDateFromString:[TBXML valueOfAttributeNamed:@"vF" forElement:customerPriceNode]];
newCustomerPrice.validTo = [self getDateFromString:[TBXML valueOfAttributeNamed:@"vT" forElement:customerPriceNode]];
newCustomerPrice.price = [NSDecimalNumber decimalNumberWithString:[TBXML valueOfAttributeNamed:@"pr" forElement:customerPriceNode]];
newCustomerPrice.enabled =[NSNumber numberWithBool: [[TBXML valueOfAttributeNamed:@"en" forElement:customerPriceNode] boolValue]];
newCustomerPrice.deleted =[NSNumber numberWithBool: [[TBXML valueOfAttributeNamed:@"del" forElement:customerPriceNode] boolValue]];
// Get Customer and Product and associate them with customer price
NSNumber *cId = [NSNumber numberWithInt:[[TBXML valueOfAttributeNamed:@"cRef" forElement:customerPriceNode] intValue]];
NSNumber *pId = [NSNumber numberWithInt:[[TBXML valueOfAttributeNamed:@"pRef" forElement:customerPriceNode] intValue]];
[self updateUIProgressLabelWithText:[NSString stringWithFormat:@"Kundenpreise werden geladen. Vielen Dank für Ihre Geduld. \nKunde: %@. Produkt: %@.", cId, pId]];
if (c == nil || [c.customerId intValue] != [cId intValue]) {
if (newCustomerPrice.customerPriceCustomer == nil) {
NSPredicate *pred = [NSPredicate predicateWithFormat: @"customerId == %i", [cId intValue]];
c = (Customer *)[Common getEntityWithName:@"Customer" usingPredicate:pred inManagedObjectContext:moc];
newCustomerPrice.customerPriceCustomer = c;
}
}
else {
newCustomerPrice.customerPriceCustomer = c;
}
if (newCustomerPrice.customerPriceProduct == nil) {
NSPredicate *pred = [NSPredicate predicateWithFormat: @"productId == %i", [pId intValue]];
Product *p = (Product *)[Common getEntityWithName:@"Product" usingPredicate:pred inManagedObjectContext:moc];
newCustomerPrice.customerPriceProduct = p;
}
customerPriceNode = [TBXML nextSiblingNamed:@"cpp" searchFromElement:customerPriceNode];
}
}
[Common LogInfo:@"End" ForClass:NSStringFromClass([self class]) withSelector:NSStringFromSelector(_cmd)];
}
================慢速方法=================
21%
-(NSDate *) getDateFromString:(NSString *)dateString
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
if ([dateString rangeOfString:@"."].location == NSNotFound) {
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss"];
}
else
[dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.zzz"];
// [dateFormat setLocale:[NSLocale currentLocale]];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
NSDate *date = [dateFormatter dateFromString:dateString];
return date;
}
61%
+ (NSManagedObject*) getEntityWithName: (NSString*)entityName usingPredicate: (NSPredicate*) predicate inManagedObjectContext: (NSManagedObjectContext*) moc {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:moc];
request.entity = entity;
request.predicate = predicate;
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[moc executeFetchRequest:request error:&error] mutableCopy];
if (mutableFetchResults == nil || mutableFetchResults.count < 1 ) {
return nil;
}
else
{
return [mutableFetchResults objectAtIndex:0];
}
}