RunLoop 应用场景(NSTimer)

2021-05-09  本文已影响0人  qinghan

NSTimer 循环引用

我们首先来下面一段代码

 self.name = @"123";
    _timer = [NSTimer scheduledTimerWithTimeInterval:1. target:self selector:@selector(timerTask) userInfo:nil repeats:YES];
- (void)timerTask
{
    NSLog(@"%@",self.name);
}

很明显上面的代码会发生会发生循环引用self->timer->self,那么如何打破循环呢

使用block

苹果可能知道上面的api会出现问题,所以给我们提供了一个block api,然后我们通过__weak来打破循环

     __weak typeof(self) weakSelf = self;
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%@",weakSelf.name);
    }];
手动打破循环

就是在我们退出页面后,手动把timer赋值为空,当然这种方式有局限性

    - (void)didMoveToParentViewController:(UIViewController *)parent
{
    if (!parent) {
        [self.timer invalidate];
        self.timer = nil;
    }
}
通过其他Target来实现
_targetNew = [NSObject new];
class_addMethod([NSObject class], @selector(timerTask), class_getMethodImplementation([self class], @selector(timerTask)), "v@:");
 _timer = [NSTimer scheduledTimerWithTimeInterval:1. target:_targetNew selector:@selector(timerTask) userInfo:nil repeats:YES];
- (void)timerTask
{
   // NSLog(@"%@",self.name);
    NSLog(@"timerTask");
}

这个方式也有弊端,如果在timerTask方法里面要应用self相关的属性,需要在_targetNew实例里面也要动态添加属性,否则会崩溃。

通过NSProxy来实现

首先继承NSProxy,通过NSProxy来实现消息转发。

@interface QHProxy : NSProxy

@property (nonatomic,weak)id fowardTarget;

@end
#import "QHProxy.h"

@implementation QHProxy

//消息转发
- (void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation invokeWithTarget:self.fowardTarget];
}


//方法签名
- (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    return [self.fowardTarget methodSignatureForSelector:sel];
}

@end

具体实现

 _proxy = [QHProxy alloc];
 _proxy.fowardTarget = self;
    
 _timer = [NSTimer scheduledTimerWithTimeInterval:1. target:_proxy selector:@selector(timerTask) userInfo:nil repeats:YES];
- (void)timerTask
{
    NSLog(@"%@",self.name);
    NSLog(@"timerTask");
}
应用场景
 dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"1");
        //方法1
        [self performSelector:@selector(testActions) withObject:nil];
        
        //方法2
       // [self performSelector:@selector(testActions) withObject:nil afterDelay:0];
        //方法3
       // [self performSelector:@selector(testActions) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
        //方法4
        // [self performSelector:@selector(testActions) onThread:[NSThread currentThread] withObject:nil waitUntilDone:NO];
        NSLog(@"3");
    });
- (void)testActions
{
    NSLog(@"2");
}

同样
[self performSelector:@selector(testActions) onThread:[NSThread currentThread] withObject:nil waitUntilDone:YES];
这个方法的wait参数,如果是YES,会立即返回,如果为NO,则也会加到当前线程runloop

解释1.png
上一篇下一篇

猜你喜欢

热点阅读