0

I need 1 sec delay in for loop but it is not working. I need to remove tableview cell with 1 sec delay with animation so it will remove one by one. Currently all rows are deleting at the same time.For loop is already in dispatch_after for 3 sec so over all it nested dispatch_after.Out side the for loop dispatch_after is working.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    for(int i=array_messages.count;i>0;i--)
     {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
            [array_messages removeObjectAtIndex:0];
            NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
            [self.tableViewMessage deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
            });

     }
    });
DJtiwari
  • 519
  • 1
  • 6
  • 21
  • Why wouldn't they? You are dispatching serially, but with no delay between dispatches. You need to make it recursive -- have each dispatch block dispatch the next deletion. – Avi May 05 '16 at 06:06
  • I confirm this. After using Grand Central Dispatch for years and years I have to say that GCD has a lot of problems. Depending on the kind of code you are developing, GCD mechanisms simply do not work as expected. I had to replace a code today where a block was being fired followed by a dispatch_after code to cancel the operation seconds later because the whole thing was not working on iPhone 5. The same code was working perfectly on iPhone 6. Both running iOS 9.3.2. On iPhone 5 the dispatch_after was firing before the specified time. I recommend using NSOperationQueue instead. – Duck May 27 '16 at 23:52

5 Answers5

1

You cannot put delay on 'for loop'. If you want to loop something with a delay use NSTimer.

rakeshNS
  • 4,227
  • 4
  • 28
  • 42
1

Your for loop will iterate through the entire sequence almost instantly, which means your inner dispatch_after calls will all be set near the same time, and so will execute at around the same time, which is what you're seeing.

You would likely be better served in this case with an NSTimer. Something like this:

Create an NSTimer property to use:

@property (strong) NSTimer* deletionTimer = nil;

Add these methods to your class:

- (void)startDeletionTimer {
    [self killDeletionTimer];
    self.deletionTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(deletionTimerFired:) userInfo:nil repeats:YES];
}

- (void)killDeletionTimer {
    [self.deletionTimer invalidate];
    self.deletionTimer = nil;
}

- (void)deletionTimerFired:(NSTimer*)timer {
    NSUInteger numberOfRecords = [array_messages count];

    if (!numberOfRecords) {
        // None left, we're done
        [self killDeleteionTimer];
        return;
    }

    [array_messages removeObjectAtIndex:0];
    [self.tableViewMessage deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationTop];
}

Initiate the timer with this:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    [self startDeletionTimer];
});

This has a few advantages over options using the inner dispatch_after with a delay. It will gracefully handle changes in the array_messages array since it's count is checked on each iteration, not assumed at the start. So for example, if you have 30 messages, your whole delete process will take 30 seconds. If a new message is added in that time period, or worse, a message is removed somehow, your app will crash when the last dispatch_after triggers, since the index and/or row won't exist. Similarly, if the user navigates away from the view, the tableView may be deallocated and you'll crash then.

Another advantage is if in those 30 seconds while it's slowly/painfully showing the records be deleted, the user wants to just move on, you can kill the timer and just delete all the rows at once.

Dave Wood
  • 13,143
  • 2
  • 59
  • 67
0

Use the below code to delay the code execution

double delayInSeconds = 1.0;
dispatch_time_t disTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(disTime, dispatch_get_main_queue(), ^(void){
    //place your code
});

Let me know if you have any issues.

itsji10dra
  • 4,603
  • 3
  • 39
  • 59
Madhu
  • 439
  • 2
  • 14
0

Try this i am not practically tried so not sure

for(int i=array_messages.count;i>0;i--)
                    {

                        int delay = (array_messages.count - i) + 1;
                        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_main_queue(), ^{


                            [array_messages removeObjectAtIndex:0];

                            NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];

                            [self.tableViewMessage deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
                        });

                    }
Shreyank
  • 1,549
  • 13
  • 24
-1

@ DJTiwari Try This it's work

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        for(int i=array_messages.count;i>0;i--)
        {
            [NSThread sleepForTimeInterval:1];
            [array_messages removeObjectAtIndex:0];
            NSIndexPath *path = [NSIndexPath indexPathForRow:0 inSection:indexPath.section];
            [self.tableViewMessage deleteRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationTop];
        }
    });
});
rakeshNS
  • 4,227
  • 4
  • 28
  • 42
Akshay Degada
  • 139
  • 2
  • 13
  • 1
    You do not want `[NSThread sleepForTimeInterval:1];` in code running on the main thread. This will lock up the app completely because you've included that inside the `dispatch_async(dispatch_get_main_queue()` block. – Dave Wood May 05 '16 at 06:58
  • I'm not going to argue with you, I'm sure it looks like it works, but I bet if you have a bunch of objects in the array, your app is locked up and you can't even scroll the tableView up/down while it's doing it's thing (sleeping). You never want `sleepForTimeInterval` on the main thread (or in the main queue which executes on the main thread). Ever. – Dave Wood May 05 '16 at 07:25
  • @DaveWood i don't understand why you are facing problem with this answer but i have try this code with 100 records of array and it's work good, thanks for informed me. – Akshay Degada May 05 '16 at 07:37