Re: Circular references caused by scheduled NSTimers?
Re: Circular references caused by scheduled NSTimers?
- Subject: Re: Circular references caused by scheduled NSTimers?
- From: Oleg Krupnov <email@hidden>
- Date: Fri, 19 Apr 2013 11:07:25 +0300
Thanks for your answers!
Now I'm thinking that I'd rather create a helper category on NSTimer
with a method that will schedule a timer but under the hood also
create the helper object. In this way, the current code of my project
will almost not change (only change the scheduling method). The helper
class will be private. The helper will not be retained by anyone
except the run loop and will be dealloced immediately after the timer
is invalidated
@interface TimerHelper
@property (nonatomic, assign) id target;
@property (nonatomic, assign) SEL action;
- (void)timerDidFire;
@end
@implementation TimerHelper
- (void)timerDidFire
{
[_target performSelector:_action withObject:nil];
}
@end
@implementation NSTimer (Helper)
+ (NSTimer*)scheduleTimerWithInterval:(NSTimeInterval)interval
target:(id)target action:(SEL)action
{
TimerHelper* helper = [[[TimerHelper alloc] init] autorelease];
helper.target = target;
helper.action = action;
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:interval
target:helper selector:@selector(timerDidFire) userInfo:nil
repeats:YES];
return timer;
}
@end
@implementation Controller
{
NSTimer* _timer;
}
- (void)someMethod
{
_timer = [[NSTimer scheduleTimerWithInterval:interval target:self
action:@selector(someTimerDidFire)] retain];
}
- (void)dealloc
{
[_timer invalidate];
[_timer release];
[super dealloc];
}
@end
I think this is a more elegant solution than public helper. Any caveats?
On Fri, Apr 19, 2013 at 9:53 AM, Graham Cox <email@hidden> wrote:
>
> On 19/04/2013, at 4:35 PM, Greg Parker <email@hidden> wrote:
>
>> Another solution is to introduce a weak reference between the timer and your controller. Create a helper class that holds a weak reference to your Controller object.
>
>
> Since Greg and I have offered the same solution, here's an implementation of it you could use:
>
> Usage would be for your controller to alloc/init the helper/proxy (or use the convenience method and retain it) and then in its -dealloc method call -invalidate followed by -release.
>
> // .h file:
>
>
> #import <Foundation/Foundation.h>
>
>
>
> @interface GCTimerTarget : NSObject
> {
> @private
> NSTimer* mTimerRef;
> id mTrueTargetRef;
> SEL mSelector;
> }
>
> @property (nonatomic, assign) NSTimer* timer;
> @property (nonatomic, assign) id trueTarget;
> @property (nonatomic, assign) SEL selector;
>
> + (GCTimerTarget*) scheduledTimerWithInterval:(NSTimeInterval) t target:(id) target selector:(SEL) selector repeats:(BOOL) repeats;
>
> - (id) initForTarget:(id) trueTarget selector:(SEL) selector;
> - (void) invalidate;
>
> @end
>
>
> /// .m file:
>
> #import "GCTimerTarget.h"
>
>
>
> @interface GCTimerTarget ()
>
> - (void) timerCallback:(NSTimer*) timer;
>
> @end
>
>
> #pragma mark -
>
>
> @implementation GCTimerTarget
>
> @synthesize timer = mTimerRef;
> @synthesize trueTarget = mTrueTargetRef;
> @synthesize selector = mSelector;
>
>
>
> + (GCTimerTarget*) scheduledTimerWithInterval:(NSTimeInterval) t target:(id) target selector:(SEL) selector repeats:(BOOL) repeats
> {
> // convenience method makes the proxy and adds a scheduled timer to it. This can be used instead of the equivalent NSTimer class method
>
> GCTimerTarget* tt = [[[self alloc] initForTarget:target selector:selector] autorelease];
> tt.timer = [NSTimer scheduledTimerWithTimeInterval:t target:tt selector:@selector(timerCallback:) userInfo:nil repeats:repeats];
>
> return tt;
> }
>
>
>
> - (id) initForTarget:(id) trueTarget selector:(SEL) selector
> {
> self = [super init];
> if( self )
> {
> mTrueTargetRef = trueTarget;
> mSelector = selector;
> }
>
> return self;
> }
>
>
> - (void) invalidate
> {
> self.trueTarget = nil;
> [self.timer invalidate];
> self.timer = nil;
>
> // could call [self autorelease] here to make the proxy a one-line teardown, but it's probably safer to leave it as is
> // and rely on a deliberate -release as usual.
> }
>
>
> - (void) timerCallback:(NSTimer*) timer
> {
> if([self.trueTarget respondsToSelector:self.selector])
> [self.trueTarget performSelector:self.selector withObject:timer];
> }
>
>
> @end
>
>
>
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden