RSDSampleRecorder
open class RSDSampleRecorder : NSObject, RSDAsyncAction
RSDSampleRecorder
is a base-class implementation of a controller that is used to record samples.
While it isn’t prohibited to instantiate this class directly, this is intended as an abstract implementation for recording sample data from GPS location, accelerometers, etc.
Using this base implementation allows for a consistent logging of shared sample data key words for the step path and the uptime. It implements the logic for writing to a file, tracking the uptime and start date, and provides a consistent implementation for error handling.
-
Errors returned in the completion handler during
See morestart()
when starting fails for timing reasons.Declaration
Swift
public enum RecorderError : Error
-
Default initializer.
Declaration
Swift
public init(configuration: RSDAsyncActionConfiguration, taskViewModel: RSDPathComponent, outputDirectory: URL)
Parameters
configuration
The configuration used to set up the controller.
taskViewModel
outputDirectory
File URL for the directory in which to store generated data files.
-
Delegate callback for handling action completed or failed.
Declaration
Swift
open weak var delegate: RSDAsyncActionDelegate?
-
The configuration used to set up the controller.
Declaration
Swift
public let configuration: RSDAsyncActionConfiguration
-
The associated task path to which the result should be attached.
Declaration
Swift
public let taskViewModel: RSDPathComponent
-
The status of the recorder.
Note
This property is implemented as@objc dynamic
so that step view controllers can use KVO to listen for changes.Declaration
Swift
@objc dynamic public private(set) var status: RSDAsyncActionStatus { get }
-
Is the action currently paused?
Note
This property is implemented as@objc dynamic
so that step view controllers can use KVO to listen for changes.Declaration
Swift
@objc dynamic open private(set) var isPaused: Bool { get }
-
The last error on the action controller.
Note
Under certain circumstances, getting an error will not result in a terminal failure of the controller. For example, if a controller is both processing motion and camera sensors and only the motion sensors failed but using them is a secondary action.Declaration
Swift
public var error: Error?
-
Results for this recorder.
During initialization the recorder will instantiate an
RSDCollectionResult
that can be used to collect any results attached to this recorder, including theORKFileResult
that points to the logging file used to record the log samples. This property will only return a non-nil result if the collection includes one or more results. If there is only one result, then that one result is returned. Otherwise, thecollectionResult
is returned.Seealso
collectionResult
Declaration
Swift
public var result: RSDResult? { get }
-
Start the recorder with the given completion handler.
This method is called by the task controller to start the recorder. This implementation performs the following actions:
- Check to see if the recorder is already running or has been cancelled and will call the completion handler with an error if that is the case.
- Update the
startUptime
andstartDate
to the current time. - Open a file for logging samples.
- If and only if the logging file was successfully opened, then call
startRecorder()
asynchronously on the main queue.
Note
This is implemented as apublic final
class to block overriding this method. Instead, subclasses should implement logic required to start a recorder by overriding thestartRecorder()
method. This is done to ensure that the logging file was successfully created before attempting to record any data to that file.Declaration
Swift
public final func start(_ completion: RSDAsyncActionCompletionHandler?)
-
Pause the action. The base class implementation marks the
isPaused
property astrue
.Declaration
Swift
open func pause()
-
Resume the action. The base class implementation marks the
isPaused
property asfalse
.Declaration
Swift
open func resume()
-
Stop the action with the given completion handler.
This method is called by the task controller to stop the recorder. This implementation will first close the logging file and then call
stopRecorder()
asynchronously on the main queue. ThestopRecorder()
method is called whether or not there is an error when closing the logging file so that subclasses can perform any required cleanup.Note
This is implemented as apublic final
class to block overriding this method. Instead, subclasses should implement logic required to stop a recorder by overriding thestopRecorder()
method. This is done to ensure that the logging file is closed and the result is added to the result collection before handing over control to the subclass.Declaration
Swift
public final func stop(_ completion: RSDAsyncActionCompletionHandler?)
-
Cancel the action. The default implementation will set the
isCancelled
flag totrue
and then callstop()
with a nil completion handler.Declaration
Swift
open func cancel()
-
Let the controller know that the task has moved to the given step. This method is called by the task controller when the task transitions to a new step. The default implementation will update the
currentStepIdentifier
andcurrentStepPath
, then it will add a marker to the logging files.Declaration
Swift
open func moveTo(step: RSDStep, taskViewModel: RSDPathComponent)
-
Available for watchOS.
This method should be called on the main thread with the completion handler also called on the main thread. The base class implementation will immediately call the completion handler.
Remark
Override to implement custom permission handling.Seealso
RSDAsyncAction.requestPermissions()
-
Available for macOS.
This method should be called on the main thread with the completion handler also called on the main thread. The base class implementation will immediately call the completion handler.
Remark
Override to implement custom permission handling.Seealso
RSDAsyncAction.requestPermissions(on:)
-
Available for iOS and tvOS.
This method should be called on the main thread with the completion handler also called on the main thread. The base class implementation will immediately call the completion handler.
Remark
Override to implement custom permission handling.Seealso
RSDAsyncAction.requestPermissions(on:)
Declaration
Swift
open func requestPermissions(on viewController: UIViewController, _ completion: @escaping RSDAsyncActionCompletionHandler)
Parameters
viewController
The view controler that should be used to present any modal dialogs.
completion
The completion handler.
-
Is this recorder running in the simulator?
Declaration
Swift
public let isSimulator: Bool
-
The collection result is used internally to allow storing multiple results associated with this recorder. For example, a location recorder may also query the pedometer and record the number of steps during a walking or runnning task.
During initialization the recorder will instantiate an
RSDCollectionResultObject
that can be used to collect any results attached to this recorder, including theORKFileResult
that points to the logging file used to record the log samples. The property is marked asopen
to allow subclasses to point at a different implementation of theRSDCollectionResult
protocol.Declaration
Swift
open private(set) var collectionResult: RSDCollectionResult { get }
-
The clock for this recorder.
Declaration
Swift
open private(set) var clock: RSDClock { get }
-
The date timestamp for when the recorder was started.
Declaration
Swift
public var startDate: Date { get }
-
The identifier for tracking the current step.
Declaration
Swift
public private(set) var currentStepIdentifier: String { get }
-
The current
stepPath
to record to log samples.Declaration
Swift
public private(set) var currentStepPath: String { get }
-
This method is called during startup after the logger is setup to start the recorder. The base class implementation will immediately call the completion handler. If an overriding class needs to do any initialization to start the recorder, then override this method. If the override calls the completion handler then DO NOT call super. This method is called from
start()
on the main thread queue.Declaration
Swift
open func startRecorder(_ completion: @escaping ((RSDAsyncActionStatus, Error?) -> Void))
Parameters
completion
Callback for updating the status of the recorder once startup has completed (or failed).
-
Convenience method for stopping the recorder without a callback handler.
Declaration
Swift
public final func stop()
-
This method is called during finish after the logger is closed. The base class implementation will immediately call the completion handler. If an overriding class needs to do any actions to stop the recorder, then override this method. If the override calls the completion handler then DO NOT call super. Otherwise, super will call the completion with the logger error as the input to the completion handler. This method is called from
stop()
on the main thread queue.Declaration
Swift
open func stopRecorder(_ completion: @escaping ((RSDAsyncActionStatus) -> Void))
Parameters
completion
Callback for updating the status of the recorder once startup has completed (or failed).
-
This method can be called by either the logging file if there was a write error, or by the subclass if there was an error when attempting to record samples. The method will call the delegate method
asyncAction(_, didFailWith:)
asynchronously on the main queue and will callcancel()
synchronously on the current queue.Declaration
Swift
open func didFail(with error: Error)
-
Append the
collectionResult
with the given result.Declaration
Swift
public final func appendResults(_ result: RSDResult)
Parameters
result
The result to add to the collection.
-
This method will synchronously update the status and is expected to only be called by a subclass to allow subclasses to transition the status from
.processingResults
to.stopping
and then.finished
or from.starting
to.running
.Declaration
Swift
public final func updateStatus(to newStatus: RSDAsyncActionStatus, error: Error?)
-
The serial queue used for writing samples to the log files. To ensure that write failures due to memory warnings do not get thrown by multiple threads, a single logging queue is used for writing to all the open log files.
Declaration
Swift
public let loggerQueue: DispatchQueue
-
The loggers used to record samples to a file.
Declaration
Swift
public private(set) var loggers: [String : RSDDataLogger] { get }
-
The list of identifiers for the loggers. For each unique identifier in this list, the recorder will open a file for recording record samples. This allows a single recorder to handle data from multiple sensors.
For example, if the application requires recording both raw accelerometer data and the device motion data, these can be recordeded to different sample files by defining a unique identifier for each sensor recording, while using a single
CMMotionManager
as recommended by Apple.Declaration
Swift
open var loggerIdentifiers: Set<String> { get }
-
The default logger identifier to call if the
writeSample()
method is called without a logger identifier.Declaration
Swift
open var defaultLoggerIdentifier: String { get }
-
The section identifier for this recorder. An identifier string that can be appended to a step view controller to differentiate this step from another instance in a different section.
Declaration
Swift
open var sectionIdentifier: String { get }
-
File URL for the directory in which to store generated data files.
Declaration
Swift
public let outputDirectory: URL
-
Should the logger use a dictionary as the root element?
If
true
then the logger will open the file with the samples included in an array with the key ofitems
. Iffalse
then the file will use an array as the root elemenent and the samples will be added to that array.Declaration
Swift
open var usesRootDictionary: Bool { get }
-
instantiate a marker for recording step transitions as well as start and stop points. The default implementation will instantiate a
RSDRecordMarker
.Declaration
Swift
open func instantiateMarker(uptime: TimeInterval, timestamp: TimeInterval, date: Date, stepPath: String, loggerIdentifier: String) -> RSDSampleRecord
Parameters
uptime
The system clock time.
timestamp
Relative timestamp for this recorder.
date
The timestamp date.
stepPath
The step path.
loggerIdentifier
The identifier for the logger for which to create the marker.
Return Value
A sample to add to the log file that can be used as a step transition marker.
-
Update the current step and step path.
Declaration
Swift
open func updateMarker(step: RSDStep?, taskViewModel: RSDPathComponent)
Parameters
step
The current step.
taskViewModel
The current path.
-
Write a sample to the logger.
Declaration
Swift
public final func writeSample(_ sample: RSDSampleRecord, loggerIdentifier: String? = nil)
Parameters
sample
sample: The sample to add to the logging file.
loggerIdentifier
The identifier for the logger for which to create the marker. If nil, then the
defaultLoggerIdentifier
will be used. -
Write multiple samples to the logger.
Declaration
Swift
public final func writeSamples(_ samples: [RSDSampleRecord], loggerIdentifier: String? = nil)
Parameters
samples
The samples to add to the logging file.
loggerIdentifier
The identifier for the logger for which to create the marker. If nil, then the
defaultLoggerIdentifier
will be used. -
Instantiate the logger file for the given identifier.
By default, the file will be created using the
RSDFileResultUtility.createFileURL()
utility method to create a URL in theoutputDirectory
. ARSDRecordSampleLogger
is returned by default.Throws
An error if opening the log file failed.Declaration
Swift
open func instantiateLogger(with identifier: String) throws -> RSDDataLogger?
Parameters
identifier
The unique identifier for the logger.
Return Value
A new instance of a
RSDDataLogger
. -
Returns the string encoding format to use for this file. Default is
nil
. If this isnil
then the file will be formatted using JSON encoding.Declaration
Swift
open func stringEncodingFormat() -> RSDStringSeparatedEncodingFormat?