-
Notifications
You must be signed in to change notification settings - Fork 0
Creating Custom Signals
There are a few types of Signal
s defined by the framework, each capturing some specific type of value and possibly some context around it. Most types of values will be logged using a WrapperSignal
, unless a more appropriate type exists. Defining a custom signal requires subclassing Signal
. However, in many cases, it may be less work to just subclass WrappedSignal
instead.
As an example, let's say we're creating a custom signal for this simple struct:
struct Duck {
name: String
}
We'll call this new signal - DuckSignal
.
Our subclass just needs to capture the value we want to log:
class DuckSignal: Signal {
private(set) var duck: Duck
init(_ aDuck: Duck, userInfo: [AnyHashable : Any]? = nil) {
duck = aDuck
super.init()
}
}
WrapperSignal
already captures the value it wraps, so it's often easier to subclass it rather than the base Signal
class.
class DuckSignal: WrapperSignal {}
You would typically want to override a few properties to distinguish this new signal from others:
class DuckSignal: WrapperSignal {
var duck: Duck { value as! Duck }
override var signalName: String { "🦆" }
override var valueDescription: String? { "A Duck named: \(duck.name)" }
}
Another benefit of subclassing from WrapperSignal
is portability - any subclass automatically uses the same portableClassName
as opposed to introducing new types that may not have been defined elsewhere. See Portability for more information.
Lastly, we need to associate the value type with the new signal type so that calls to emit()
can infer this information. This is done via the Signaling
protocol:
extension Duck: Signaling {
public var beaconSignal: DuckSignal { .init(self) }
}
All of this is captured in this snippet, which you can easily add to XCode.