summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Fischer <joeljfischer@gmail.com>2020-05-08 12:58:51 -0400
committerGitHub <noreply@github.com>2020-05-08 12:58:51 -0400
commitc34d76487b50ce839de7773a98d9fbede89bce02 (patch)
tree43c6ab0575789836f8f50ce77c4718f27f0d728d
parent67d00d0caa0296a3a9ec839bf7bd93141110b6d7 (diff)
parent7cf2918f2a3ff3c9e4fb3eda370bc2bae7dcae8c (diff)
downloadsdl_ios-c34d76487b50ce839de7773a98d9fbede89bce02.tar.gz
Merge pull request #1646 from smartdevicelink/bugfix/issue-1611-replace-nstimer-with-sdltimer
Replace uses of NSTimer with SDLTimer
-rw-r--r--SmartDeviceLink/SDLTCPTransport.m23
-rw-r--r--SmartDeviceLink/SDLTimer.h28
-rw-r--r--SmartDeviceLink/SDLTimer.m37
-rw-r--r--SmartDeviceLink/SDLTouchManager.h37
-rw-r--r--SmartDeviceLink/SDLTouchManager.m22
5 files changed, 82 insertions, 65 deletions
diff --git a/SmartDeviceLink/SDLTCPTransport.m b/SmartDeviceLink/SDLTCPTransport.m
index 027a9f204..0dc347f8a 100644
--- a/SmartDeviceLink/SDLTCPTransport.m
+++ b/SmartDeviceLink/SDLTCPTransport.m
@@ -10,6 +10,7 @@
#import "SDLMutableDataQueue.h"
#import "SDLError.h"
#import "SDLLogMacros.h"
+#import "SDLTimer.h"
#import <errno.h>
NS_ASSUME_NONNULL_BEGIN
@@ -26,7 +27,7 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
@property (nullable, nonatomic, strong) NSInputStream *inputStream;
@property (nullable, nonatomic, strong) NSOutputStream *outputStream;
@property (nonatomic, assign) BOOL outputStreamHasSpace;
-@property (nullable, nonatomic, strong) NSTimer *connectionTimer;
+@property (nullable, nonatomic, strong) SDLTimer *connectionTimer;
@property (nonatomic, assign) BOOL transportConnected;
@property (nonatomic, assign) BOOL transportErrorNotified;
@end
@@ -126,7 +127,12 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
[self sdl_setupStream:self.outputStream];
// JFYI: NSStream itself has a connection timeout (about 1 minute). If you specify a large timeout value, you may get the NSStream's timeout event first.
- self.connectionTimer = [NSTimer scheduledTimerWithTimeInterval:ConnectionTimeoutSecs target:self selector:@selector(sdl_onConnectionTimedOut:) userInfo:nil repeats:NO];
+ __weak typeof(self) weakSelf = self;
+ self.connectionTimer = [[SDLTimer alloc] initWithDuration:ConnectionTimeoutSecs];
+ self.connectionTimer.elapsedBlock = ^{
+ [weakSelf sdl_onConnectionTimedOut];
+ };
+ [self.connectionTimer startOnRunLoop:[NSRunLoop currentRunLoop]];
// these will initiate a connection to remote server
SDLLogD(@"Connecting to %@:%@ ...", self.hostName, self.portNumber);
@@ -145,7 +151,7 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
[self sdl_teardownStream:self.inputStream];
[self sdl_teardownStream:self.outputStream];
- [self sdl_cancelConnectionTimer];
+ [self.connectionTimer cancel];
}
}
@@ -170,13 +176,6 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
[self performSelector:@selector(sdl_doNothing) onThread:self.ioThread withObject:nil waitUntilDone:NO];
}
-/// Cancels the connection timer for establishing a TCP socket with the accessory.
-- (void)sdl_cancelConnectionTimer {
- if (self.connectionTimer == nil) { return; }
- [self.connectionTimer invalidate];
- self.connectionTimer = nil;
-}
-
#pragma mark - NSStreamDelegate
// this method runs only on the I/O thread (i.e. invoked from the run loop)
@@ -189,7 +188,7 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
// We will get two NSStreamEventOpenCompleted events (for both input and output streams) and we don't need both. Let's use the one of output stream since we need to make sure that output stream is ready before Proxy sending Start Service frame.
if (aStream == self.outputStream) {
SDLLogD(@"TCP transport connected");
- [self sdl_cancelConnectionTimer];
+ [self.connectionTimer cancel];
self.transportConnected = YES;
[self.delegate onTransportConnected];
}
@@ -268,7 +267,7 @@ NSTimeInterval ConnectionTimeoutSecs = 30.0;
self.outputStreamHasSpace = NO;
}
-- (void)sdl_onConnectionTimedOut:(NSTimer *)timer {
+- (void)sdl_onConnectionTimedOut {
NSAssert([[NSThread currentThread] isEqual:self.ioThread], @"sdl_onConnectionTimedOut is called on a wrong thread!");
SDLLogW(@"TCP connection timed out");
diff --git a/SmartDeviceLink/SDLTimer.h b/SmartDeviceLink/SDLTimer.h
index cba9efefa..3ca45fdb1 100644
--- a/SmartDeviceLink/SDLTimer.h
+++ b/SmartDeviceLink/SDLTimer.h
@@ -8,14 +8,34 @@ NS_ASSUME_NONNULL_BEGIN
@interface SDLTimer : NSObject
+/// A block called when the timer elapses
@property (copy, nonatomic, nullable) void (^elapsedBlock)(void);
+
+/// A block called when the timer is cancelled
@property (copy, nonatomic, nullable) void (^canceledBlock)(void);
-@property (assign, nonatomic) float duration;
-- (instancetype)init;
-- (instancetype)initWithDuration:(float)duration;
-- (instancetype)initWithDuration:(float)duration repeat:(BOOL)repeat;
+/// The time between calling `start` and when the elapsed block will be called
+@property (assign, nonatomic) NSTimeInterval duration;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+/// Initialize a timer with a specified duration on the main run loop without repeating
+/// @param duration The duration of the timer. Must not be 0.
+- (instancetype)initWithDuration:(NSTimeInterval)duration;
+
+/// Initialize a timer with a specified duration on the passed run loop and optionally repeating
+/// @param duration The duration of the timer
+/// @param repeat Whether or not the timer should autorepeat
+- (instancetype)initWithDuration:(NSTimeInterval)duration repeat:(BOOL)repeat;
+
+/// Starts the timer on the main run loop. When the timer has elapsed, the elapsed block will be called.
- (void)start;
+
+/// Starts the timer on the specified run loop. When the timer has elapsed, the elapsed block will be called.
+/// @param runLoop The run loop to start the timer on
+- (void)startOnRunLoop:(NSRunLoop *)runLoop;
+
+/// Cancels and invalidates the timer. The canceled block will be called.
- (void)cancel;
@end
diff --git a/SmartDeviceLink/SDLTimer.m b/SmartDeviceLink/SDLTimer.m
index 2774c0836..5ef063307 100644
--- a/SmartDeviceLink/SDLTimer.m
+++ b/SmartDeviceLink/SDLTimer.m
@@ -2,6 +2,7 @@
// SDLTimer.m
//
+#import "SDLLogMacros.h"
#import "SDLTimer.h"
NS_ASSUME_NONNULL_BEGIN
@@ -42,30 +43,26 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, nonatomic, nullable) NSTimer *timer;
@property (assign, nonatomic) BOOL timerRunning;
@property (assign, nonatomic) BOOL repeat;
+
@end
@implementation SDLTimer
-- (instancetype)init {
- if (self = [super init]) {
- _duration = 0;
- _timerRunning = NO;
- }
- return self;
-}
-
-- (instancetype)initWithDuration:(float)duration {
+- (instancetype)initWithDuration:(NSTimeInterval)duration {
return [self initWithDuration:duration repeat:NO];
}
-- (instancetype)initWithDuration:(float)duration repeat:(BOOL)repeat {
+- (instancetype)initWithDuration:(NSTimeInterval)duration repeat:(BOOL)repeat {
self = [super init];
- if (self) {
- _duration = duration;
- _repeat = repeat;
- _timerRunning = NO;
- }
+ if (!self) { return nil; }
+
+ NSAssert(duration > 0, @"Cannot create a timer with a 0 duration");
+
+ _duration = duration;
+ _repeat = repeat;
+ _timerRunning = NO;
+
return self;
}
@@ -74,12 +71,16 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)start {
+ [self startOnRunLoop:[NSRunLoop mainRunLoop]];
+}
+
+- (void)startOnRunLoop:(NSRunLoop *)runLoop {
if (self.duration > 0) {
[self stopAndDestroyTimer];
-
+
SDLTimerTarget *timerTarget = [[SDLTimerTarget alloc] initWithDelegate:self];
- self.timer = [NSTimer timerWithTimeInterval:_duration target:timerTarget selector:@selector(timerElapsed) userInfo:nil repeats:_repeat];
- [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
+ self.timer = [NSTimer timerWithTimeInterval:self.duration target:timerTarget selector:@selector(timerElapsed) userInfo:nil repeats:_repeat];
+ [runLoop addTimer:self.timer forMode:NSRunLoopCommonModes];
self.timerRunning = YES;
}
}
diff --git a/SmartDeviceLink/SDLTouchManager.h b/SmartDeviceLink/SDLTouchManager.h
index 7b7e65a97..c762d6822 100644
--- a/SmartDeviceLink/SDLTouchManager.h
+++ b/SmartDeviceLink/SDLTouchManager.h
@@ -33,39 +33,35 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
@property (nonatomic, weak, nullable) id<SDLTouchManagerDelegate> touchEventDelegate;
/**
- * @abstract
- * Returns all OnTouchEvent notifications as SDLTouch and SDLTouchType objects.
+ Returns all OnTouchEvent notifications as SDLTouch and SDLTouchType objects.
*/
@property (copy, nonatomic, nullable) SDLTouchEventHandler touchEventHandler;
/**
Distance between two taps on the screen, in the head unit's coordinate system, used for registering double-tap callbacks.
- @note Defaults to 50 px.
+ Defaults to 50 px.
*/
@property (nonatomic, assign) CGFloat tapDistanceThreshold;
/**
Minimum distance for a pan gesture in the head unit's coordinate system, used for registering pan callbacks.
- @note Defaults to 8 px.
+ Defaults to 8 px.
*/
@property (nonatomic, assign) CGFloat panDistanceThreshold;
/**
- * @abstract
- * Time (in seconds) between tap events to register a double-tap callback.
- * @remark
- * Default is 0.4 seconds.
+ Time (in seconds) between tap events to register a double-tap callback. This must be greater than 0.0.
+
+ Default is 0.4 seconds.
*/
@property (nonatomic, assign) CGFloat tapTimeThreshold;
/**
- * @abstract
- * Time (in seconds) between movement events to register panning or pinching
- * callbacks.
- * @remark
- * Default is 0.05 seconds.
+ Time (in seconds) between movement events to register panning or pinching callbacks.
+
+ Default is 0.05 seconds.
*/
@property (nonatomic, assign) CGFloat movementTimeThreshold __deprecated_msg("This is now unused, the movement time threshold is now synced to the framerate automatically");
@@ -75,19 +71,16 @@ typedef void(^SDLTouchEventHandler)(SDLTouch *touch, SDLTouchType type);
@property (assign, nonatomic) BOOL enableSyncedPanning;
/**
- * @abstract
- * Boolean denoting whether or not the touch manager should deliver touch event
- * callbacks.
- * @remark
- * Default is true.
+ Boolean denoting whether or not the touch manager should deliver touch event callbacks.
+
+ Default is true.
*/
@property (nonatomic, assign, getter=isTouchEnabled) BOOL touchEnabled;
/**
- * @abstract
- * Cancels pending touch event timers that may be in progress.
- * @remark
- * Currently only impacts the timer used to register single taps.
+ Cancels pending touch event timers that may be in progress.
+
+ Currently only impacts the timer used to register single taps.
*/
- (void)cancelPendingTouches;
diff --git a/SmartDeviceLink/SDLTouchManager.m b/SmartDeviceLink/SDLTouchManager.m
index 50209940e..5a861663d 100644
--- a/SmartDeviceLink/SDLTouchManager.m
+++ b/SmartDeviceLink/SDLTouchManager.m
@@ -18,6 +18,7 @@
#import "SDLProxyListener.h"
#import "SDLRPCNotificationNotification.h"
#import "SDLStreamingVideoScaleManager.h"
+#import "SDLTimer.h"
#import "SDLTouch.h"
#import "SDLTouchCoord.h"
#import "SDLTouchEvent.h"
@@ -74,7 +75,7 @@ static NSUInteger const MaximumNumberOfTouches = 2;
* @abstract
* Timer used for distinguishing between single & double taps.
*/
-@property (nonatomic, strong, nullable) NSTimer *singleTapTimer;
+@property (nonatomic, strong, nullable) SDLTimer *singleTapTimer;
/*!
* @abstract
@@ -447,8 +448,12 @@ static NSUInteger const MaximumNumberOfTouches = 2;
[self sdl_cancelSingleTapTimer];
}
- self.singleTapTimer = [NSTimer timerWithTimeInterval:self.tapTimeThreshold target:self selector:@selector(sdl_singleTapTimerCallback:) userInfo:@{@"point": [NSValue valueWithCGPoint:point]} repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.singleTapTimer forMode:NSRunLoopCommonModes];
+ __weak typeof(self) weakSelf = self;
+ self.singleTapTimer = [[SDLTimer alloc] initWithDuration:self.tapTimeThreshold];
+ self.singleTapTimer.elapsedBlock = ^{
+ [weakSelf sdl_singleTapTimerCallbackWithPoint:point];
+ };
+ [self.singleTapTimer start];
}
/**
@@ -456,10 +461,9 @@ static NSUInteger const MaximumNumberOfTouches = 2;
This is called on the main thread based on `sdl_initializeSingleTapTimerAtPoint:`
- @param timer The timer that was fired
+ @param point The point where the tap occurred
*/
-- (void)sdl_singleTapTimerCallback:(NSTimer *)timer {
- CGPoint point = ((NSValue *)timer.userInfo[@"point"]).CGPointValue;
+- (void)sdl_singleTapTimerCallbackWithPoint:(CGPoint)point {
self.singleTapTouch = nil;
[self sdl_cancelSingleTapTimer];
if ([self.touchEventDelegate respondsToSelector:@selector(touchManager:didReceiveSingleTapForView:atPoint:)]) {
@@ -476,8 +480,8 @@ static NSUInteger const MaximumNumberOfTouches = 2;
*
* Checks if a single tap is inside a view. As the single tap timer is run on a background thread, the check is done on a main thread and then the result is returned on a background thread.
*
- * @param point Screen coordinates of the tap gesture
- * @param hitViewHandler A handler that returns the view the point is inside of; nil if the point does not lie inside of a view
+ * @param point Screen coordinates of the tap gesture
+ * @param hitViewHandler A handler that returns the view the point is inside of; nil if the point does not lie inside of a view
*/
- (void)sdl_getSingleTapHitView:(CGPoint)point hitViewHandler:(nullable void (^)(UIView * __nullable hitView))hitViewHandler {
if (!self.hitTester) {
@@ -499,7 +503,7 @@ static NSUInteger const MaximumNumberOfTouches = 2;
return;
}
- [self.singleTapTimer invalidate];
+ [self.singleTapTimer cancel];
self.singleTapTimer = nil;
}