Protocols
The following protocols are available globally.
-
Actions that can be performed conform to this protocol to define their inputs, presenter and logic.
Actions are statically defined to avoid the mistake of storing state with them. Any state belongs in the
input
passed when performing the action.Many of these static properties have default implementations provided by a protocol extension.
Note
Action implementations must be final due to Swift extension requirements.The same action can be reused in different features, so they receive all context they need when executing.
Note that actions have their own analytics ID defined statically.
See moreDeclaration
Swift
public protocol Action
-
The protocol to which Inputs must conform to be logged usefully by Flint’s logging, Timeline, Action Stacks etc.
Flint requires a human readable description of all inputs to use in logs and debug UI, as well as a structured data representation for use in machine-readable outputs.
We cannot rely on
See moreCustomStringConvertible
andCustomDebugStringConvertible
for this as the developer may not control the contents of these, and the semantics are not rigid enough for our use.Declaration
Swift
public protocol FlintLoggable
-
An action that performs no work except successfully completing with feature termination.
Actions adopting this protocol will not need to provide a
perform
implementation.Conforming to this protocol is useful for
See moredone
type Actions that you want to participate in standard Action patterns, but do not actually perform any code.Declaration
Swift
public protocol TerminatingAction : Action
-
Note
See https://bugs.swift.org/browse/SR-10831 for why this is so ugly. The type inference should see the constraints fully satisfy the associated types but it doesn’t, so we have to also specify the associatedtype so that conforming types can compileDeclaration
Swift
public protocol DismissingUIAction : UIAction where Self.InputType == DismissUIInput, Self.PresenterType == UIViewController
-
Action input types can conform to this protocol to automatically supply the
See moreuserInfo
for NSUserActivity with the Activities feature.Declaration
Swift
public protocol ActivityCodable
-
A protocol for Action input types to conform to, to supply metadata for
See moreNSUserActivity
when used with the Activities feature.Declaration
Swift
public protocol ActivityMetadataRepresentable
-
Conform to this protocol to wire up your chosen Analytics service to receive events when
Action
(s) that have ananalyticsID
set are performed.Your implementation will receive the feature and action information, and the analytics properties returned by your
Action
implementations’analyticsAttributes(for:)
function.Read the
analyticsID
for the event from theaction
passeds to the functions.See
ConsoleAnalyticsProvider
for a trivial example implementation.Declaration
Swift
public protocol AnalyticsProvider
-
You can customise the checking of purchased and user toggled conditional features by implementing this protocol.
Implementations must be safe to call from any thread or queue, so that callers testing
isAvailable
on a feature do not need to be concerned about this even if running on a background queue or an ActionSession that is not on the main queue.Implementations must also take care to examine the ancestors of features to ensure the correct result is returned from isAvailable.
See moreDeclaration
Swift
public protocol AvailabilityChecker
-
Features that are not guaranteed to be available all the time must conform to this protocol.
You implement a conditional feature like so:
public class TimelineFeature: ConditionalFeature { /// Set the availability to .purchasRequired, .runtimeEvaluated or .userToggled as appropriate public static var availability: FeatureAvailability = .runtimeEvaluated public static var description: String = "Maintains an in-memory timeline of actions for debugging and reporting" /// If availability is `runtimeEvaluated`, you must make `isAvailable` return whether or not it is available. /// Otherwise do not define a property for it and the `DefaultAvailabilityChecker` will be used to work out /// the correct value of this by calling into the `UserDefaultsFeatureToggles` or `PurchaseValidator`. public static var isAvailable: Bool? = true /// If using `runtimeEvaluated` you can use this function to set `isAvailable` at startup based on /// some other condition. Beware of dependency on other features and non-determinate initialising sequence. public static func prepare(actions: FeatureActionsBuilder) { if isAvailable == true { // Tracks the user's history of actions performed Flint.dispatcher.add(observer: TimelineDispatchObserver.instance) } } }
Apps must call
See morerequest
to test if the action is available, and then callperform
with the resulting request instance.Declaration
Swift
public protocol ConditionalFeature : ConditionalFeatureDefinition
-
A feature that is not guaranteed to always be available must conform to
ConditionalFeatureDefinition
, so that we can ensure the caller always verifies their availability before performing them.This type exists separately from
ConditionalFeature
so that other types of conditional feature can exist (e.g. a futureConditionalFeatureGroup
).We also have this type to enable us to reference conditional features without generic constraint issues that arise from the Self requirement of
ConditionalFeature
. This allows us to define helper functions that operate on conditional features without having to deal with those problems.Note
Accesses to any properties that may change at runtime, e.g.isAvailable
must only occur on the main thread.Declaration
Swift
public protocol ConditionalFeatureDefinition : FeatureDefinition
-
The interface to user-specified feature toggling, where a user may choose to switch certain features on or off in the
Settings
of your app.The
DefaultAvailabilityChecker
uses instances of this type to verify availability of user toggled features at runtime. The default implementationUserDefaultsFeatureToggles
stores the toggled values in User Defaults.If you want to store your feature toggles differently, implement this protocol and assign your own instance of
See moreDefaultAvailabilityChecker
toFlint.availabilityChecker
at startup.Declaration
Swift
public protocol UserFeatureToggles
-
The protocol for observers of changes to user feature toggles
Note
@objc
only because of SR-55.Declaration
Swift
@objc public protocol UserFeatureTogglesObserver
-
The interface to the constraints evaluator component.
Implementations are responsible for evaluating all the constraints and returning information about those that are satisfied or not.
See moreDeclaration
Swift
public protocol ConstraintsEvaluator : AnyObject
-
All feature constraint types must conform to this protocol.
This protocol lets us get at basic information about any kind of constraint enum.
See moreDeclaration
Swift
public protocol FeatureConstraint : Hashable
-
The protocol for accessing information about the results of an evaluation
See moreDeclaration
Swift
public protocol FeatureConstraintEvaluationResults
-
The protocol for the builder used to evaluate the
See moreconstraints
convention function of conditional features.Declaration
Swift
public protocol FeatureConstraintsBuilder : AnyObject
-
An authorisation controller is used to request a set of system permissions.
Using
ConditionalFeature.permissionAuthorisationController(using:)
you can get an instance of a controller in your app for any conditional feature you have. You then callbegin
to start the flow.The flow can be multi-step if your feature has multiple permissions that are not yet authorised, and the coordinator object you pass to
ConditionalFeature.permissionAuthorisationController
gives you the opportunity to update your UI at each step, giving the user the ability to skip or cancel the process.See
ConditionalFeature.permissionAuthorisationController
Declaration
Swift
public protocol AuthorisationController
-
The interface to the coordinator that apps must implement if they want to hook in to the permission authorisation controller flow.
Apps can use this interface to present custom UI before the authorisation flow starts, and update this before and after each permission is requested, with control over what happens next.
For example you may have non-modal UI that shows the user what the camera will be used for, and it contains a SKIP button. If they tap this, you call the completion handler passing
See more.skip
and the controller will move on to the next permission, or finish the flow if there are no more permissions required.Declaration
Swift
public protocol PermissionAuthorisationCoordinator
-
The interface for components that provide access to underlying system permissions.
See moreDeclaration
Swift
public protocol SystemPermissionAdapter : AnyObject
-
Undocumented
See moreDeclaration
Swift
public protocol SystemPermissionCheckerDelegate : AnyObject
-
The interface for the component that will check that required permissions are granted.
Implementations must be safe to call from any thread.
See moreDeclaration
Swift
public protocol SystemPermissionChecker : AnyObject
-
The interface to types that evaluate whether or not a specific precondition has been met.
See moreDeclaration
Swift
public protocol FeaturePreconditionConstraintEvaluator : AnyObject
-
The protocol for observers of the ActionDispatcher.
Dispatch observers are called asynchronously on an arbitrary queue.
Note
Because of the user of generics, this cannot be @objc which is required if we want to useObserverSet
because… https://bugs.swift.org/browse/SR-55Declaration
Swift
public protocol ActionDispatchObserver
-
An action dispatcher is used to perform actions and perform housekeeping to enable tracking of which features are active at a given time, hooking into logging and analytics etc.
Dispatchers are expected to perform actions synchronously.
If you wish to use your own implementation you must assign it to
See moreFlint.dispatcher
at startup.Declaration
Swift
public protocol ActionDispatcher
-
Classes conforming to this protocol can provide debug reports when
Flint.gatherReportZip
is called.Use in apps to expose app-specific debug information that may be useful for troubleshooting.
See
DebugReporting.add(:)
for registering your own reportable objet to be included.Declaration
Swift
public protocol DebugReportable : AnyObject
-
Classes conforming to Feature represent an always-available feature that can perform actions.
To define such a feature, conform to this protocol and declare static properties for the actions it supports, using the
action(Action.Type)
helper function. You then overrideprepare
and use the actions builder to declare or publish those actions:class DocumentManagementFeature: Feature, URLMapped { static let description = "Create, Open and Save documents" static let createNew = action(DocumentCreateAction.self) static let openDocument = action(DocumentOpenAction.self) static let closeDocument = action(DocumentCloseAction.self) static let saveDocument = action(DocumentSaveAction.self) static func prepare(actions: FeatureActionsBuilder) { actions.declare(createNew) actions.declare(openDocument) actions.declare(closeDocument) actions.declare(saveDocument) } static func urlMappings(routes: URLMappingsBuilder) { routes.send("create", to: createNew) routes.send("open", to: openDocument) } }
You can optionally override the default implementations of
name
anddescription
of you want to change how the feature is presented in logging and debug UI.-note: This type exists simply to allow protocol extenions on this type that are not to be inherited by
ConditionalFeatureDefinition
, e.g. the differingaction()
binding functions.See
ConditionalFeature
for features that can be enabled or disabled based on some condition.Declaration
Swift
public protocol Feature : FeatureDefinition
-
The actions builder protocol defines the domain-specific-language used to declare the actions available on a feature.
See moreDeclaration
Swift
public protocol FeatureActionsBuilder
-
This is the basic information for all features of an application or framework. Use specific sub-protocols
Feature
andConditionalFeature
in your code.Note
Accesses to any properties that may change at runtime, e.g.variation
must only occur on the main thread.Declaration
Swift
public protocol FeatureDefinition : AnyObject
-
A grouping (nesting) of features.
Used to apply some hierarchical struture to feature definitions internally, for logging and debugging user activities.
See morefinal class AppFeatures: FeatureGroup { static var description = "Demo app features" static var subfeatures: [FeatureDefinition.Type] = [ DocumentManagementFeature.self, DocumentSharingFeature.self ] }
Declaration
Swift
public protocol FeatureGroup : FeatureDefinition
-
An implementation of
FocusSelection
is used to control what logging and debug info is currently being produced. When the focus selection is empty (reset), all the normal logging levels apply and there is no filtering.Focusing on one or more features results in only logging related to the focused items being produced, automatically setting debug log level for those features and topic paths.
Topic Paths are used to allow control of non-Feature subsystems that have opted in to Contextual Logging. Feature identifiers are converted to Topic Paths so we have one common concept for logging hierarchy.
See
TopicPath
Declaration
Swift
public protocol FocusSelection
-
The is the high level logger interface that uses the same context for all events, for passing to actions and other subsystems where the user’s feature context is known.
You obtain one of these from a
See moreContextualLoggerFactory
, although typically Flint will automatically provide these to yourAction
(s) in theActionContext
.Declaration
Swift
public protocol ContextSpecificLogger : AnyObject
-
The low level interface for getting a logger.
This is the application-facing interface for logging, which will filter and if necessary prepare log entries for the underlying logging implementation.
Note
Flint supports log levels per topic path (e.g. by Feature) even without setting one or more focused features.
Declaration
Swift
public protocol ContextualLoggerFactory : AnyObject
-
Implementations of this protocol receive the contextual logging requests and must filter and route them to the
See moreLoggerOutput
.Declaration
Swift
public protocol ContextualLoggerTarget
-
The abstraction for creating new log file names
See moreDeclaration
Swift
public protocol LogFileNamingStrategy
-
Declaration
Swift
public protocol LogEventFormattingStrategy
-
An implementation of logging output. This is the protocol to implement to output logs to your chosen logging system.
Note
Log events for excluded levels will never be passed in to the implementation. Interactions with your logging system’s own log level may need close attention. The expectation at the app level is that if something passes the log filtering of Flint that it will appear in the logs. This is particularly important for Focus where Flint will flip the effective log level to DEBUG to allow all loggic for the focused topics through. If your logging subsystem is set to log level INFO then these log events will not be logged.Declaration
Swift
public protocol LoggerOutput
-
Implement this protocol to verify whether a specific purchase has been paid for.
You may implement this against whatever receipt system you use, but typically this is StoreKit.
Flint will call this multiple times for each productID that is required in a
See morePurchaseRequirement
, so implementations only need to respond to single product requests.Declaration
Swift
public protocol PurchaseTracker
-
The protocol for observers of changes to product purchase status
Note
@objc
only because of SR-55.See
PurchaseValidator
Declaration
Swift
@objc public protocol PurchaseTrackerObserver
-
Applications must implement this protocol to provide UI for actions that are invoked for URLs or deep linking.
The implementation is responsible for providing an instance of the right kind of presenter for a given action.
How this works is up to your UI platform and your application. On UIKit for example you may choose to return
See more.appCancelled
if the user has a modal view controller presented currently, or unsaved data in an incomplete workflow. For the case where the current UI state can present the UI for the specified action, the view controllers required must be created in the correct configuration and the final presenter instance returned with a value of.appReady
Declaration
Swift
public protocol PresentationRouter
-
The protocol for decoding an input value from URL route parameters. Conform your input types to this to to enable execution of actions with your input type when incoming URLs are parsed.
See moreDeclaration
Swift
public protocol RouteParametersDecodable
-
The protocol for encoding an input value from URL route parameters. Conform your input types to this to to enable creation of links to actions with your input type.
See moreDeclaration
Swift
public protocol RouteParametersEncodable
-
Features must adopt this protocol if they support URL mappings, and define the routes that map from URLs to actions.
There is support for multiple custom app URL schemes and multiple associated domains, URL wildcards and named variables in the path components.
See moreDeclaration
Swift
public protocol URLMapped
-
The interface to a URLPattern that can be matched to an incoming path and generate
See morereverse
pathsDeclaration
Swift
public protocol URLPattern
-
Actions that implement a Siri Intent must conform to this protocol.
It will ensure that they use a non-main queue (because Intent extensions are called on a background thread) and use an Intent-specific session for log and timeline scoping.
See moreDeclaration
Swift
@available(iOS 12, *) public protocol IntentBackgroundAction : Action
-
Adopt this protocol when implementing an action that fulfills a Siri Intent via an Intent Extension
Note
See https://bugs.swift.org/browse/SR-10831 for why this is so ugly re: defaulting the associated types. The type inference should see the constraints fully satisfy the associated types but it doesn’t, so we have to also specify the associatedtype so that conforming types can compileDeclaration
Swift
@available(iOS 12, *) public protocol IntentAction : IntentBackgroundAction
-
Undocumented
See moreDeclaration
Swift
@objc public protocol TimeOrderedResultsControllerDataSourceObserver
-
Undocumented
See moreDeclaration
Swift
public protocol TimeOrderedResultsControllerDataSource : AnyObject
-
!!! TODO: Remove @objc and change entry to
See morestruct
when Swift bug SR-6039 is fixed.Declaration
Swift
@objc public protocol TimeOrderedResultsControllerDelegate : AnyObject
-
Items conforming to this have an unchanging ID which can be used to locate them again in lists.
See moreDeclaration
Swift
public protocol UniquelyIdentifiable