self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
selector:@selector(runTest) userInfo:nil repeats:YES];
此方法会造成循环应用,因为:
- ViewController 有一个强引用引用着定时器
- 定时器会对target产生一个强引用
- 产生了一个循环引用,两个都无法释放了
解决办法1:iOS10提供的Block的形式的定时器
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf runTest];
}];
解决方法2:使用一个中间介来做消息转发
(1)、swift版的方法:
import Foundation
class TimerTarget: NSObject {
weak var target :AnyObject?
convenience init(_ target:AnyObject) {
self.init()
self.target = target
}
override func forwardingTarget(for aSelector: Selector!) -> Any? {
return target
}
deinit {
print("---- deinit ---")
}
}
具体使用
func initTimer() {
timer = Timer(timeInterval: 1.0, target: TimerTarget(self), selector: #selector(timerStarted),
userInfo: nil, repeats: true)
RunLoop.current.add(timer!, forMode: .common)
}
(2)、oc版的方法:
oc版本使用借助NSProxy这个抽象类,相比NSObject,NSProxy更轻量级, 做消息转发效率更高.必须继承实例化其子类才能使用
TimerProxy.h
文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TimerProxy : NSProxy
- (instancetype)initWithTarget:(id)target;
+ (instancetype)proxyWithTarget:(id)target;
@end
NS_ASSUME_NONNULL_END
TimerProxy.m
文件
#import "TimerProxy.h"
@interface TimerProxy ()
@property (nonatomic, weak) id target;
@end
@implementation TimerProxy
- (instancetype)initWithTarget:(id)target {
_target = target;
return self;
}
+ (instancetype)proxyWithTarget:(id)target {
return [[TimerProxy alloc] initWithTarget:target];
}
- (id)forwardingTargetForSelector:(SEL)selector {
return _target;
}
@end
具体使用:
- (void)initTimer {
TimerProxy * proxy = [TimerProxy proxyWithTarget:self];
self.timer = [NSTimer timerWithTimeInterval:1.0 target:proxy
selector:@selector(timerStart) userInfo:nil repeats:YES];//NSRunLoopCommonModes
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
网友评论