Reputation: 6777
Consider the following code:
class Bar {
let callback: () -> ()
init(callback: @escaping () -> ()) {
self.callback = callback
}
func event() {
self.callback()
}
}
class Foo {
let bar: Bar
init() {
self.bar = Bar(callback: self.handler)
}
func handler() {
print("Handled")
}
}
The basic idea is that we want each Foo
to have a Bar
, which, when event()
is called on a Foo
's bar
, will call Foo
's handler method. However, the setup above warns on Foo
's init since we're using self
before all instance properties have been initialized.
I understand why this is an error: the compiler cannot guarantee that the method passed to Bar
's initializer won't be called somehow before Foo
's initializer finishes (e.g. Bar
may call the callback
param right in it's initializer, or another thread may call event()
just after Bar
's initializer returns but just before the result is assigned to Foo
's bar
).
My question is, is there is a way to implement this pattern that I'm missing? One workaround is to make bar
an IUO var
and assign it to nil
just before calling Bar
's init
--as long as we know the callback won't be called at an improper time (or as long as we don't use bar
in handler
) there shouldn't be an issue. However, this feels pretty hacky to me and I'd love to hear alternatives if they exist.
Upvotes: 1
Views: 346
Reputation: 33967
Here's another option:
class Foo {
let bar: Bar
init() {
self.bar = Bar(callback: self.handler)
}
let handler: () -> Void = {
print("handled")
}
}
Maybe it doesn't feel quite as hacky, but if handler
deals with self
at all, this won't work. You can't do it with a Delegate either.
Yea, AFAIK, the only way to do this is to make bar
an implicitly unwrapped var
class Foo {
var bar: Bar!
init() {
bar = Bar(callback: handler)
}
func handler() {
print("Handled")
}
}
Upvotes: 4