Objective-C: 每秒调用方法的最佳实践
Objective-C: Best practice to call method every second
场景 我需要一种每秒触发的方法。我还需要能够随时停止该方法的触发。目前我正在使用 NSTimer
:
代码
self.controlTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updatePlayer) userInfo:nil repeats:YES];
问题 我确定我可以使用 NSTimer
实现此功能,并在我希望它停止时调用 invalidate
,但我很担心关于在 UITableViewCell 中放置 NSTimer
的性能开销。
问题有谁知道每秒调用一个方法的更轻量级替代方法?
NSTimer 非常轻量级。您只需要确保在重复使用单元格时正确处理单元格的计时器即可。
我已经在 UITableViewCell
和 UICollectionViewCell
自定义子类中使用了 NSTimer
个实例来完成您正在做的事情,但我创建了一个协议 PLMMonitor
来提供 -startMonitoring
和 -stopMonitoring
在我的单元格上与 start/stop (参见:invalidate
)任何计时机制的合同。
协议
(显然协议名称前缀可以很容易地改变)
@protocol PLMMonitor <NSObject>
@required
- (void)startMonitoring;
- (void)stopMonitoring;
@end
使用单元格可见性来控制计时器
然后我可以利用 -[UITableViewDataSource tableView:cellForRowAtIndexPath:]
or -[UICollectionViewDelegate collectionView:willDisplayCell:forItemAtIndexPath:]
在符合协议的单元格上调用 -startMonitoring
(允许 UITableView/UICollectionView
中的混合单元格):
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell conformsToProtocol:@protocol(PLMMonitor)])
{
[(UICollectionViewCell<PLMMonitor> *)cell startMonitoring];
}
}
然后我使用 -[UITableViewDelegate tableView:didEndDisplayingCell:forRowAtIndexPath:]
or -[UICollectionViewDelegate collectionView:didEndDisplayingCell:forItemAtIndexPath:]
在符合协议的单元格上调用 -stopMonitoring
(再次允许 UITableView/UICollectionView
中的混合单元格):
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell conformsToProtocol:@protocol(PLMMonitor)])
{
[(UICollectionViewCell<PLMMonitor> *)cell stopMonitoring];
}
}
使用视图控制器可见性来控制计时器
您还应该将代码添加到 -viewWillAppear
和 -viewWillDisappear
到 -startMonitoring
和 -stopMonitoring
在 visible 单元格符合到协议以确保计时器在不再可见时得到适当的started/stopped:
- (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];
}
}
}
NSTimers 的性能影响/能源使用
可以减少 NSTimer
实例对电池寿命等影响的一种方法是利用它们的 tolerance
属性,它允许 iOS 执行 some power savings magic with them while sacrificing a strict firing interval.
替代Timer/Trigger机制
您可以使用 Grand Central Dispatch (GCD) dispatch_after()
机制,但您将失去取消调用的能力。
另一种选择是利用 -[NSObject
performSelector:withObject:afterDelay:]
方法和
伴随 +[NSObject
cancelPreviousPerformRequestsWithTarget:selector:object:]
安排要调用的选择器和取消调用的方法
分别
场景 我需要一种每秒触发的方法。我还需要能够随时停止该方法的触发。目前我正在使用 NSTimer
:
代码
self.controlTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updatePlayer) userInfo:nil repeats:YES];
问题 我确定我可以使用 NSTimer
实现此功能,并在我希望它停止时调用 invalidate
,但我很担心关于在 UITableViewCell 中放置 NSTimer
的性能开销。
问题有谁知道每秒调用一个方法的更轻量级替代方法?
NSTimer 非常轻量级。您只需要确保在重复使用单元格时正确处理单元格的计时器即可。
我已经在 UITableViewCell
和 UICollectionViewCell
自定义子类中使用了 NSTimer
个实例来完成您正在做的事情,但我创建了一个协议 PLMMonitor
来提供 -startMonitoring
和 -stopMonitoring
在我的单元格上与 start/stop (参见:invalidate
)任何计时机制的合同。
协议
(显然协议名称前缀可以很容易地改变)
@protocol PLMMonitor <NSObject>
@required
- (void)startMonitoring;
- (void)stopMonitoring;
@end
使用单元格可见性来控制计时器
然后我可以利用 -[UITableViewDataSource tableView:cellForRowAtIndexPath:]
or -[UICollectionViewDelegate collectionView:willDisplayCell:forItemAtIndexPath:]
在符合协议的单元格上调用 -startMonitoring
(允许 UITableView/UICollectionView
中的混合单元格):
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell conformsToProtocol:@protocol(PLMMonitor)])
{
[(UICollectionViewCell<PLMMonitor> *)cell startMonitoring];
}
}
然后我使用 -[UITableViewDelegate tableView:didEndDisplayingCell:forRowAtIndexPath:]
or -[UICollectionViewDelegate collectionView:didEndDisplayingCell:forItemAtIndexPath:]
在符合协议的单元格上调用 -stopMonitoring
(再次允许 UITableView/UICollectionView
中的混合单元格):
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
if ([cell conformsToProtocol:@protocol(PLMMonitor)])
{
[(UICollectionViewCell<PLMMonitor> *)cell stopMonitoring];
}
}
使用视图控制器可见性来控制计时器
您还应该将代码添加到 -viewWillAppear
和 -viewWillDisappear
到 -startMonitoring
和 -stopMonitoring
在 visible 单元格符合到协议以确保计时器在不再可见时得到适当的started/stopped:
- (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];
}
}
}
NSTimers 的性能影响/能源使用
可以减少 NSTimer
实例对电池寿命等影响的一种方法是利用它们的 tolerance
属性,它允许 iOS 执行 some power savings magic with them while sacrificing a strict firing interval.
替代Timer/Trigger机制
您可以使用 Grand Central Dispatch (GCD)
dispatch_after()
机制,但您将失去取消调用的能力。另一种选择是利用
-[NSObject performSelector:withObject:afterDelay:]
方法和 伴随+[NSObject cancelPreviousPerformRequestsWithTarget:selector:object:]
安排要调用的选择器和取消调用的方法 分别