Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -1612,10 +1612,11 @@ [state->_timersQueueMutex unlock]; } #endif if (timer.valid) { + [timer of_reschedule]; [timer fire]; return; } } Index: src/OFTimer+Private.h ================================================================== --- src/OFTimer+Private.h +++ src/OFTimer+Private.h @@ -19,8 +19,9 @@ OF_DIRECT_MEMBERS @interface OFTimer () - (void)of_setInRunLoop: (nullable OFRunLoop *)runLoop mode: (nullable OFRunLoopMode)mode; +- (void)of_reschedule; @end OF_ASSUME_NONNULL_END Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -460,12 +460,13 @@ * @return The result of the comparison */ - (OFComparisonResult)compare: (OFTimer *)timer; /** - * @brief Fires the timer, meaning it will execute the specified selector on the - * target. + * @brief Fires the timer without changing its regular schedule. + * + * A non-repeating timer will be invalidated after firing. */ - (void)fire; /** * @brief Invalidates the timer, preventing it from firing. Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -521,90 +521,93 @@ [oldInRunLoop release]; _inRunLoopMode = [mode copy]; [oldInRunLoopMode release]; } + +- (void)of_reschedule +{ + long long missedIntervals; + OFTimeInterval newFireDate; + OFRunLoop *runLoop; + + if (!_repeats || !_valid) + return; + + missedIntervals = -_fireDate.timeIntervalSinceNow / _interval; + + /* In case the clock was changed backwards */ + if (missedIntervals < 0) + missedIntervals = 0; + + newFireDate = _fireDate.timeIntervalSince1970 + + (missedIntervals + 1) * _interval; + + [_fireDate release]; + _fireDate = nil; + _fireDate = [[OFDate alloc] + initWithTimeIntervalSince1970: newFireDate]; + + runLoop = [OFRunLoop currentRunLoop]; + [runLoop addTimer: self forMode: runLoop.currentMode]; +} - (void)fire { - void *pool = objc_autoreleasePoolPush(); - id target = [[_target retain] autorelease]; - id object1 = [[_object1 retain] autorelease]; - id object2 = [[_object2 retain] autorelease]; - id object3 = [[_object3 retain] autorelease]; - id object4 = [[_object4 retain] autorelease]; - OFEnsure(_arguments <= 4); - if (_repeats && _valid) { - int64_t missedIntervals = - -_fireDate.timeIntervalSinceNow / _interval; - OFTimeInterval newFireDate; - OFRunLoop *runLoop; - - /* In case the clock was changed backwards */ - if (missedIntervals < 0) - missedIntervals = 0; - - newFireDate = _fireDate.timeIntervalSince1970 + - (missedIntervals + 1) * _interval; - - [_fireDate release]; - _fireDate = [[OFDate alloc] - initWithTimeIntervalSince1970: newFireDate]; - - runLoop = [OFRunLoop currentRunLoop]; - [runLoop addTimer: self forMode: runLoop.currentMode]; - } else - [self invalidate]; + if (!_valid) + return; #ifdef OF_HAVE_BLOCKS if (_block != NULL) _block(self); else { #endif switch (_arguments) { case 0: - [target performSelector: _selector]; + [_target performSelector: _selector]; break; case 1: - [target performSelector: _selector withObject: object1]; + [_target performSelector: _selector + withObject: _object1]; break; case 2: - [target performSelector: _selector - withObject: object1 - withObject: object2]; + [_target performSelector: _selector + withObject: _object1 + withObject: _object2]; break; case 3: - [target performSelector: _selector - withObject: object1 - withObject: object2 - withObject: object3]; + [_target performSelector: _selector + withObject: _object1 + withObject: _object2 + withObject: _object3]; break; case 4: - [target performSelector: _selector - withObject: object1 - withObject: object2 - withObject: object3 - withObject: object4]; + [_target performSelector: _selector + withObject: _object1 + withObject: _object2 + withObject: _object3 + withObject: _object4]; break; } #ifdef OF_HAVE_BLOCKS } #endif + if (!_repeats) + [self invalidate]; + #ifdef OF_HAVE_THREADS [_condition lock]; @try { _done = true; [_condition signal]; } @finally { [_condition unlock]; } #endif - - objc_autoreleasePoolPop(pool); } - (OFDate *)fireDate { return _fireDate; @@ -633,10 +636,13 @@ - (void)invalidate { _valid = false; +#ifdef OF_HAVE_BLOCKS + [_block release]; +#endif [_target release]; [_object1 release]; [_object2 release]; [_object3 release]; [_object4 release];