Structures

The following structures are available globally.

  • Represents the binding of an action to a specific unconditional Feature.

    These are use as the main entry point for performing actions, having been bound using the action function of Feature (provided by a protocol extension).

    class DocumentManagementFeature: Feature {
        static let description = "Create documents"
    
        // This is where the binding is created
        static let createNew = action(DocumentCreateAction.self)
    
        static func prepare(actions: FeatureActionsBuilder) {
            actions.declare(createNew)
        }
    }
    
    ... later you can perform the action directly ...
    
    DocumentManagementFeature.createNew.perform( ... )
    
    Note that you do not create these bindings explicitly, you must use the Flint `action` function for this.
    
    See more

    Declaration

    Swift

    public struct StaticActionBinding<FeatureType, ActionType> : CustomDebugStringConvertible where FeatureType : FeatureDefinition, ActionType : Action
  • Action inputs that have per-instance metadata applicable to NSUserActivity can conform to ActivityMetadataRepresentable and the metadata they return of this type will be automatically used by the Activities feature to register the activity and an implicit Siri Shortcut if so desired.

    See more

    Declaration

    Swift

    public struct ActivityMetadata
  • A binding of feature and action for a conditional action that may not be available at runtime, depending on other factors e.g. feature flagging or IAPs.

    You can call request() on such a binding to see if its available in order to perform it:

    public class TimelineFeature: ConditionalFeature {
        public static var availability: FeatureAvailability = .runtimeEvaluated
    
        public static var description: String = "Maintains an in-memory timeline of actions for debugging and reporting"
    
        public static var isAvailable: Bool? = true
    
        // ** This creates the conditional binding **
        public static let loadData = action(LoadDataAction.self)
    
        public static func prepare(actions: FeatureActionsBuilder) {
            // Declare the action to  Flint
            actions.declare(loadData)
        }
    }
    
    ... elsewhere when you need to perform the action ...
    
    if let request = TimelineFeature.loadData.request() {
        // Perform it in the main session. Use `ActionSession.perform` to use other sessions.
        request.perform(input: input, presenter: presenter)
    } else {
        fatalError("Should not have been able to chose this action, feature is disabled!")
    }
    
    

    Note

    This is a completely discrete type from StaticActionBinding so that you cannot call perform with a conditional action, you must first request the conditional action using this binding, and then call perform with the ConditionalActionRequest received from that.
    See more

    Declaration

    Swift

    public struct ConditionalActionBinding<FeatureType, ActionType> : CustomDebugStringConvertible where FeatureType : ConditionalFeature, ActionType : Action
  • A type used to prevent direct execution of actions on ConditionalFeature(s), such that ActionSession only has functions to perform actions using ConditionalActionRequest and not a perform() using a ConditionalActionBinding.

    This makes it impossible to directly perform an action of a conditional feature without first requesting access to it, as these request instances are only created by the framework and must be used to perform such actions.

    The protocol extensions on ConditionalFeature only supports request and not perform, forcing the caller to test if the feature is available first and at least explicitly ignore the feature not available path, but hopefully provide a code path for that.

    See more

    Declaration

    Swift

    public struct ConditionalActionRequest<FeatureType, ActionType> where FeatureType : ConditionalFeature, ActionType : Action
  • Values of this type represent a single constraint evaluation result, used to determine whether a constraint has been met or not.

    You receive these values when the feature’s constraints have been evaluated by the FeatureConstraintsEvaluator, which returns a FeatureConstraintEvaluation so that you can access the individual results.

    See

    FeatureConstraintEvaluation
    See more

    Declaration

    Swift

    public struct FeatureConstraintResult<T> : Hashable where T : FeatureConstraint
  • The container for constraint evaluation results.

    Use this to examine all the constraints on the feature and whether they are active and/or fulfilled.

    See more

    Declaration

    Swift

    public struct FeatureConstraintsEvaluation
  • A type that encapsulates information about the permission requirements of a feature, for easy access when determining what to do in your app when a Feature is not available.

    Use notDetermined.count > 0 to detect when there are permissions that can be authorised.

    See more

    Declaration

    Swift

    public struct FeaturePermissionRequirements
  • An encapsulation of a single Action Stack entry.

    This is intentionally lightweight, so it does not retain objects from your app, using simplified representations instead.

    This is explicitly immutable as entries cannot be changed after the fact.

    See more

    Declaration

    Swift

    public struct ActionStackEntry : CustomDebugStringConvertible
  • An abstract path for log events.

    This is used to provide a simple hierarchical structure to log events to facilitate filtering and collapsing, mostly by Features but also arbitrary paths for non-Feature based subsystems.

    See more

    Declaration

    Swift

    public struct TopicPath : Hashable, Equatable, CustomStringConvertible, ExpressibleByArrayLiteral
  • Represents a topic path that you want to focus on for debugging.

    This is an immutable wrapper used to allow the Focus feature to be used with either TopicPath or Feature.

    See more

    Declaration

    Swift

    public struct FocusArea : FlintLoggable, CustomStringConvertible, CustomDebugStringConvertible, Hashable
  • The context for a log event.

    The same context should be used for multiple log events if the context remains the same, e.g. the topic is the same.

    See more

    Declaration

    Swift

    public struct LogEventContext
  • This type provides access to the App’s loggers.

    Logging in Flint is slightly different and solves several problems:

    1. Excessively noisy logs in non-development builds (a separate logger for debug logging, always silenced in production)
    2. The inability to tell what actual user activity a log entry relates to (see: topic paths, contextual logging)
    3. The typical reliance on a specific logging framework. Wire up whatever implementation you like here.
    4. Focusing on logs only related to specific application features, e.g. drill down into just your Share feature’s logging

    Abstracting logging is one of the more laughable and tedious things in computing, after all how many ways do we need to log text? However nothing out there supports contextual logging and topic paths which are crucial for Flint. So here we are.

    Flint’s logging is somewhat decoupled from the rest of Flint and works like this:

    1. Something in the App calls Logging.development?.contextualLogger(...) or Logging.production.contextualLogger(...) to get a logger that has information about what the user is doing.
    2. The resulting ContextSpecificLogger, if not nil is passed to subsystems that require logging. This is the biggest difference with other logging systems that assume the logger never changes.
    3. The subsystems call one of the logging functions on the logger.
    4. The ContextualLogger delegates the actual logging to a ContextualLoggerTarget, which can filter events or log levels as desired
    5. The DefaultContextualLoggerTarget filters events according to Focus rules, and sends output to a LoggerOutput instance which is the final output of the log text.

    The chain of execution is along these lines:

    ContextualLogger -> ContextualLoggerTarget -> LoggerOutput

    The LoggerOutput is the only think you need to implement for your logging framework, e.g. a layer that uses CocoaLumberjack or Apple’s log systems, or Fabric’s CLS_LOG rolling log buffer.

    Production logging is always available, so that logger factory is not optional. Debug logging can be entirely disabled for production builds, resulting is close to zero overheads due to the optional dereferencing.

    This solves the problem of polluting production logs with excessive internal debug info, without having to dial down log levels in production.

    The implementation of ContextualLoggerTarget can peform filtering of events by topic path or other properties of the context (see DefaultLogger) and those ContextSpecificLogger implementations then pass the logging info on to the LoggerOutput implementation which writes to whatever output you desire.

    There is an AggregatingLoggerOutput provided so you can compose multiple log outputs easily and drive them from the same contextual loggers, e.g. to output to Console as well as an ASL log file.

    See

    DefaultLoggerFactory.setup() for the simple console logging used by default when using Flint.quickSetup.
    See more

    Declaration

    Swift

    public struct Logging
  • This type provides information about the purchases required for a single conditional feature.

    You can use this at runtime to establish which purchases you need to show to the user to enable them to unlock a feature.

    See more

    Declaration

    Swift

    public struct FeaturePurchaseRequirements
  • A wrapper that provides all the details of a successful url mapping lookup.

    This is used to execution an action bound to a URL mapping, supplying the extra parameters parsed out of the URL itself.

    See

    `URLPattern

    Declaration

    Swift

    public struct URLExecutionContext
  • A value that represents a file, a direcotry or a symbolic link within a ZIP Archive.

    You can retrieve instances of Entry from an Archive via subscripting or iteration. Entries are identified by their path.

    See more

    Declaration

    Swift

    public struct Entry : Equatable