我正在开发的应用程序通过API下载产品目录(将是大约40,000种产品)并将它们解析为CoreData,以便可以轻松搜索它们。
我有这种方法来处理数据的解析,下载它可以完美地按照预期工作。我有一个下载进度条和一个处理进度条。下载可按要求工作,但标签(或进度条)不会更改为处理文本或百分比进度。我已经以编程方式检查了它确实将正确的标签文本输出到控制台,它只是没有在视图中显示。
使用活动监视器进行检查后,手机正在最大程度地降低CPU ...所以我猜这就是为什么没有显示任何视图上的更改。无论如何,我可以减少计算负荷并让它正确显示进度条吗?我确信这远不是有效的代码,我还没有完全进入我认识最佳实践的阶段等。
修改为使用循环GCD
我已经更改了代码以使用GCD,但是在运行时这会给我一个错误: *由于未捕获的异常'NSGenericException'而终止应用,原因:'* Collection&lt ; __ NSCFSet:0x8b26720>在被列举时被突变。'
- (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
}
原始代码
- (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
}
答案 0 :(得分:2)
您需要在多个线程上运行以释放主线程以进行UI工作。遗憾的是,多线程上的核心数据并非易事。此链接演示了实现此http://www.cocoanetics.com/2012/07/multi-context-coredata/
的绝妙方式答案 1 :(得分:1)
您可以尝试在后台进行抓取活动。
dispatch_queue_t <your dispatch>;//do it in .m before @implementation
然后
<your dispatch>=dispatch_queue_create("name", nil);//create your dispatch
然后编码
dispatch_async(myDispatch_photosView, ^{<your code>});
这会阻止您的视图落后
答案 2 :(得分:0)
我选择了这样的东西。我找不到一个有效的例子,所以希望这将有助于将来的某个人。非常基本,但你应该能够得到这个主义。这是我最终选择的解决方案。
dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
for (id p in products) {
// Dispatch the following code on our background queue
dispatch_async(backgroundDispatchQueue,
^{
id product = p;
// Because at this point we are running in another thread we need to create a
// new NSManagedContext using the app's persistance store coordinator
NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
/*
*
*
* Perform fetch and other actions as required.
*
*
*/
dispatch_async(dispatch_get_main_queue(), ^
{
self.productDBCount = self.productDBCount + 1;
float progress = ((float)self.productDBCount / (float)self.totalCount);
int percent = progress * 100.0f;
self.downloadUpdateProgress.progress = progress;
self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];
});
});
}