iphone - Repeating NSTimer, weak reference, owning reference or iVar? -


i thought put out here separate question previous retaining-repeating-nstimer-for-later-access discussion has moved forward making new question clearer yet edit:

the scenario object creates repeating nstimer, lets in viewdidload, once created nstimer needs stay around can accessed other methods.

nstimer *ti = [nstimer scheduledtimerwithtimeinterval:1                                                 target:self                                               selector:@selector(updatedisplay:)                                               userinfo:nil                                                repeats:yes]; 

i understand when created runloop takes ownership of nstimer , stops, removes , releases nstimer when [ti invalidate]; called.

by virtue of fact need access nstimer in more 1 method need way hold reference future use, revised question is:

// (1) should nstimer held using owning reference (i.e.) @property(nonatomic, retain) nstimer *walktimer; [self setwalktimer: ti]; ... ... // cancel method [[self walktimer] invalidate; [self setwalktimer:nil]; ... ... // dealloc method [walktimer release]; [super dealloc]; 

.

// (2) should nstimer held using weak reference (i.e.) @property(nonatomic, assign) nstimer *walktimer; [self setwalktimer: ti]; ... ... // cancel method [[self walktimer] invalidate]; [self setwalktimer:nil]; ... ... // dealloc method [super dealloc]; 

.

// (3) use ivar , rely on runloop holding (i.e. retaining) timer nstimer *walktimer; nstimer *walktimer = [nstimer scheduledtimerwithtimeinterval:1                                                        target:self                                                      selector:@selector(updatedisplay:)                                                      userinfo:nil                                                       repeats:yes]; ... ... // cancel method [walktimer invalidate]; walktimer = nil; 

.

// (4) not listed above ... 

i happy (1) (2) (3) or (4) lot of discussion regarding best has been written on other thread. there seem lot of conflicting answers hope more specific question focus on might best practice in situation.


edit:

as side note in apple nstimer class reference 4 out of 5 of sample code projects use nstimers assigned** retained property. here example of class reference examples show:

@property (nonatomic, retain) nstimer *updatetimer; updatetimer = [nstimer scheduledtimerwithtimeinterval:.01 target:self selector:@selector(updatecurrenttime) userinfo:p repeats:yes]; ... ... // cancel [updatetimer invalidate]; updatetimer = nil; ... ... // dealloc method [super dealloc]; [updatetimer release]; 

** should noted in examples apple assigning ivar directly , not using property setter.

edit

after giving more thought , finding important flaw in reasoning, i've come different conclusion:

it doesn't matter much, whether hold owning or non-owning reference timer need invalidate. matter of taste.

the deal breaker is, target of timer is:

if object creates timer target, managing object's lifetime becomes more fragile: cannot retain/release managed, instead need ensure client holds last reference object makes invalidate timer before disposes of it.

let me illustrate situation couple of sort-of-object-graphs:

  1. you start in state setup timer , set target:
    setup of timer: yourobject owned someclientobject. in parallel exists current run-loop array of scheduledtimers. setuptimer method called upon yourobject http://a.yfrog.com/img616/8947/fqlc.png
  2. the result following initial state:
    initial state: in addition former state yourobject has reference (owned or not) worktimer, in turn owns yourobject. furthermore, worktimer owned run-loops scheduledtimers array. http://a.yfrog.com/img640/3444/acq.png
  3. so you'll use object, when you're done , release it, you'll end with
    simple release leak: after someclientobject disposes of yourobject through simple release, yourobject disassociated object-graph kept alive worktimer. worktimer , yourobject leaked! http://a.yfrog.com/img610/7223/jyyj.png
    leak object (and timer) because runloop keeps timer alive, — in turn — keeps owning reference object.

this can avoided if yourobject ever owned one single instance @ time, when disposed of:
proper disposal through cancellation: before disposing of yourobject through release, someclientobject calls canceltimer method on yourobject. within method, yourobject invalidates worktimer , (if owned worktimer) disposes of worktimer through release http://a.yfrog.com/img614/7428/p8af.png

but now, how resolve following situation?
multiple owners: setup in initial state, multiple independent clientobjects hold references yourobject http://a.yfrog.com/img619/3908/wqe.png

there no easy answer, aware of! (not latter has much, but...)

so advice is...

  1. don't make timer property/don't provide accessors it! instead, keep private (with modern runtime think go far define ivar in class extension) , deal 1 single object. (you may retain it, if feel more comfortable doing so, there absolutely no need it.)
    • caveat: if absolutely need access timer object, make property retain timer (as way avoid crashes caused clients directly invalidated timer accessed) and provide own setter. rescheduling timer — in opinion — not reason break encapsulation here: provide mutator if need that.
  2. set timer target other self. (there plenty of ways doing so. maybe through writing generic timertarget class or — if can use — through mazeroingweakreference?)

i apologize being moron in first discussion , want thank daniel dickison , rob napier patience.

so here way going handle timers on:

// nstimer+d12weaktimertarget.h: #import <foundation/nstimer.h> @interface nstimer (d12weaktimertarget) +(nstimer *)d12scheduledtimerwithtimeinterval:(nstimeinterval)ti weaktarget:(id)target selector:(sel)selector userinfo:(id)userinfo repeats:(bool)shouldrepeat logsdeallocation:(bool)shouldlogdealloc; @end  // nstimer+d12weaktimertarget.m: #import "nstimer+d12weaktimertarget.h" @interface d12weaktimertarget : nsobject {     __weak id weaktarget;     sel selector;     // logging purposes:     bool logging;     nsstring *targetdescription; } -(id)initwithtarget:(id)target selector:(sel)aselector shouldlog:(bool)shouldlogdealloc; -(void)passthroughfiredtimer:(nstimer *)atimer; -(void)dumbcallbacktimer:(nstimer *)atimer; @end  @implementation d12weaktimertarget -(id)initwithtarget:(id)target selector:(sel)aselector shouldlog:(bool)shouldlogdealloc {     self = [super init];     if ( !self )         return nil;      logging = shouldlogdealloc;      if (logging)         targetdescription = [[target description] copy];      weaktarget = target;     selector = aselector;      return self; }  -(void)dealloc {     if (logging)         nslog(@"-[%@ dealloc]! (target %@)", self, targetdescription);      [targetdescription release];     [super dealloc]; }  -(void)passthroughfiredtimer:(nstimer *)atimer; {     [weaktarget performselector:selector withobject:atimer]; }  -(void)dumbcallbacktimer:(nstimer *)atimer; {     [weaktarget performselector:selector]; } @end  @implementation nstimer (d12weaktimertarget) +(nstimer *)d12scheduledtimerwithtimeinterval:(nstimeinterval)ti weaktarget:(id)target selector:(sel)selector userinfo:(id)userinfo repeats:(bool)shouldrepeat logsdeallocation:(bool)shouldlogdealloc {     sel actualselector = @selector(dumbcallbacktimer:);     if ( 2 != [[target methodsignatureforselector:aselector] numberofarguments] )         actualselector = @selector(passthroughfiredtimer:);      d12weaktimertarget *indirector = [[d12weaktimertarget alloc] initwithtarget:target selector:selector shouldlog:shouldlogdealloc];      nstimer *thetimer = [nstimer scheduledtimerwithtimeinterval:ti target:indirector selector:actualselector userinfo:userinfo repeats:shouldrepeat];     [indirector release];      return thetimer; } @end 

original (for full disclosure):

you know opinion your other post:

there little reason owning reference of scheduled timer (and bbum seems agree).

that said, options 2 , 3 same. (there additional messaging involved in [self setwalktimer:nil] on walktimer = nil i'm not sure if compiler won't optimize away , access ivar directly, well...)


Comments

Popular posts from this blog

python - Scipy curvefit RuntimeError:Optimal parameters not found: Number of calls to function has reached maxfev = 1000 -

c# - How to add a new treeview at the selected node? -

java - netbeans "Please wait - classpath scanning in progress..." -