2015-06-29 3 views
0

В моем приложении я хочу иметь возможность сразу удалить все строки конкретной таблицы и перезагрузить таблицу при вызове блока завершения.Удалите все строки из таблицы сразу с завершением в Swift

Я знаю, как удалить одну строку:

override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
     switch editingStyle { 
     case .Delete: 
      // remove the deleted item from the model 
      let appDel:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate 
      let context:NSManagedObjectContext = appDel.managedObjectContext! 
      context.deleteObject(myData[indexPath.row] as NSManagedObject) 
      myData.removeAtIndex(indexPath.row) 
      context.save(nil) 

      //tableView.reloadData() 
      // remove the deleted item from the `UITableView` 
      self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
     default: 
      return 

     } 
} 

Я также знаю, что я могу извлечь все строки и удалять их по одному в цикле, но я изо всех сил о том, как добавить блок завершения к нему, поэтому я могу перерисовать таблицу после удаления.

Любая помощь очень ценится.

+0

Вы хотите, чтобы блок завершения для анимации исчезновения действия удаления? – luk2302

+0

Я хочу, чтобы завершение для reloadTable ... это не будет вызвано из этого метода выше.У меня будет другой метод, например deleteAll(), где я буду вызывать все элементы из БД для конкретной таблицы, а затем в блоке завершения при успешном удалении всех элементов из массива источников данных и перезагрузите таблицу. –

+0

@EugeneGordin, если вы правильно реализуете методы делегирования FetchedResultsController, вам не нужно вызывать какие-либо методы для перезагрузки таблицы, поскольку это будет выполняться автоматически при добавлении или удалении управляемых объектов. Поэтому просто создайте метод deleteAll(), а затем используйте moc.deleteObject (object), чтобы удалить все объекты, а затем перезагрузить их все. Пользовательский интерфейс должен обновляться, чтобы отражать эти изменения, без необходимости переписывать reloadData. –

ответ

0

Некоторые примеры кода ниже. Обычным способом было бы выполнить большую операцию удаления или добавления в фоновом потоке, а затем использовать уведомление для запуска слияния в основном потоке. Таким образом, приведенный ниже код предполагает следующее:

  • У вас есть главный ManagedObjectContext, который используется в
    FetchedResultsController в вашем TableView
  • У вас есть вспомогательные функции для запуска удалить или нагрузку методы фоновых потоков
  • создается фон managedObjectContexts и зарегистрировать ContextDidSave уведомлений, которые вы затем использовать для слияния изменений в основной контекст

Вспомогательная функция для вызова нагрузки или удаления.

- (void)deleteDataInBackground { 

      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { 
       [self deleteData]; 
      }); 
} 

функция Load

/* Loads the required seed data */ 
    // Usually called on a background thread and therefor we need to process the DidSave notification 
    // to merge the changed with the main context so the UI gets updated 
    func loadData() { 
     //FLOG(" called"); 

     let bgContext:NSManagedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.ConfinementConcurrencyType) 

     // Register for saves in order to merge any data from background threads 
     NSNotificationCenter.defaultCenter().addObserver(self, selector:"storesDidSave:", name: NSManagedObjectContextDidSaveNotification, object:bgContext) 

     while (persistentStoreCoordinator == nil) { 
      //FLOG(@" persistentStoreCoordinator = nil, waiting 5 seconds to try again..."); 
      sleep(5); 
     } 

     bgContext.persistentStoreCoordinator = persistentStoreCoordinator 



     insertStatusCode(bgContext, number: 0, name: "Not started") 
     insertStatusCode(bgContext, number: 1, name: "Started on track") 
     insertStatusCode(bgContext, number: 2, name: "Behind schedule") 
     insertStatusCode(bgContext, number: 3, name: "Completed") 
     insertStatusCode(bgContext, number: 4, name: "Completed behind schedule") 
     insertStatusCode(bgContext, number: 5, name: "On hold or cancelled") 


     bgContext.processPendingChanges() 

     do { 

      try bgContext.save() 

      //FLOG(" Seed data loaded") 

     } catch { 
      //FLOG(" Unresolved error \(error), \(error?.userInfo)") 
     } 
    } 


Code to insert new records 

    func insertStatusCode(moc:NSManagedObjectContext, number:Int, name:String) 
    { 
     //FLOG(" called") 

     if let newManagedObject:NSManagedObject = NSEntityDescription.insertNewObjectForEntityForName("StatusCode", inManagedObjectContext:moc) { 

      newManagedObject.setValue(number, forKey:"number") 
      newManagedObject.setValue(name, forKey:"name") 

     }   
    } 

код для обработки уведомлений и объединить изменения в основной контекст

// NB - this may be called from a background thread so make sure we run on the main thread !! 
// This is when transaction logs are loaded 
func storesDidSave(notification: NSNotification!) { 

    // Ignore any notifications from the main thread because we only need to merge data 
    // loaded from other threads. 
    if (NSThread.isMainThread()) { 
     //FLOG(" main thread saved context") 
     return 
    } 

    NSOperationQueue.mainQueue().addOperationWithBlock { 
     //FLOG("storesDidSave ") 
     // Set this so that after the timer goes off we perform a save 
     // - without this the deletes don't appear to trigger the fetchedResultsController delegate methods ! 
     self.import_or_save = true 

     self.createTimer() // Timer to prevent this happening too often! 
     if let moc = self.managedObjectContext { 
      moc.mergeChangesFromContextDidSaveNotification(notification) 
     } 

    } 
} 

А вот Obj-C функция удаления, обратите внимание, что есть некоторые проверки, чтобы убедиться, что объекты не были удалены другим потоком ...

- (void)deleteData { 
    FLOG(@"deleteData called"); 
    _deleteJobCount++; 
    [self postJobStartedNotification]; 

    FLOG(@" waiting 5 seconds..."); 
    sleep(5); 
    [self showBackgroundTaskActive]; 

    NSManagedObjectContext *bgContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 

    // Register for saves in order to merge any data from background threads 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(storesDidSave:) name: NSManagedObjectContextDidSaveNotification object:bgContext]; 


    while (self.persistentStoreCoordinator == nil) { 
     FLOG(@" persistentStoreCoordinator = nil, waiting 5 seconds to try again..."); 
     sleep(5); 
    } 

    bgContext.persistentStoreCoordinator = [self persistentStoreCoordinator]; 

    FLOG(@" fetching data..."); 

    NSArray *companies = [self getData:@"Company" sortField:@"name" predicate:nil managedObjectContext:bgContext]; 

    NSUInteger count = companies.count; 

    if (count>2) { 
     for (int i = 0; i<3; i++) { 
      NSManagedObject *object = [companies objectAtIndex:i]; 

      // Must wrap this incase another thread deleted it already 
      @try { 
       if ([object isDeleted]) { 
        FLOG(@" object has been deleted"); 
       } else { 
        FLOG(@" deleting %@", [object valueForKey:@"name"]); 
        [bgContext deleteObject:object]; 
        [bgContext processPendingChanges]; 
        NSError *error = nil; 
        if (![bgContext save:&error]) { 
         FLOG(@" Unresolved error %@, %@", error, [error userInfo]); 
        } 
       } 
      } 
      @catch (NSException *exception) { 
       FLOG(@" error deleting object"); 
       FLOG(@" exception is %@", exception); 
      } 


      FLOG(@" waiting 5 seconds..."); 
      sleep(0.01); 
     } 

    } 

    [[NSNotificationCenter defaultCenter] removeObserver:self name: NSManagedObjectContextDidSaveNotification object:bgContext]; 

    /* 
    dispatch_async(dispatch_get_main_queue(),^(void){ 
    [[NSNotificationCenter defaultCenter] removeObserver:self name: NSManagedObjectContextDidSaveNotification object:nil]; 
    }); 
    */ 

    FLOG(@" delete ended..."); 
    [self showBackgroundTaskInactive]; 
    _deleteJobCount--; 
    [self postJobDoneNotification]; 

} 

Если у вас есть большой пакет, взгляните на пакетные функции Core Data.

0

В основном все, что вам нужно сделать, это сделать то, что вы сказали, что хотите сделать в блоке завершения - просто удалите все элементы из источника данных и обновите таблицу. Методы делегата UITableView datasource сделают все остальное для вас и опустят tableView.

+0

Я действительно прошу пример метода delete с блоком завершения. Если бы я знал, как сделать блок завершения для основных данных, я бы не стал задавать этот вопрос :) –

0

deleteRowsAtIndexPaths:withRowAnimation: Просто используйте метод и применить код из следующего вопроса - How to detect that animation has ended on UITableView beginUpdates/endUpdates?

Это даст вам завершающий функциональные возможности блока, что вы ищете, так что вы будете в состоянии назвать reloadData в нем.

Для Swift это будет выглядеть следующим образом:

CATransaction.begin() 
CATransaction.setCompletionBlock { 
    //Reload data here 
} 

tableView.beginUpdates() 
//Remove cells here 
tableView.endUpdates() 

CATransaction.commit() 
+0

это код Objective-C, знаете ли вы, как это сделать быстро? –

+0

Я не знаю сейчас, но смогу прояснить это через минуту. –

+0

Готово. Обновлен с помощью вызовов Swift. Это было довольно прозрачно. Пожалуйста, проверьте. –

Смежные вопросы