NSTimer的selector回调中如何获取关联的Car类对象引用
NSTimer绑定自定义对象方案解答
你的子类化方案不可行
原因有两点:
- NSTimer属于类簇类型,苹果官方明确不建议子类化。类簇的底层实现隐藏了大量内部逻辑,强行子类化很容易出现不可预期的运行异常。
- 你给出的示例代码存在本质错误:
[NSTimer scheduledTimerWithTimeInterval...]返回的仍然是原生NSTimer实例,强制转换为CustomTimer类型访问car属性时,会直接触发找不到方法的崩溃。
更合理的实现方案
- 方案1:使用NSTimer自带的userInfo参数传递Car对象
这是官方设计的标准传参方式,实现成本最低。
创建定时器时把Car对象传入userInfo:
// 遍历所有Car对象创建定时器 for (Car *car in self.carList) { [NSTimer scheduledTimerWithTimeInterval:car.triggerInterval target:self selector:@selector(timerTick:) userInfo:car repeats:YES]; }
回调中直接读取userInfo即可:
- (void)timerTick:(NSTimer *)timer { Car *currentCar = timer.userInfo; NSLog(@"当前触发定时器的车辆名称:%@", currentCar.name); // 其他业务逻辑 }
- 方案2:使用Block版本的定时器接口(iOS 10+支持)
可以直接在Block中捕获对应的Car对象,不需要单独实现回调方法,代码更简洁,注意避免循环引用即可:
for (Car *car in self.carList) { __weak typeof(self) weakSelf = self; [NSTimer scheduledTimerWithTimeInterval:car.triggerInterval repeats:YES block:^(NSTimer * _Nonnull timer) { __strong typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) return; NSLog(@"当前触发定时器的车辆名称:%@", car.name); // 其他业务逻辑 }]; }
- 方案3:维护映射字典(特殊场景使用)
如果需要同时传递多个自定义参数,也可以维护一个全局的NSMutableDictionary,用定时器的唯一标识作为key,存储对应的Car对象,回调时查询字典即可。不过该方案需要额外处理字典的线程安全和内存清理,复杂度更高,一般不推荐。
额外注意事项
- 定时器不再使用时必须调用
invalidate方法销毁,避免Target被循环引用无法释放。 - 如果定时器需要在列表滑动时也正常触发,需要手动将定时器添加到NSRunLoop的NSRunLoopCommonModes模式中。
内容的提问来源于stack exchange,提问作者Mark Freewind
相关产品推荐
相关产品推荐

