Gerardo
Gerardo

Reputation: 55

Swift: Passing callbacks to struct instance

I would like to do something along the lines of the pseudo code below:

struct Foo {
  let BarInstance = Bar(Callback: CallBarInstance)

  func CallBarInstance() -> Void {
    BarInstance.FunctionToCall()
  }
}

struct Bar {
  var Callback: () -> Void

  func FunctionToCall() -> Void {
    print("Hello")
  }

  // More code that calls Callback
}

I get the error that I can't convert (Foo)->()->Void to ()->Void. I think I understand this is because the instance of Foo is being passed in as it is a member function. I figured it could then be made a static function that calls but getting access to the member variables felt hacky - is there a good way to get the functionality I want in Swift?

Upvotes: 0

Views: 953

Answers (1)

Sweeper
Sweeper

Reputation: 271735

You seem to be trying to do something dangerous here, and Swift is stopping you from doing it.

In this line:

let BarInstance = Bar(Callback: CallBarInstance)

You are leaking an uninitialised self to Bar. Why? Because at the point in time when Bar.init is called, Foo is not be fully initialised. Namely, what is the value of BarInstance at this point? It is undefined. Yet you are trying to pass self.CallbarInstance to Bar.init!

Imagine what could happen if this were allowed. Bar.init had called the passed in function directly, before it returns. Now we have a very weird situation: CallBarInstance actually makes use of the value of BarInstance in its implementation, but what's the value of BarInstance? Bar.init hasn't returned so it's undefined!

The error message is a bit unclear though. Swift treats CallBarInstance as a (Foo) -> () -> Void in this situation (as if you were calling it as Foo.CallBarInstance), because self is unavailable.

You can kind of fix it by initialising BarInstance with some other value first, then assigning the intended Bar instance, but I don't know whether this will produce your intended behaviour or not.

struct Foo {
  var BarInstance = Bar(Callback: {})

    init() {
        BarInstance = Bar(Callback: CallBarInstance)
    }

  func CallBarInstance() -> Void {
    BarInstance.FunctionToCall()
  }
}

Upvotes: 2

Related Questions