Observables in a remote interface are reactive streams of Event instances in
Swift that, when connected to a Web Frame, can push data to the web
layer. They are implemented with
Combine Framework,
the reactive programming library that powers
SwiftUI, which means they are instances of
Publishers.
Examples
Observables can be declared any number of ways. The following examples are for a remote observable that sends events every time the network connection changes.
Declared as a @Published property
Use the
@Published attribute
to create an underlying publisher for the annotated property. Every time the
property is assigned a new value, the underlying publisher will emit the new
value to any subscribers.
The underlying publisher can be accessed with the $ operator ($connection in
the following example).
class Network {
@Published var connection: Event?
}
Declared as a CurrentValueSubject
A
CurrentValueSubject
can be used to declare a publisher outside of a class.
let networkConnection = CurrentValueSubject<Event?, Never>(nil)
Web Frame Configuration
For the following example, we’ll be using an observable declared like the following:
let networkConnection = CurrentValueSubject<Event?, Never>(nil)
The observable reference can be passed directly to the Web Frame configuration.
Notice we must reset the type of the publisher to AnyPublisher by using
.eraseToAnyPublisher()
to conform to the
RemoteObservable type expected by
Peregrine. This is known as type erasure in Swift.
let configuration = WebFrame.Configuration(
baseURL: ...
functions: ...
observables: [
"networkConnection$": networkConnection.eraseToAnyPublisher()
]
)
Observables must end in a dollar sign ($) to denote a reactive property, as
popularized by Cycle.js. This isn’t merely
convention—the dollar sign is how ProxyClient knows it’s an observable, not a
function.
Swift API
Event
Remote observables must emit Event objects, which represent a single value
sent to the web layer.
Initializers
init?<T: Encodable>(_ json: T)
Create an Event with any encodable object.
Structs (or classes) must implement the
Encodable protocol
from Swift:
struct Connection: Encodable {
let type: String
}
Then, objects can be passed to this constructor directly:
let event = Event(Connection(type: "wifi"))
This initializer will return nil if encoding fails (highly unlikely).
Not all Events must be wrapped in objects. In Swift, many data types implement the Encodable protocol: strings, booleans, ints, doubles, arrays, dictionaries, etc.