Novellizator
Novellizator

Reputation: 14883

how to deal with 'Self captured by closure before being initialized'

Say I have a structure as follows:

class A {
  class ReadyHandler { // fires off the callback when needed
    let callback;
    init(callback: ()->Void) {
      self.callback = callback
    }
  }
  let readyHandler: ReadyHandler
  let ready = false
  init() {
    readyHandler = ReadyHandler(callback: {self.ready = true})
  }
}

The problem is, naturally, that I'm attempting to initialize a callback using self, which is not yet initialized. How can I avoid the circular reference and the respective error?

Upvotes: 4

Views: 4402

Answers (2)

Sandeep
Sandeep

Reputation: 21144

The problem with your code is that you have declared the variable as a constant, and swift should always have constants initialized within the init method. But, here you have dependent kind of requirement, readyHandler property is a constant which has to be initialized in order to create object but then, you are using self inside it which is not initialized, you can see a cyclic requirement.

You can directly get rid of this, if you use optional or implicitly unwrapped optional in which case, swift need not have initial value at the phase of instantiation.

class A {
  class ReadyHandler { // fires off the callback when needed
    let callback: ()->Void
    init(callback: @escaping ()->Void) {
      self.callback = callback
    }
  }
  var readyHandler: ReadyHandler!
  var ready = false

  init() {
    readyHandler = ReadyHandler(callback: {self.ready = true})
  }
}

You can create a also use lazy property for your readyHandler which gets initialized first time it is used.

class A {
  class ReadyHandler {

    let callback: ()->Void

    init(callback: @escaping ()->Void) {
      self.callback = callback
    }

  }

  var ready = false

  lazy var readyHandler: ReadyHandler = {
    return ReadyHandler(callback: { [unowned self] in
      self.ready = true
    })
  }()
}

Upvotes: 4

dymv
dymv

Reputation: 3252

The easiest way you can go with something like this:

class A {
    class ReadyHandler {
        let callback: () -> Void
        init(callback: @escaping () -> Void) { self.callback = callback }
    }

    let readyHandler: ReadyHandler
    var ready = false

    init() {
        var handlerBody = {}
        readyHandler = ReadyHandler { handlerBody() }
        handlerBody = { self.ready = true }
    }
}

Upvotes: 1

Related Questions