I'd like to achieve the following in code:
class MyService {
let mySubject = BehaviorSubject<MyData>(value: nil)
//....
}
Unfortunately, I get the "nil requires a contextual type" error. I want the subject to be "empty" till I actually put something in there. How can I pass nil as the argument then? Can I cast it to my own type to make it work?
Contextual objects characterize an object M together with the typing context Ψ in which it is meaningful. This idea is then also internalized within the type theory itself using the notion of a contextual type which pairs the type A of an object together with the context Ψ in which the object is well-typed.
Swift assumes by default that all variables have a value. Unless you tell it otherwise by declaring an optional you can't have a nil value in a place where your program expects there to be a value.
Based on the reference for RxSwift BehaviorSubject
, the init(value:)
initializer is declared as
public init(value: Element)
Where the value
parameter is described as:
value
Initial value sent to observers when no other value has been received by the subject yet.
And where Element
is the placeholder type of BehaviorSubject
:
public final class BehaviorSubject<Element> ...
This means you need to specify the placeholder type Element
as an Optional
type if you are to be able to set the initial value (used when no other value has been received) to nil
. E.g.:
class MyService {
let mySubject = BehaviorSubject<MyData?>(value: nil)
//....
}
Or, letting the compiler infer the placeholder as MyData?
by using the non-sugared .none
form for the nil
argument:
class MyService {
let mySubject = BehaviorSubject(value: Optional<MyData>.none)
//....
}
As for understanding the actual error message better, consider the following self-contained example:
struct Foo<T> {
init(value: T) {}
}
struct Bar {}
let bar = Bar()
_ = Foo<Bar>(value: bar) // OK
_ = Foo(value: bar) // OK, T inferred as Bar
_ = Foo<Bar>(value: nil) // Error: error: 'nil' requires a contextual type
_ = Foo<Bar?>(value: nil) // OK
_ = Foo(value: Optional<Bar>.none) // OK, T inferred as Bar?
While dfri's answer is technically correct, you might want to consider a different type when working with RxSwift. Since you want your subject to be empty only at the beginning, I'd suggest to use ReplaySubject
or PublishSubject
.
A similar question has also been asked on RxSwift's GitHub issue page. Allow BehaviorSubject without initial value. There, kzaher suggests the ReplaySubject
.
Your subject would then look like this, without any initial value and without MyData being Optional
.
let subject = ReplaySubject<MyData>().create(bufferSize: 1)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With