API  0.9.7
 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 
24 #define CPTimerDefaultTimeInterval 0.1
25 
32 @implementation CPTimer : CPObject
33 {
34  CPTimeInterval _timeInterval;
35  CPInvocation _invocation;
36  Function _callback;
37 
38  BOOL _repeats;
39  BOOL _isValid;
40  CPDate _fireDate;
41  id _userInfo;
42 }
43 
47 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
48 {
49  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
50 
51  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
52 
53  return timer;
54 }
55 
59 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
60 {
61  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
62 
63  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
64 
65  return timer;
66 }
67 
71 + (CPTimer)scheduledTimerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
72 {
73  var timer = [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
74 
75  [[CPRunLoop currentRunLoop] addTimer:timer forMode:CPDefaultRunLoopMode];
76 
77  return timer;
78 }
79 
83 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
84 {
85  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds invocation:anInvocation repeats:shouldRepeat];
86 }
87 
91 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
92 {
93  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds target:aTarget selector:aSelector userInfo:userInfo repeats:shouldRepeat];
94 }
95 
99 + (CPTimer)timerWithTimeInterval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
100 {
101  return [[self alloc] initWithFireDate:[CPDate dateWithTimeIntervalSinceNow:seconds] interval:seconds callback:aFunction repeats:shouldRepeat];
102 }
103 
107 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds invocation:(CPInvocation)anInvocation repeats:(BOOL)shouldRepeat
108 {
109  self = [super init];
110 
111  if (self)
112  {
113  _timeInterval = (seconds <= 0) ? CPTimerDefaultTimeInterval : seconds;
114  _invocation = anInvocation;
115  _repeats = shouldRepeat;
116  _isValid = YES;
117  _fireDate = aDate;
118  }
119 
120  return self;
121 }
122 
126 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
127 {
128  var invocation = [CPInvocation invocationWithMethodSignature:1];
129 
130  [invocation setTarget:aTarget];
131  [invocation setSelector:aSelector];
132  [invocation setArgument:self atIndex:2];
133 
134  self = [self initWithFireDate:aDate interval:seconds invocation:invocation repeats:shouldRepeat];
135 
136  if (self)
137  _userInfo = userInfo;
138 
139  return self;
140 }
141 
145 - (id)initWithFireDate:(CPDate)aDate interval:(CPTimeInterval)seconds callback:(Function)aFunction repeats:(BOOL)shouldRepeat
146 {
147  self = [super init];
148 
149  if (self)
150  {
151  _timeInterval = (seconds <= 0) ? CPTimerDefaultTimeInterval : seconds;
152  _callback = aFunction;
153  _repeats = shouldRepeat;
154  _isValid = YES;
155  _fireDate = aDate;
156  }
157 
158  return self;
159 }
160 
164 - (CPTimeInterval)timeInterval
165 {
166  return _timeInterval;
167 }
168 
172 - (CPDate)fireDate
173 {
174  return _fireDate;
175 }
176 
180 - (void)setFireDate:(CPDate)aDate
181 {
182  _fireDate = aDate;
183 }
184 
188 - (void)fire
189 {
190  if (!_isValid)
191  return;
192 
193  if (_callback)
194  _callback();
195  else
196  [_invocation invoke];
197 
198  if (!_isValid)
199  return;
200 
201  if (_repeats)
202  _fireDate = [CPDate dateWithTimeIntervalSinceNow:_timeInterval];
203 
204  else
205  [self invalidate];
206 }
207 
211 - (BOOL)isValid
212 {
213  return _isValid;
214 }
215 
219 - (void)invalidate
220 {
221  _isValid = NO;
222  _userInfo = nil;
223  _invocation = nil;
224  _callback = nil;
225 }
226 
230 - (id)userInfo
231 {
232  return _userInfo;
233 }
234 
235 @end
236 
237 var CPTimersTimeoutID = 1000,
239 
240 var _CPTimerBridgeTimer = function(codeOrFunction, aDelay, shouldRepeat, functionArgs)
241 {
242  var timeoutID = CPTimersTimeoutID++,
243  theFunction = nil;
244 
245  if (typeof codeOrFunction === "string")
246  {
247  theFunction = function()
248  {
249  new Function(codeOrFunction)();
250 
251  if (!shouldRepeat)
252  CPTimersForTimeoutIDs[timeoutID] = nil;
253  }
254  }
255  else
256  {
257  if (!functionArgs)
258  functionArgs = [];
259 
260  theFunction = function()
261  {
262  codeOrFunction.apply(window, functionArgs);
263 
264  if (!shouldRepeat)
265  CPTimersForTimeoutIDs[timeoutID] = nil;
266  }
267  }
268 
269  // A call such as setTimeout(f) is technically invalid but browsers seem to treat it as setTimeout(f, 0), so so will we.
270  aDelay = aDelay | 0.0;
271 
272  CPTimersForTimeoutIDs[timeoutID] = [CPTimer scheduledTimerWithTimeInterval:aDelay / 1000 callback:theFunction repeats:shouldRepeat];
273 
274  return timeoutID;
275 };
276 
277 // Avoid "TypeError: Result of expression 'window' [undefined] is not an object" when running unit tests.
278 // We can't use a regular PLATFORM(DOM) check because that platform constant is not defined in Foundation.
279 if (typeof(window) !== 'undefined')
280 {
281  window.setTimeout = function(codeOrFunction, aDelay)
282  {
283  return _CPTimerBridgeTimer(codeOrFunction, aDelay, NO, Array.prototype.slice.apply(arguments, [2]));
284  };
285 
286  window.clearTimeout = function(aTimeoutID)
287  {
288  var timer = CPTimersForTimeoutIDs[aTimeoutID];
289 
290  if (timer)
291  [timer invalidate];
292 
293  CPTimersForTimeoutIDs[aTimeoutID] = nil;
294  };
295 
296  window.setInterval = function(codeOrFunction, aDelay, functionArgs)
297  {
298  return _CPTimerBridgeTimer(codeOrFunction, aDelay, YES, Array.prototype.slice.apply(arguments, [2]));
299  };
300 
301  window.clearInterval = function(aTimeoutID)
302  {
303  window.clearTimeout(aTimeoutID);
304  };
305 }