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
![](https://img.haomeiwen.com/i322113/10bbfe54ad0dea1f.png)
网友评论