Brandon A
Brandon A

Reputation: 8279

Objective-C: Best practice to call method every second

THE SCENARIO I need a method to fire off every second. I also need to be able to stop the firing of the method at any time. At the moment I am using an NSTimer:

THE CODE

self.controlTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updatePlayer) userInfo:nil repeats:YES];

THE ISSUE I am certain I can achieve this functionality using an NSTimer and call invalidate when I want it to stop, however I am concerned about the performance overhead of placing an NSTimer in a UITableViewCell.

THE QUESTION Does anyone know of a more light-weight alternative to calling a method every second?

Upvotes: 0

Views: 1173

Answers (2)

Beltalowda
Beltalowda

Reputation: 4678

I have used NSTimer instances inside of UITableViewCell and UICollectionViewCell custom subclasses to do what you are doing, but I created a protocol PLMMonitor to provide -startMonitoring and -stopMonitoring contracts on my cells to start/stop (see: invalidate) any timing mechanisms.

The Protocol

(Obviously the protocol name prefix can be easily changed)

@protocol PLMMonitor <NSObject>

@required

- (void)startMonitoring;
- (void)stopMonitoring;

@end

Using Cell Visibility to Control the Timers

I could then utilize -[UITableViewDataSource tableView:cellForRowAtIndexPath:] or -[UICollectionViewDelegate collectionView:willDisplayCell:forItemAtIndexPath:] to call -startMonitoring on the cell if it conforms to the protocol (allows for mixed cells in the UITableView/UICollectionView):

- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell conformsToProtocol:@protocol(PLMMonitor)])
    {
        [(UICollectionViewCell<PLMMonitor> *)cell startMonitoring];
    }
}

Then I utilized the -[UITableViewDelegate tableView:didEndDisplayingCell:forRowAtIndexPath:] or -[UICollectionViewDelegate collectionView:didEndDisplayingCell:forItemAtIndexPath:] to call -stopMonitoring on the cell if it conformed to the protocol (again allowing for mixed cells in the UITableView/UICollectionView):

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell conformsToProtocol:@protocol(PLMMonitor)])
    {
        [(UICollectionViewCell<PLMMonitor> *)cell stopMonitoring];
    }
}

Using View Controller Visibility to Control the Timers

You should also add code to -viewWillAppear and -viewWillDisappear to -startMonitoring and -stopMonitoring on the visible cells that conform to the protocol to ensure the timers get started/stopped appropriately when they are no longer visible:

- (void)viewWillAppear
{
    for (UICollectionViewCell *aCell in [self.collectionView visibleCells])
    {
        if ([aCell conformsToProtocol:@protocol(PLMMonitor)])
        {
            [(UICollectionViewCell<PLMMonitor> *)aCell startMonitoring];
        }
    }
}

- (void)viewWillDisappear
{
    for (UICollectionViewCell *aCell in [self.collectionView visibleCells])
    {
        if ([aCell conformsToProtocol:@protocol(PLMMonitor)])
        {
            [(UICollectionViewCell<PLMMonitor> *)aCell stopMonitoring];
        }
    }
}

Performance Implications / Energy Usage of NSTimers

One way you can reduce the impact NSTimer instances have on battery life, etc is the make use of their tolerance property which allows iOS to do some power savings magic with them while sacrificing a strict firing interval.

Alternative Timer/Trigger Mechanisms

Upvotes: 3

David Vallas
David Vallas

Reputation: 17

NSTimer is pretty lightweight. You just need to make sure you properly handle the Cell's timer when the cell is reused.

Upvotes: 2

Related Questions