Index: src/OFRunLoop.h ================================================================== --- src/OFRunLoop.h +++ src/OFRunLoop.h @@ -88,11 +88,13 @@ * @brief Adds an OFTimer to the run loop. * * @param timer The timer to add */ - (void)addTimer: (OFTimer*)timer; + +- (void)OF_removeTimer: (OFTimer*)timer; /*! * @brief Starts the run loop. */ - (void)run; @end Index: src/OFRunLoop.m ================================================================== --- src/OFRunLoop.m +++ src/OFRunLoop.m @@ -316,12 +316,32 @@ [timersQueue insertObject: timer]; } @finally { [timersQueueLock unlock]; } + [timer OF_setInRunLoop: self]; + [streamObserver cancel]; } + +- (void)OF_removeTimer: (OFTimer*)timer +{ + [timersQueueLock lock]; + @try { + of_list_object_t *iter; + + for (iter = [timersQueue firstListObject]; iter != NULL; + iter = iter->next) { + if ([iter->object isEqual: timer]) { + [timersQueue removeListObject: iter]; + break; + } + } + } @finally { + [timersQueueLock unlock]; + } +} - (void)streamIsReadyForReading: (OFStream*)stream { OFList *queue = [readQueues objectForKey: stream]; of_list_object_t *listObject; @@ -565,10 +585,12 @@ OF_ORDERED_DESCENDING) { timer = [[listObject->object retain] autorelease]; [timersQueue removeListObject: listObject]; + + [timer OF_setInRunLoop: nil]; } else timer = nil; } @finally { [timersQueueLock unlock]; } Index: src/OFTimer.h ================================================================== --- src/OFTimer.h +++ src/OFTimer.h @@ -17,10 +17,11 @@ #import "OFObject.h" @class OFTimer; @class OFDate; @class OFCondition; +@class OFRunLoop; #ifdef OF_HAVE_BLOCKS typedef void (^of_timer_block_t)(OFTimer*); #endif @@ -38,14 +39,15 @@ #ifdef OF_HAVE_BLOCKS of_timer_block_t block; #endif BOOL isValid, done; OFCondition *condition; + OFRunLoop *inRunLoop; } #ifdef OF_HAVE_PROPERTIES -@property (readonly, retain) OFDate *fireDate; +@property (retain) OFDate *fireDate; #endif /*! * @brief Creates and schedules a new timer with the specified time interval. * @@ -273,10 +275,22 @@ * * @return The next date at which the timer will fire */ - (OFDate*)fireDate; +/*! + * @brief Sets the next date at which the timer will fire. + * + * If the timer is already scheduled in a run loop, it will be rescheduled. + * Note that rescheduling is an expensive operation, though it still might be + * preferrable to reschedule instead of invalidating the timer and creating a + * new one. + * + * @param fireDate The next date at which the timer will fire + */ +- (void)setFireDate: (OFDate*)fireDate; + /*! * @brief Invalidates the timer, preventing it from firing. */ - (void)invalidate; @@ -298,6 +312,8 @@ /*! * @brief Waits until the timer fired. */ - (void)waitUntilDone; + +- (void)OF_setInRunLoop: (OFRunLoop*)inRunLoop; @end Index: src/OFTimer.m ================================================================== --- src/OFTimer.m +++ src/OFTimer.m @@ -14,10 +14,12 @@ * file. */ #include "config.h" +#include + #import "OFTimer.h" #import "OFDate.h" #import "OFRunLoop.h" #import "OFCondition.h" @@ -313,10 +315,16 @@ } #endif - (void)dealloc { + /* + * The run loop references the timer, so it should never be deallocated + * if it is still in a run loop. + */ + assert(inRunLoop == nil); + [fireDate release]; [target release]; [object1 release]; [object2 release]; #ifdef OF_HAVE_BLOCKS @@ -389,10 +397,26 @@ - (OFDate*)fireDate { OF_GETTER(fireDate, YES) } + +- (void)setFireDate: (OFDate*)fireDate_ +{ + [self retain]; + @try { + @synchronized (self) { + [inRunLoop OF_removeTimer: self]; + + OF_SETTER(fireDate, fireDate_, YES, 0) + + [inRunLoop addTimer: self]; + } + } @finally { + [self release]; + } +} - (double)timeInterval { return interval; } @@ -419,6 +443,11 @@ [condition wait]; } @finally { [condition unlock]; } } + +- (void)OF_setInRunLoop: (OFRunLoop*)inRunLoop_ +{ + OF_SETTER(inRunLoop, inRunLoop_, YES, 0) +} @end