Re: Logical and - second operator evaluated?
Re: Logical and - second operator evaluated?
- Subject: Re: Logical and - second operator evaluated?
- From: Peter N Lewis <email@hidden>
- Date: Tue, 3 Mar 2009 16:00:42 +0900
At 21:06 +0100 1/3/09, Martijn van Exel wrote:
I can't seem to get away with
if(timer!=nil && [timer isValid]) [timer invalidate];
Aside from whatever is actually causing your problems (which is
nothing to do with the short circuited and in this line, these three
lines are all functionally equivalent:
if(timer!=nil && [timer isValid]) [timer invalidate];
if([timer isValid]) [timer invalidate];
[timer invalidate];
and so you should just use the third.
In the second case, if timer is nil, then [tiner isValid] will not
call any method and return 0.
In the third case, if timer is nil, nothing will be called, and if
timer is not nil and already invalid, then calling invalidate on it
will have no effect.
There are two gotchas though:
1. You must initialize the timer variable. If it is an ivar, then
Objective C will initialize it to nil for you. Alternatively, you
should initialize it to nil when it is created (ie NSTimer* timer =
nil) or initialize it to a newlt created NSTimer& using alloc
initWithFireDate or one of the various class constructors like
scheduledTimerWithTimeInterval.
2. You should/must initialize the tiemr to nil after invalidating it, ie:
[timer invalidate];
timer = nil; (or self.timer = nil as appropriate)
(unless it is going to go out of scope or it is an ivar and you are
in the dealloc routine).
There are three further things to keep in mind:
1. If you create it will alloc initWithFireDate then you own the
timer and will need to release it. If you create it with a class
constructor like scheduledTimerWithTimeInterval then you do not own
it, and you should retain it and then release it if you want to keep
it around (technically, you don't have to retain/release it for
reasons we'll see below, but its probably still a good idea).
2. If you schedule a timer (eg with scheduledTimerWithTimeInterval or
NSRunLoop addTimer:forMode:) the run loop will own the timer (perhaps
as well as you if you've retained it). The run loop will retain the
timer and will release it when its appropriate (after it fires if it
is non repeating or after you invalidate it for repeating timers).
3. As soon as you call [timer invalidate] the timer variable may be
a stale pointer, hence you need to set it to nil. For non repeating
timers, as soon as it fires, the run loop may release the timer, and
so the timer variable will again be a stale pointer unless you have
retained it.
I suspect it is the stale pointer issue that is causing you problems.
Wow, you know when you write it all out there is actually quite a lot
to know to make one of these things work properly. Of course, a lot
of it is the basic memory management stuff of when to release it,
which is a challenge for anyone new to Cocoa, but also a lot of it is
the interaction with the run loop and the inevitable issues of
threading that start rearing their very ugly heads.
At 21:59 +0100 1/3/09, Martijn van Exel wrote:
What I do is:
* Two NSTimer instances are created upon the user pressing a button. One is
a non-repeating NSTimer for executing a delayed action. The other is a
repeating one updating the title of a UIActionSheet (iPhone) so it shows a
count down.
* The method invoked by the first timer also dismisses the UIActionSheet.
* In the didDismissWithButtonIndex callback, the two timers would be
invalidated. This would cause a BAD_ACCESS crash.
If the non repeating timer is a time out, then I would get rid of it
altogether and handle the time out in the repeating timer so the
count down matches exactly. If it serves another purpose, then I
don't know what you're doing with it.
Concrete advice:
Make your two timers ivars.
Make their @property retain.
The properties will be nil when your object is created.
When the button in pressed:
self.countingTimer = [NSTimer scheduledTimerWithTimeInterval ... repeats:YES]
self.otherTimer = [NSTimer scheduledTimerWithTimeInterval ... repeats:NO]
didDismissWithButtonIndex does:
[self.countingTimer invalidate];
self.countingTimer = nil; // also release
[self.otherTimer invalidate];
self.otherTimer = nil; // also release
countingTimer method updates the count down
otherTimer does whatever it wants, if it dismisses the sheet, then it
also invalidates and releases the timers.
dealloc:
[self.countingTimer invalidate];
[self.otherTimer invalidate];
That should do the trick.
Because you are remembering the timer in the ivar, you also take
ownership with it by using the retain @property. That guarantees the
object will be alive to respond to the invalidate method when you
want to send it and you cannot have a stale pointer.
Enjoy,
Peter.
--
Run macros from your iPhone with Keyboard Maestro Control!
or take a break with Aragom Space War for your iPhone
Keyboard Maestro <http://www.keyboardmaestro.com/> Macros for your Mac
Aragom Space War <http://www.stairways.com/iphone/aragom> Don't get killed!
<http://www.stairways.com/> <http://download.stairways.com/>
_______________________________________________
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