API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPTimer.j
Go to the documentation of this file.
1 /*
2  * CPTimer.j
3  * Foundation
4  *
5  * Created by Nick Takayama.
6  * Copyright 2008.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
30 @implementation CPTimer : CPObject
31 {
32  CPTimeInterval _timeInterval;
33  CPInvocation _invocation;
34  Function _callback;
35 
36  BOOL _repeats;
37  BOOL _isValid;
38  CPDate _fireDate;
39  id _userInfo;
40 }
41 
45 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
46 {
47  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
48 
49  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
50 
51  return timer;
52 }
53 
57 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
58 {
59  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
60 
61  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
62 
63  return timer;
64 }
65 
69 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
70 {
71  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
72 
73  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
74 
75  return timer;
76 }
77 
81 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
82 {
83  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
84 }
85 
89 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
90 {
91  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
92 }
93 
97 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
98 {
99  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
100 }
101 
105 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
106 {
107  self = [super init];
108 
109  if (self)
110  {
111  _timeInterval = seconds;
112  _invocation = anInvocation;
113  _repeats = shouldRepeat;
114  _isValid = YES;
115  _fireDate = aDate;
116  }
117 
118  return self;
119 }
120 
124 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
125 {
126  var invocation = [CPInvocation invocationWithMethodSignature:1];
127 
128  [invocation setTarget:aTarget];
129  [invocation setSelector:aSelector];
130  [invocation setArgument:self atIndex:2];
131 
132  self = [self initWithFireDate:aDate interval:seconds invocation:invocation repeats:shouldRepeat];
133 
134  if (self)
135  _userInfo = userInfo;
136 
137  return self;
138 }
139 
143 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
144 {
145  self = [super init];
146 
147  if (self)
148  {
149  _timeInterval = seconds;
150  _callback = aFunction;
151  _repeats = shouldRepeat;
152  _isValid = YES;
153  _fireDate = aDate;
154  }
155 
156  return self;
157 }
158 
162 - (CPTimeInterval)timeInterval
163 {
164  return _timeInterval;
165 }
166 
170 - (CPDate)fireDate
171 {
172  return _fireDate;
173 }
174 
178 - (void)setFireDate:(CPDate)aDate
179 {
180  _fireDate = aDate;
181 }
182 
186 - (void)fire
187 {
188  if (!_isValid)
189  return;
190 
191  if (_callback)
192  _callback();
193  else
194  [_invocation invoke];
195 
196  if (!_isValid)
197  return;
198 
199  if (_repeats)
200  _fireDate = [CPDate dateWithTimeIntervalSinceNow:_timeInterval];
201 
202  else
203  [self invalidate];
204 }
205 
209 - (BOOL)isValid
210 {
211  return _isValid;
212 }
213 
217 - (void)invalidate
218 {
219  _isValid = NO;
220  _userInfo = nil;
221  _invocation = nil;
222  _callback = nil;
223 }
224 
228 - (id)userInfo
229 {
230  return _userInfo;
231 }
232 
233 @end
234 
235 var CPTimersTimeoutID = 1000,
237 
238 var _CPTimerBridgeTimer = function(codeOrFunction, aDelay, shouldRepeat, functionArgs)
239 {
240  var timeoutID = CPTimersTimeoutID++,
241  theFunction = nil;
242 
243  if (typeof codeOrFunction === "string")
244  {
245  theFunction = function()
246  {
247  new Function(codeOrFunction)();
248 
249  if (!shouldRepeat)
250  CPTimersForTimeoutIDs[timeoutID] = nil;
251  }
252  }
253  else
254  {
255  if (!functionArgs)
256  functionArgs = [];
257 
258  theFunction = function()
259  {
260  codeOrFunction.apply(window, functionArgs);
261 
262  if (!shouldRepeat)
263  CPTimersForTimeoutIDs[timeoutID] = nil;
264  }
265  }
266 
267  // A call such as setTimeout(f) is technically invalid but browsers seem to treat it as setTimeout(f, 0), so so will we.
268  aDelay = aDelay | 0.0;
269 
270  CPTimersForTimeoutIDs[timeoutID] = [CPTimer scheduledTimerWithTimeInterval:aDelay / 1000 callback:theFunction repeats:shouldRepeat];
271 
272  return timeoutID;
273 };
274 
275 // Avoid "TypeError: Result of expression 'window' [undefined] is not an object" when running unit tests.
276 // We can't use a regular PLATFORM(DOM) check because that platform constant is not defined in Foundation.
277 if (typeof(window) !== 'undefined')
278 {
279  window.setTimeout = function(codeOrFunction, aDelay)
280  {
281  return _CPTimerBridgeTimer(codeOrFunction, aDelay, NO, Array.prototype.slice.apply(arguments, [2]));
282  };
283 
284  window.clearTimeout = function(aTimeoutID)
285  {
286  var timer = CPTimersForTimeoutIDs[aTimeoutID];
287 
288  if (timer)
289  [timer invalidate];
290 
291  CPTimersForTimeoutIDs[aTimeoutID] = nil;
292  };
293 
294  window.setInterval = function(codeOrFunction, aDelay, functionArgs)
295  {
296  return _CPTimerBridgeTimer(codeOrFunction, aDelay, YES, Array.prototype.slice.apply(arguments, [2]));
297  };
298 
299  window.clearInterval = function(aTimeoutID)
300  {
301  window.clearTimeout(aTimeoutID);
302  };
303 }