美文网首页
iOS-NSTimer-循环引用问题

iOS-NSTimer-循环引用问题

作者: 御雪飞斐 | 来源:发表于2019-03-25 15:46 被阅读0次

    在使用NSTimer的时候,NSTimer会生成指向其使用者的引用,而其使用者如果也引用了NSTimer,那么就会生成保留环。

    通常使用:

    #import <Foundation/Foundation.h>
    
    @interface EOCClass : NSObject
    - (void)startPolling;
    - (void)stopPolling;
    @end
    
    
    @implementation EOCClass {
         NSTimer *_pollTimer;
    }
    
    
    - (id)init {
         return [super init];
    }
    
    
    - (void)dealloc {
        [_pollTimer invalidate];
    }
    
    
    - (void)stopPolling {
    
        [_pollTimer invalidate];
        _pollTimer = nil;
    }
    
    
    - (void)startPolling {
       _pollTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
                                                     target:self
                                                   selector:@selector(p_doPoll)
                                                   userInfo:nil
                                                    repeats:YES];
    }
    
    - (void)p_doPoll {
        // Poll the resource
    }
    
    @end
    
    注:在EOCClass和_pollTimer之间形成了保留环,如果不主动调用stopPolling方法就无法打破这个保留环。像这种通过主动调用方法来打破保留环的设计显然是不好的。
    

    通过给NSTimer增加一个分类,解决循环引用问题:

    #import <Foundation/Foundation.h>
    
    @interface NSTimer (EOCBlocksSupport)
    
    + (NSTimer*)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                             block:(void(^)())block
                                             repeats:(BOOL)repeats;
    @end
    
    
    
    @implementation NSTimer (EOCBlocksSupport)
    
    + (NSTimer*)eoc_scheduledTimerWithTimeInterval:(NSTimeInterval)interval
                                             block:(void(^)())block
                                            repeats:(BOOL)repeats
    {
                 return [self scheduledTimerWithTimeInterval:interval
                                                      target:self
                                                    selector:@selector(eoc_blockInvoke:)
                                                    userInfo:[block copy]
                                                     repeats:repeats];
    
    }
    
    
    + (void)eoc_blockInvoke:(NSTimer*)timer {
         void (^block)() = timer.userInfo;
             if (block) {
                 block();
            }
    }
    @end
    

    看下使用:

    - (void)startPolling {
    
             __weak EOCClass *weakSelf = self;    
             _pollTimer = [NSTimer eoc_scheduledTimerWithTimeInterval:5.0 block:^{
    
                   EOCClass *strongSelf = weakSelf;
                   [strongSelf p_doPoll];
              }
    
                                                              repeats:YES];
    }
    

    在这里,创建了一个self的弱引用,然后让块捕获了这个self变量,让其在执行期间存活。
    一旦外界指向EOC类的最后一个引用消失,该类就会被释放,被释放的同时,也会向NSTimer发送invalidate消息(因为在该类的dealloc方法中向NSTimer发送了invalidate消息)。
    而且,即使在dealloc方法里没有发送invalidate消息,因为块里的weakSelf会变成nil,所以NSTimer同样会失效。

    相关文章

      网友评论

          本文标题:iOS-NSTimer-循环引用问题

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