不要忘记 NSTimer 会 retain它的对象,意味着如果你的timer的 target 也是 NSTimer的 拥有者的时候,很容易就进入一个循环引用。
你可以通过一个 代理的delegate来 绕过这个, 这个代理对象拥有这个真正target的 weak 引用。
@interface TMWeakTimerTarget : NSObject
- (instancetype)initWithTarget:(id)target selector:(SEL)selector;
- (void)timerDidFire:(NSTimer *)timer;
@end
@interface TMWeakTimerTarget()
@property (nonatomic, weak) id target;
@property (nonatomic) SEL selector;
@end
@implementation TMWeakTimerTarget
#pragma mark - Initialization
- (instancetype)initWithTarget:(id)target selector:(SEL)selector {
if (self = [super init]) {
_target = target;
_selector = selector;
}
return self;
}
- (id)init {
return [self initWithTarget:nil selector:nil];
}
#pragma mark - TMWeakTimerTarget
- (void)timerDidFire:(NSTimer *)timer {
if (self.target) {
// `performSelector:` would generate a potential leak warning (http://stackoverflow.com/a/7073761/503916)
objc_msgSend(self.target, self.selector);
}
else {
[timer invalidate];
}
}
@end
你可以创建一个 NSTimer的 Category ,来更容易的使用这个类
/**
* Method that can be used in favor of `scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:` in case the target retains the timer instance. Using the aforementioned method would create a retain cycle in this case.
*/
@interface NSTimer (RetainCyclePrevention)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
weakTarget:(id)target
selector:(SEL)selector
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo;
@end
@implementation NSTimer (RetainCyclePrevention)
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)timeInterval
weakTarget:(id)target
selector:(SEL)selector
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo {
return [self scheduledTimerWithTimeInterval:timeInterval
target:[[TMWeakTimerTarget alloc] initWithTarget:target
selector:selector]
selector:@selector(timerDidFire:)
userInfo:userInfo
repeats:yesOrNo];
}
@end