避免NSTimer 强引用的两种方法

91 阅读2分钟

NSTimer不准确的问题 cloud.tencent.com/developer/a…

后台会停止的问题。 www.jianshu.com/p/388fc8f12…

gcdtimer 耗电

<1>NSProxy:NSProxy 是一个抽象类,它接收到任何自己没有定义的方法他都会产生一个异常,所以一个实际的子类必须提供一个初始化方法或者创建方法,并且重载forwardInvocation:方法和methodSignatureForSelector:方法来处理自己没有实现的消息。 从类名来看是代理类,专门负责代理对象转发消息的。相比NSObject类来说NSProxy更轻量级,通过NSProxy可以帮助Objective-C间接的实现多重继承的功能。

.h


NS_ASSUME_NONNULL_BEGIN

@interface LGProxy : NSProxy
+ (instancetype)proxyWithTransformObject:(id)object;
@end

NS_ASSUME_NONNULL_END

.m


@interface LGProxy()

@property (nonatomic, weak) id object;

@end

@implementation LGProxy
+ (instancetype)proxyWithTransformObject:(id)object{
    LGProxy *proxy = [LGProxy alloc];
    proxy.object = object;
    return proxy;
}

// sel - imp -
// 消息转发 self.object
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel{
    
    if (self.object) {
    }else{
        NSLog(@"麻烦收集 stack");
    }
    return [self.object methodSignatureForSelector:sel];
}

- (void)forwardInvocation:(NSInvocation *)invocation{
    
    if (self.object) {
        [invocation invokeWithTarget:self.object];
    }else{
        // add imp - 动态创建 - imp
        // imp 常规 -- pop
        // 收集奔溃信息
        NSLog(@"麻烦收集 stack");
    }
    
}
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.proxy = [XZHProxy alloc];
    //作为当前控制器的代理
    self.proxy.obj = self;
    //target为代理
    self.timer = [NSTimer timerWithTimeInterval:1 target:self.proxy selector:@selector(timerEvent) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}

- (void)timerEvent{
    NSLog(@"%zd",self.count++);
}

- (void)dealloc{
    NSLog(@"----dealloc");
    //释放计时器
    [self.timer invalidate];
}

<2>创建一个中间层,让timer强持有它,然后vc能正常的析构,这样定时器就可以关闭,中间层就可以释放了。

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGTimerWapper : NSObject

- (instancetype)lg_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (void)lg_invalidate;

@end

NS_ASSUME_NONNULL_END

@interface LGTimerWapper()
@property (nonatomic, weak) id target;
@property (nonatomic, assign) SEL aSelector;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation LGTimerWapper

- (instancetype)lg_initWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo{
    if (self == [super init]) {
        self.target     = aTarget;
        self.aSelector  = aSelector;
        self.timer      = [NSTimer scheduledTimerWithTimeInterval:ti target:self selector:@selector(fireHome) userInfo:userInfo repeats:yesOrNo];
    }
    return self;
}

- (void)fireHome{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    // 让编译器出栈,恢复状态,继续编译后续的代码!
    if ([self.target respondsToSelector:self.aSelector]) {
        [self.target performSelector:self.aSelector];
    }
#pragma clang diagnostic pop
}

- (void)lg_invalidate{
    [self.timer invalidate];
    self.timer = nil;
}

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

@end

参考连接:www.jianshu.com/p/d45891343…

代码地址:github.com/cherishandj…