解决NSTimer自动释放的问题

场景: 使用NSTimer会产生循环引用, 所以, 当对象应该被销毁的时候, 需要首先手动移除NSTimer, 这样, 该对象才对被销毁. 手动设置timer = nil.
timer之所以不能自动像其他对象跟随对象释放而释放

解决方案: 不让定时器强引用对象.

问题出在这里, 把target设置成self, 出现了循环引用. 如果target不设置成self, 就不会出现循环引用了.

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTest) userInfo:nil repeats:YES];

创建另外一个对象作为定时间消息的接受者, 但是不实现@selector(timerTest), 然后通过消息转发, 再发消息转发到当前对象中执行.

@interface ProxyObj : NSObject
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
@implementation ProxyObj

+ (instancetype)proxyWithTarget:(id)target
{
    MJProxyObj *proxy = [[MJProxyObj alloc] init];
    proxy.target = target;
    return proxy;
}

- (id)forwardingTargetForSelector:(SEL)aSelector
{
    return self.target;
}
@end

- (id)forwardingTargetForSelector:(SEL)aSelector 因为ProxyObj最为定时器消息的接受者, 但是这个接受者并未实现定时器需要执行的方法, 所以会执行消息转发, 把这个消息转发到能够处理该消息的对象里, 很明显, 能够处理消息的就是ProxyObj.target

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[ProxyObj proxyWithTarget:self] selector:@selector(timerTest) userInfo:nil repeats:YES];
}

- (void)timerTest
{
    NSLog(@"%s", __func__);
}

- (void)dealloc
{
    NSLog(@"%s", __func__);
    [self.timer invalidate];
}

@end

这样就可以办到timer不引用当前对象, 不会造成循环引用. 也不用担心timer何时释放了.

优化方法查找流程

继承自NSObject的进行消息转发会先从方法缓存列表中找, 找不到再找当前类对象的方法列表中找, 找不到, 再依次往父类中找, 最终找到NSObject的类对象,
依然找不到, 然后抛出动态方法解析, 动态方法解析没有实现, 再抛出消息转发, 此时才会真正去调用到定时器的方法

按照目前的流程, 必定是需要消息转发的, 但是还是先进行一番的方法查找, 最后才进行转发, 但是我们已经很清楚的知道, 根本不需要进行查找, 直接进行转发即可.
NSProxy: 专门做消息转发的, 只要调用到NSProxy里面的方法, 就会立即执行转发

@interface Proxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@property (weak, nonatomic) id target;
@end
@implementation Proxy

+ (instancetype)proxyWithTarget:(id)target
{
    // NSProxy对象不需要调用init,因为它本来就没有init方法
    MJProxy *proxy = [MJProxy alloc];
    proxy.target = target;
    return proxy;
}

// NSProxy 是专门做消息转发的, 只要调用到NSProxy里面的方法, 就会立即执行下面的函数
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.target methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.target];
}
@end

你可能感兴趣的:(解决NSTimer自动释放的问题)