iphone - 使用文件 (CSV) 而不是使用 CoreData

标签 iphone ios objective-c

我正在构建的一个应用程序包含一个包含数千个项目的目录,这些项目需要存储在手机上。目前我正在通过 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/

相关文章:

ios - 构建失败 : Could not find an option named "track-widget-creation"

iphone - 是否可以保证iPhone应用程序可以在iPod touch上运行?

iphone - 如何在 .c 文件中使用 iOS 中的 Grand Central Dispatch

css - 防止在 iPhone 上的导航栏品牌中拉伸(stretch) Logo

objective-c - 将 Objective-C block 移植到 Swift

objective-c - 将 NSValue 转换回 CGPoint

ios - 在 iphone 5 中调整相机表的大小

ios - 如何根据 Childviewcontroller(UIViewController 的不同大小)高度更改容器 View (父 View )的高度?

ios - 在 Storyboard 中,UIScrollview 无法正常使用自动调整大小。没有代码如何管理?

ios - 赋予按钮相同的行为(双胞胎)