NSTimer as a self-tuning ivar

I came across an awkward situation where I would like to have a class with an NSTimer instance variable that repeatedly calls the class method while the class is alive. To illustrate, this might look like this:

// .h
@interface MyClock : NSObject {
    NSTimer* _myTimer;
}
- (void)timerTick;
@end

-

// .m
@implementation MyClock

- (id)init {
    self = [super init];
    if (self) {
        _myTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(timerTick) userInfo:nil repeats:NO] retain];
    }
    return self;
}

- (void)dealloc {
    [_myTimer invalidate];
    [_myTImer release];
    [super dealloc];
}

- (void)timerTick {
    // Do something fantastic.
}

@end

What I want. I do not want to expose an interface in my class to start and stop the internal timer, I just want it to work during the existence of the class. It seems simple enough.

, NSTimer . , , , , . . NSTimer, , - ivar, , ivar .

- MyClock, , . , , , , , , . -- , ... ? .

, , . NSTimer, NSTimer, . , .

+5
8

, , - . , , , , nil, .

@interface Foo : NSObject
{
    __weak NSTimer *_timer;
}
@end

@implementation Foo
- (void) foo
{
    _timer = [NSTimer ....self....];
}

- (void) reset
{
    [_timer invalidate], _timer = nil;
}

- (void) dealloc
{
    // since the timer is retaining self, no point in invalidating here because
    // that just can't happen
    [super dealloc];
}
@end

- -reset self . , self timer. - self , self. , self ( self, ), invalidate dealloc.

, Mac OS X, GC .

+4

, NoodleSoft NSTimer, , ( ). ( , , , )..

+2

:

THInWeakTimer

https://github.com/th-in-gs/THIn

.

:

ivar:

THInWeakTimer *_keepaliveTimer;

init:

    __weak FunderwearConnection* wself = self;
    _keepaliveTimer = [[THInWeakTimer alloc] initWithDelay:kIntervalPeriod do:^{
        [wself doSomething];
    }];
+2

, , . -, , , , , .

, NSTimer Core Foundation: CFRunLoopTimerRef. Core Foundation .

@implementation Target

- (void)timerFired:(NSTimer*)timer {
   ...
}

static void timerCallback(CFRunLoopTimerRef timer, void *info) {
    Target* target = (Target*) info;

    [target timerFired:(NSTimer*) timer];
}

- (void)startTimer {
    //timer not retaining its context

    CFRunLoopTimerContext timerContext;
    timerContext.version = 0;
    timerContext.info = self;
    timerContext.retain = NULL;
    timerContext.release = NULL;
    timerContext.copyDescription = NULL;

    //this is a repeating timer
    CFRunLoopTimerRef timer = CFRunLoopTimerCreate(kCFAllocatorDefault,
                                                   CFAbsoluteTimeGetCurrent() + FIRE_INTERVAL,
                                                   FIRE_INTERVAL,
                                                   0,
                                                   0,
                                                   timerCallback,
                                                   &timerContext);

    //schedule the timer
    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);

    self.timer = (NSTimer*) timer;

    CFRelease(timer);
}
@end

MRC, ARC .

+1

( iOS, UIView) removeFromSuperview, .superview , .

, - , , - ?

0

ivar, :

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerTick) userInfo:nil repeats:YES];    

.

: performSelector.

0

. , - , , .

, keepCount .

- (void)setMyTimer:(NSTimer *)aNewTimer { // timer retains target/object (self)
    if(aNewTimer != myTimer) {   


    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        // since myTimer was retaining its target (self) and aNewTimer is not retaining self (aNewTimer is nil) and will not retain self you – should retain self
    if(aNewTimer == nil && myTimer != nil) {
        [self retain];
    }
        // since old timer was not retaining self since myTimer is nil and aNewTimer is retaining self – you should release
    else if(aNewTimer != nil && myTimer == nil) {
        [self release]; 
    }

        [myTimer invalidate];
        [myTimer release];
        myTimer = [aNewTimer retain];

    [pool drain], pool = nil;

    }
}

, , , .

- (void)timerDidFire:(NSTimer *)aTimer { 
    if(aTimer == self.myTimer) {
        self.myTimer = nil;
    }
}

dealloc self.myTimer = nil

0

-, self, .. .

0

All Articles