An App I'm developing pulls down a product catalogue (will be approx 40,000 products) via an API and parses them into CoreData so they can be easily searched through.
I have this method to handle the parsing of the data, downloading it works perfectly and as intended. I have a download progress bar and a processing progress bar. The download one works as required, but the label (or progress bar) doesn't change to the processing text or percentage progress. I've checked programmatically and it does output the correct label text to the console, it just doesn't show in the view.
Having checked using the activity monitor, the phone is maxing out CPU wise.. so I'm guessing that's why none of the on-view changes are being shown. Is there anyway I can reduce the computational load and get it showing the progress bar properly? I'm sure this is far from efficient code anyway, I haven't quite go to the stage where I know best practices etc..
Modified to use loop GCD
I've changed the code to make use of GCD, however this is giving me an error when run though: * Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection <__NSCFSet: 0x8b26720> was mutated while being enumerated.'
- (void) processUpdatesBG {
NSArray *jsonArray=[NSJSONSerialization JSONObjectWithData:_responseData options:0 error:nil];
NSArray *products = [jsonArray valueForKey:@"products"];
NSInteger productDBCount = _productDBCount;
productDBCount = 0;
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = delegate.managedObjectContext;
_managedObjectContext = managedObjectContext;
self.totalCount = [products count];
for (id product in products) {
dispatch_queue_t processTheUpdates = dispatch_queue_create("com.app.process_the_updates", 0);
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:_managedObjectContext]];
[request setIncludesSubentities:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
[request setPredicate:predicate];
dispatch_async(processTheUpdates, ^{
NSError *err;
NSArray *results = [_managedObjectContext executeFetchRequest:request error:&err];
if (results.count == 0){
// Product doesn't exist with code, make a new product
NSLog(@"Product.. %@", [product valueForKey:@"product_name"]);
NSManagedObject* newProduct;
newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:_managedObjectContext];
[newProduct setValue:[product valueForKey:@"product_name"] forKey:@"name"];
[newProduct setValue:[product valueForKey:@"product_codes"] forKey:@"codes"];
if ([product valueForKey:@"information"] == (id)[NSNull null]){
// No information, NULL
[newProduct setValue:@"" forKey:@"information"];
} else {
NSString *information = [product valueForKey:@"information"];
[newProduct setValue:information forKey:@"information"];
}
} else {
// Product exists, update existing product
for (NSManagedObject *r in results) {
[r setValue:[product valueForKey:@"product_name"] forKey:@"name"];
if ([product valueForKey:@"information"] == (id)[NSNull null]){
// No information, NULL
[r setValue:@"" forKey:@"information"];
} else {
NSString *information = [product valueForKey:@"information"];
[r setValue:information forKey:@"information"];
}
}
}
dispatch_async(dispatch_get_main_queue(), ^{
self.productDBCount = productDBCount + 1;
NSNumber *progress = [NSNumber numberWithFloat:(self.productDBCount / self.totalCount)];
self.downloadUpdateProgress.progress = [progress floatValue];
NSLog(@"Added product");
});
});
}
NSError *error;
if ([self.managedObjectContext save:&error]) {
NSLog(@"Database Updated");
} else {
NSLog(@"Database not Updated, Error: %@", error);
}
self.updateStatus.text = @"Update Completed!";
self.downloadUpdateProgress.hidden = YES;
self.close.hidden = NO;
// NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
// [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *now = [[NSDate alloc] init];
// NSString *currentTimestamp = [dateFormatter stringFromDate:now];
// NSLog(@"%@", currentTimestamp);
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *apiUpdateTimestamp = [jsonArray valueForKey:@"last_updated"];
[prefs setObject:now forKey:@"last_downloaded_update"];
[prefs setObject:apiUpdateTimestamp forKey:@"api_update_timestamp"];
[prefs synchronize];
// Set the lastDownloadedTimestamp as today
// Set the last
}
Original Code
- (void) processUpdates {
self.updateStatus.text = @"Processing Updates";
self.downloadUpdateProgress.progress = 0;
NSArray *jsonArray=[NSJSONSerialization JSONObjectWithData:_responseData options:0 error:nil];
NSArray *products = [jsonArray valueForKey:@"products"];
NSInteger productDBCount = 0;
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = delegate.managedObjectContext;
_managedObjectContext = managedObjectContext;
NSInteger totalCount = [products count];
for (id product in products) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:_managedObjectContext]];
[request setIncludesSubentities:NO];
NSError *err;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
[request setPredicate:predicate];
NSArray *results = [_managedObjectContext executeFetchRequest:request error:&err];
if (results.count == 0){
// Product doesn't exist with code, make a new product
NSManagedObject* newProduct;
newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:_managedObjectContext];
[newProduct setValue:[product valueForKey:@"product_name"] forKey:@"name"];
[newProduct setValue:[product valueForKey:@"product_codes"] forKey:@"codes"];
if ([product valueForKey:@"information"] == (id)[NSNull null]){
// No information, NULL
[newProduct setValue:@"" forKey:@"information"];
} else {
NSString *information = [product valueForKey:@"information"];
[newProduct setValue:information forKey:@"information"];
}
} else {
// Product exists, update existing product
for (NSManagedObject *r in results) {
[r setValue:[product valueForKey:@"product_name"] forKey:@"name"];
if ([product valueForKey:@"information"] == (id)[NSNull null]){
// No information, NULL
[r setValue:@"" forKey:@"information"];
} else {
NSString *information = [product valueForKey:@"information"];
[r setValue:information forKey:@"information"];
}
}
}
productDBCount = productDBCount + 1;
NSNumber *progress = [NSNumber numberWithFloat:(productDBCount / totalCount)];
self.downloadUpdateProgress.progress = [progress floatValue];
}
NSError *error;
if ([self.managedObjectContext save:&error]) {
NSLog(@"Database Updated");
} else {
NSLog(@"Database not Updated, Error: %@", error);
}
self.updateStatus.text = @"Update Completed!";
self.downloadUpdateProgress.hidden = YES;
self.close.hidden = NO;
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSDate *now = [[NSDate alloc] init];
NSString *currentTimestamp = [dateFormatter stringFromDate:now];
NSLog(@"%@", currentTimestamp);
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *apiUpdateTimestamp = [jsonArray valueForKey:@"last_updated"];
[prefs setObject:currentTimestamp forKey:@"last_downloaded_update"];
[prefs setObject:apiUpdateTimestamp forKey:@"api_update_timestamp"];
[prefs synchronize];
// Set the lastDownloadedTimestamp as today
// Set the last
}