当前位置:网站首页>Object-C programming tips timer "suggestions collection"

Object-C programming tips timer "suggestions collection"

2022-07-07 20:44:00 Full stack programmer webmaster

Hello everyone , I meet you again , I'm the king of the whole stack .

object-c Timer

object-c The timer will take the initiative retain Current user , Suppose you don't pay attention to calling invalidate, It's very easy Cause a circular reference and cause a memory leak . The following ideas provide a set of feasible solutions .

give an example :

Often in viewController There may be a need to refresh the interface on your own initiative . After data acquisition fails . every other 10 Take the initiative to refresh and get data again in seconds , At this time NSTimer Is a very convenient thing . In general, create a NSTimer Of repeat object , Then realize the corresponding timerFireMethod Method . When the user actively clicks back button When , This interface should be released . But because NSTimer retain The current viewController, Cause interface memory leak . You might say in dealloc Call in invalidate, But it must be clear dealloc You won't call , Of course viewDidDisappear Also won't be called .

I saw it some time ago effective object-c, Learned a very good idea , Now share it .

to NSTimer Add a category , Use block Way of transmission timerFireMethod. The code is as follows :

@implementation NSTimer(LPBLocks)

+(NSTimer*) lpScheduleTimerWithTimerInternal:(NSTimeInterval)interval
                                       block:(void(^)())block
                                     repeats:(BOOL)repeats
{
    return [self scheduledTimerWithTimeInterval:interval target:self selector:@selector(lpTimerBlockInvoke:) userInfo:[block copy] repeats:repeats];
}
+(void)lpTimerBlockInvoke:(NSTimer*)timer
{
    void(^block)() = timer.userInfo;

    if(block){
        block();
    }
}
@end

This scheduledTimer The method will also retain target, But because this is a class method . It retains class objects , So there will be no problem .

It passes in the to run block, And then in the callback function through userInfo obtain block, And run .

improvement :

This is already a very big improvement . We can safely pass in the code block Code . Just think carefully . Suppose that block Introduced in viewController Members of , also timer It also exists as a member variable in viewController in .

For example, the following code :

@interface LPNextViewController ()
{
    NSTimer*  refreshTimer;
}

such viewController and refreshTimer Fell into the logical circle of circular reference again . Of course, it can be in block Use in weak_self Avoid circular references , But writing code is always a little difficult . And it also needs to be explicitly done by external users .

So very easy The thought of . It should be encapsulated in a special LPTimer Class . It is responsible for holding NSTimer. At the same time NSTimer Of block Use LPTimer Of weak Version number .

@interface LPTimer ()
{
    NSTimer* _pollTimer;

    //timer selector
    __weak id _weak_target;
    SEL _selector;
    id  _userInfo;
}
@end
-(void)scheduleTimerWithTimerInternal:(NSTimeInterval)interval
                                 target:(id)target
                               selector:(SEL)aSelector
                               userInfo:(id)userInfo
                                repeats:(BOOL)repeats
{
    __weak id weak_self = self;

    _weak_target = target;
    _selector = aSelector;
    _userInfo = userInfo;

    // Borrow the first version number block thought 
    // The second layer of indirection is used , call _weak_target Of aSelector Method .
    // This can make stopTimer Put it in the box . External management is not necessary timer Of stop.
    _pollTimer = [NSTimer lpScheduleTimerWithTimerInternal:1 block:^{
        [weak_self doTimer];
    } repeats:repeats];
}

The above code LPTimer hold NSTimer object . and NSTimer Running block It uses weak_self.

It's in timer When triggered, call its own doTimer Method . stay doTimer Is responsible for passing methods to external users .

-(void)doTimer
{
    if ([_weak_target respondsToSelector:_selector]) {
        [_weak_target performSelector:_selector withObject:self];
    }
    else{
        DLog(@"WARNNING: unknown selector");
    }
}

_weak_target Is an external user . External users can put LPTimer Just regard it as an ordinary object , There's nothing wrong with holding it . LPTimer Keep a weak reference to the external user . When the time comes timer When triggered , It will be transferred to NStimer Of block in . Then pass it on to LPTimer Of doTimer in . And then call to _weak_target Of selector in .

Attention must be paid to release NStimer object , stay LPTimer Call when releasing NSTimer Of invalidate Method .

-(void)stopTimer
{
    DLog(@"");
    [_pollTimer invalidate];
}
-(void)dealloc
{
    [self stopTimer];
    DLog(@"");
}

in fact . Users are using LPTimer class , Then let LPTimer Performance and NSTimer Your behavior is exactly the same , Using the combined adapter mode can be easily done .

summary :

The main idea is NSTimer Meeting retain An object , Now let it retain Class object .

When the time comes to trigger , from NSTimer Class object triggers to Block in . Then trigger to the external LPTimer Ordinary objects .

We can deal with ordinary objects freely . Use weak_target send LPTimer Weak references to external users , Disconnect external users from LPTimer The associated .

Use weak_self To break off LPTimer And NStimer Circular correlation of . I think it's a good idea , Welcome to discuss if necessary .

Publisher : Full stack programmer stack length , Reprint please indicate the source :https://javaforall.cn/116393.html Link to the original text :https://javaforall.cn

原网站

版权声明
本文为[Full stack programmer webmaster]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207072002205416.html