美文网首页
RunLoop 应用场景(NSTimer)

RunLoop 应用场景(NSTimer)

作者: qinghan | 来源:发表于2021-05-09 11:04 被阅读0次

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");
}
  • 方法1打印顺序123
  • 方法2打印13
  • 方法3打印123
  • 方法4打印13
    第一种不难理解,当是第二种为什么不答应2,原因很简单
    方法解释.png
    这个方法会加到当前线程的runloop,但是子线程的runloop没有开启,需要手动开启才能运行

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

解释1.png

相关文章

  • iOS RunLoop

    RunLoop 的应用场景: RunLoop在系统中应用 1.自动释放池。 2.NSTimer 3.Perform...

  • RunLoop 应用场景(NSTimer)

    NSTimer 循环引用 我们首先来下面一段代码 很明显上面的代码会发生会发生循环引用self->timer->s...

  • RunLoop应用场景

    场景一:NSTimer RunLoop有多种model,每种model下面有多个source,RunLoop的运行...

  • RunLoop应用

    在我的另一篇文章RunLoop简单介绍了关于runLoop基础知识和NSTimer时runloop简单应用, 下面...

  • runLoop的应用

    runloop的应用:1.NSTimer2.ImageView显示3.PerformSelector4.常驻线程 ...

  • iOS RunLoop

    RunLoop 应用:NSTimer、 PerformSelector、常驻线程iOS 中有两套API访问 Fo...

  • NSTimer、CADisplayLink、GCD定时器

    一、NSTimer NSTimer和CADisplayLink依赖于RunLoop,如果RunLoop的任务过于繁...

  • Objective - C 内存管理(二)GCD定时器

    GCD定时器的使用场景 NSTimer依赖于RunLoop,如果RunLoop的任务过于繁重,可能会导致NSTim...

  • RunLoop -- 相关问题的总结

    1、RunLoop在实际场景的应用 RunLoop -- 在实际开发中的应用 2、RunLoop内部实现逻辑 Ru...

  • GCD定时器的封装

    NSTimer 依赖于 RunLoop,如果 RunLoop 的任务过于繁重,可能会导致 NSTimer 不准时。...

网友评论

      本文标题:RunLoop 应用场景(NSTimer)

      本文链接:https://www.haomeiwen.com/subject/iqaudltx.html