- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在构建的一个应用程序包含一个包含数千个项目的目录,这些项目需要存储在手机上。目前我正在通过 CoreData 实现这一点,因为从逻辑上讲,它似乎是放置它的最佳位置。我正在使用 GCD 在后台运行 CoreData 插入进程并显示进度条/当前完成百分比。这按预期工作,但是对于仅 5000 个项目,在 iPhone 4 上需要 8 分钟才能完成。此应用程序将在 3GS 及更高版本上使用,并且在启动后更有可能包含 30/40 千个项目。因此,这个处理时间将非常长。
有什么方法可以使用 CSV 文件或其他文件进行搜索,而不是将每个项目都存储在 CoreData 中?我假设这样的方法会导致一些效率下降,但它会减少过多的等待时间。除非有另一种解决方案可以帮助解决这个问题。
谢谢。
编辑:我不确定如何在整个操作结束时保存上下文,因为它在循环中使用了单独的上下文。对此的任何建议将不胜感激。我不知道如何在这方面取得进展。
正在使用的插入代码
- (void) processUpdatesGCD {
NSArray *jsonArray=[NSJSONSerialization JSONObjectWithData:_responseData options:0 error:nil];
NSArray *products = [jsonArray valueForKey:@"products"];
NSArray *deletions;
if ([jsonArray valueForKey:@"deletions"] == (id)[NSNull null]){
self.totalCount = [products count];
} else {
deletions = [jsonArray valueForKey:@"deletions"];
self.totalCount = [products count] + [deletions count];
}
self.productDBCount = 0;
_delegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = _delegate.managedObjectContext;
self.persistentStoreCoordinator = [managedObjectContext persistentStoreCoordinator];
_managedObjectContext = managedObjectContext;
// Create a new background queue for GCD
dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
for (id p in products) {
// id product = p;
// 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];
NSFetchRequest *BGRequest = [[NSFetchRequest alloc] init];
NSLog(@"Running.. (%@)", product);
[BGRequest setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:backgroundThreadContext]];
[BGRequest setIncludesSubentities:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
[BGRequest setPredicate:predicate];
NSError *err;
NSArray *results = [backgroundThreadContext executeFetchRequest:BGRequest error:&err];
if (results.count == 0){
// Product doesn't exist with code, make a new product
NSLog(@"Product not found for add/update (%@)", [product valueForKey:@"product_name"]);
NSManagedObject* newProduct;
newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:backgroundThreadContext];
[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 {
NSLog(@"Product found for add/update (%@)", [product valueForKey:@"product_name"]);
// 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"];
}
}
}
// Is very important that you save the context before moving to the Main Thread,
// because we need that the new object is writted on the database before continuing
NSError *error;
if(![backgroundThreadContext save:&error])
{
NSLog(@"There was a problem saving the context (add/update). With error: %@, and user info: %@",
[error localizedDescription],
[error userInfo]);
}
// Now let's move to the main thread
dispatch_async(dispatch_get_main_queue(), ^
{
// If you have a main thread context you can use it, this time i will create a
// new one
// NSManagedObjectContext *mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
// [mainThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
self.productDBCount = self.productDBCount + 1;
float progress = ((float)self.productDBCount / (float)self.totalCount);
int percent = progress * 100.0f;
// NSNumber *progress = [NSNumber numberWithFloat:((float)self.productDBCount / (float)self.totalCount)];
self.downloadUpdateProgress.progress = progress;
self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];
NSLog(@"Added / updated product %f // ProductDBCount: %i // Percentage progress: %i // Total Count: %i", progress, self.productDBCount, percent, self.totalCount);
if (self.productDBCount == self.totalCount){
[self updatesCompleted:[jsonArray valueForKey:@"last_updated"]];
}
});
});
}
if ([deletions count] > 0){
for (id d in deletions){
dispatch_async(backgroundDispatchQueue,
^{
id deleted = d;
// 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];
NSFetchRequest *BGRequest = [[NSFetchRequest alloc] init];
// NSLog(@"Running.. (%@)", deleted);
[BGRequest setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:backgroundThreadContext]];
[BGRequest setIncludesSubentities:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [deleted valueForKey:@"product_codes"]];
[BGRequest setPredicate:predicate];
NSError *err;
NSArray *results = [backgroundThreadContext executeFetchRequest:BGRequest error:&err];
if (results.count == 0){
// Product doesn't exist with code, make a new product
NSLog(@"Product not found, can't delete.. %@", [deleted valueForKey:@"product_name"]);
} else {
NSLog(@"Product found, deleting: %@", [deleted valueForKey:@"product_name"]);
// Product exists, update existing product
for (NSManagedObject *r in results) {
[backgroundThreadContext deleteObject:r];
}
}
// Is very important that you save the context before moving to the Main Thread,
// because we need that the new object is writted on the database before continuing
NSError *error;
if(![backgroundThreadContext save:&error])
{
NSLog(@"There was a problem saving the context (delete). With error: %@, and user info: %@",
[error localizedDescription],
[error userInfo]);
}
// Now let's move to the main thread
dispatch_async(dispatch_get_main_queue(), ^
{
self.productDBCount = self.productDBCount + 1;
float progress = ((float)self.productDBCount / (float)self.totalCount);
int percent = progress * 100.0f;
// NSNumber *progress = [NSNumber numberWithFloat:((float)self.productDBCount / (float)self.totalCount)];
self.downloadUpdateProgress.progress = progress;
self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];
NSLog(@"Deleted product %f // ProductDBCount: %i // Percentage progress: %i // Total Count: %i", progress, self.productDBCount, percent, self.totalCount);
if (self.productDBCount == self.totalCount){
[self updatesCompleted:[jsonArray valueForKey:@"last_updated"]];
}
/*
*
* Change the completion changes to a method. Check to see if the total number of products == total count. If it does, run the completion method.
*
*/
});
});
}
}
}
将IF放在dispatch里面,最后运行一个save
// Create a new background queue for GCD
dispatch_queue_t backgroundDispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
// id product = p;
// Dispatch the following code on our background queue
dispatch_async(backgroundDispatchQueue,
^{
NSManagedObjectContext *backgroundThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
[backgroundThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
for (id p in products) {
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
NSFetchRequest *BGRequest = [[NSFetchRequest alloc] init];
NSLog(@"Running.. (%@)", product);
[BGRequest setEntity:[NSEntityDescription entityForName:@"Products" inManagedObjectContext:backgroundThreadContext]];
[BGRequest setIncludesSubentities:NO];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"codes == %@", [product valueForKey:@"product_codes"]];
[BGRequest setPredicate:predicate];
NSError *err;
NSArray *results = [backgroundThreadContext executeFetchRequest:BGRequest error:&err];
if (results.count == 0){
// Product doesn't exist with code, make a new product
NSLog(@"Product not found for add/update (%@)", [product valueForKey:@"product_name"]);
NSManagedObject* newProduct;
newProduct = [NSEntityDescription insertNewObjectForEntityForName:@"Products" inManagedObjectContext:backgroundThreadContext];
[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 {
NSLog(@"Product found for add/update (%@)", [product valueForKey:@"product_name"]);
// 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"];
}
}
}
// Is very important that you save the context before moving to the Main Thread,
// because we need that the new object is writted on the database before continuing
// Now let's move to the main thread
dispatch_async(dispatch_get_main_queue(), ^
{
// If you have a main thread context you can use it, this time i will create a
// new one
// NSManagedObjectContext *mainThreadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSConfinementConcurrencyType];
// [mainThreadContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
self.productDBCount = self.productDBCount + 1;
float progress = ((float)self.productDBCount / (float)self.totalCount);
int percent = progress * 100.0f;
// NSNumber *progress = [NSNumber numberWithFloat:((float)self.productDBCount / (float)self.totalCount)];
self.downloadUpdateProgress.progress = progress;
self.percentageComplete.text = [NSString stringWithFormat:@"%i", percent];
NSLog(@"Added / updated product %f // ProductDBCount: %i // Percentage progress: %i // Total Count: %i", progress, self.productDBCount, percent, self.totalCount);
NSDate *currentProcessedDate = [NSDate date];
NSTimeInterval timeSinceStarted = [currentProcessedDate timeIntervalSinceDate:self.startProcessing];
NSInteger remainingProcesses = self.totalCount - self.productDBCount;
float timePerProcess = timeSinceStarted / (float)self.productDBCount;
float remainingTime = timePerProcess * (float)remainingProcesses;
self.timeRemaining.text = [NSString stringWithFormat:@"ETA: %0.0f minutes", fmodf(remainingTime, 60.0f)];
if (self.productDBCount == self.totalCount){
[self updatesCompleted:[jsonArray valueForKey:@"last_updated"]];
}
/*
*
* Change the completion changes to a method. Check to see if the total number of products == total count. If it does, run the completion method.
*
*/
});
}
NSError *error;
if(![backgroundThreadContext save:&error])
{
NSLog(@"There was a problem saving the context (add/update). With error: %@, and user info: %@",
[error localizedDescription],
[error userInfo]);
}
});
最佳答案
好的,这是你的问题。
每次插入记录时,都会对上下文进行保存操作。现在,不要这样做,那会花费很多时间。
保存一次,在循环结束时,不是每次插入记录时。
关于iphone - 使用文件 (CSV) 而不是使用 CoreData,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17185270/
按照我目前安排代码的方式,下一行将为各种托管对象上下文运行。一些获取的实体将具有“complededDate”,而其他实体将没有“completedDate”属性。 let task = retrie
我在 import CoreData 的应用程序委托(delegate)中遇到此错误。据我所知,这是因为我将一个项目命名为 coreData。但是我更改了项目的名称,然后将其删除,并且删除了 /Lib
我想将记录保存在数组中并从 CoreData 中删除它们。我尝试过使用 NSCopying 但似乎 copyWithZone 不适用于 NSManagedObject。我真的很困惑,任何帮助将不胜感激
有时我的项目中很少会出现错误(比如每第 100 个请求)。我的一些 CoreData 的请求有 data:我无法使用该数据。我真的不明白为什么会发生这种情况以及如何防止这种行为。 错误数据输出示例:
如果您使用 Xcode 创建一个新项目并告诉它在您创建项目时创建一个 CoreData 模板,则您不需要 #import 在使用 ManagedObjects 的类中。 我已经将 Core Data
我对 SQLCipher 数据库加密和 CoreData 有疑问:当我将持久存储协调器与 SQLCipher 一起使用时,它总是在第一次应用程序重新启动后因一对多关系故障而崩溃。因此,当我第一次启动该
我有一个想要添加 iCloud 支持的应用程序。此应用程序从服务器加载数据,并将数据存储在 CoreData 中,以便 NSFetchedResultsController可以管理UITableVie
我正在从 coredata 表 STUDENT 中获取数据,并使用 Array 在 tableview 中显示所有学生姓名。在选择任何一个学生姓名后(点击 tableViewCell),它会从另一个表
我在构建过程中收到以下错误。 “API 滥用:尝试序列化非拥有协调器上的存储访问(PSC = 0x7fb5ae208890,存储 PSC = 0x0)CoreData 为什么我的应用程序会出现 Cor
当将 iOS 6.0.1 上的 Core Data 托管对象上下文保存到 SQLite 存储时,我遇到了一个奇怪的“CoreData 不支持持久的跨存储关系”异常。它涉及模型中 Quotes 和 Ab
我的应用程序有两个选项卡栏...每个选项卡栏都将用户带到一个向他显示项目列表的 TableView Controller 。第一个 View 允许用户在数据库中记录条目。另一个选项卡/ View 从数
Objective-C (OC) 中使用 Core Data 是iOS应用开发中管理模型层对象的一种有效工具。Core Data 使用 ORM (对象关系映射) 技术来抽象化和管理数据。这不仅可以节省
我有一个名为visitDate的coredata属性 我想使用单独的选择器相互独立地设置日期和时间。 我意识到,当我设置时间时,我需要获取visitDate的现有日期、月份和年份,但只从NSDateP
我有这个代码示例演示如何更新核心数据中的对象,但是我遇到了一个小问题: // Retrieve the context if (managedObjectContext == nil) { m
我在 CoreData 中有一个包含整数值的列。在从中检索结果时,我希望将列值减去一个数字。 类似于:columnValue - someNumber(此数字由用户输入) 我知道我可能必须为此使用 N
有没有办法将 CoreData 模型文件(即实体描述:*.xcdatamodeld)导出到另一个项目。因为重新创建所有实体很无聊:-) 最佳答案 是的,只需将模型文件本身添加/复制到新项目中,就像任何
我使用核心数据编写了 iPhone 应用程序。当我在模拟器中运行应用程序时,它崩溃并出现以下错误: 2010-02-12 17:24:22.359 CrData[46122:4503] Unresol
我是 CoreData 的新手,在我的 iPhone 应用程序中,我想知道如何保存一些文本,然后将其重新加载。但诀窍是,当 UIDatePicker 中的日期与我相同时加载它。像日历一样保存它。 更新
我正在寻找在 CoreData 中编写一些基本查询的方法,但文档中没有示例。以下是我的查询: 我有一个费用对象,它有一个费用金额字段。 费用可以链接到 ExpenseCategory 对象。 Expe
我在标题中使用“单例”一词时可能存在术语不正确的情况。我现在正在寻找一种好的技术。我有一个名为 user 的实体,它存储用户登录的数据,例如用于发出服务器请求的 session key 。我只希望这些
我是一名优秀的程序员,十分优秀!