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 start() when starting fails for timing reasons.

    See more

    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 the ORKFileResult 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, the collectionResult is returned.

    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:

    1. 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.
    2. Update the startUptime and startDate to the current time.
    3. Open a file for logging samples.
    4. If and only if the logging file was successfully opened, then call startRecorder() asynchronously on the main queue.

    Note

    This is implemented as a public final class to block overriding this method. Instead, subclasses should implement logic required to start a recorder by overriding the startRecorder() 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 as true.

    Declaration

    Swift

    open func pause()
  • Resume the action. The base class implementation marks the isPaused property as false.

    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. The stopRecorder() 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 a public final class to block overriding this method. Instead, subclasses should implement logic required to stop a recorder by overriding the stopRecorder() 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 to true and then call stop() 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 and currentStepPath, 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 the ORKFileResult that points to the logging file used to record the log samples. The property is marked as open to allow subclasses to point at a different implementation of the RSDCollectionResult 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 call cancel() 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 of items. If false 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 the outputDirectory. A RSDRecordSampleLogger 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 is nil then the file will be formatted using JSON encoding.

    Declaration

    Swift

    open func stringEncodingFormat() -> RSDStringSeparatedEncodingFormat?