Aleksandar Petrov Aleksandar Petrov - 4 months ago 12
Swift Question

Create member variable with closure in its constructor

I'm having the following code in my class:

// MARK: - Lifecycle

init() {
authenticationContext = AuthenticationContext()
synchronizationContext = SynchronizationContext()

employeesCoordinator = EmployeesCoordinator()

serverErrorObserver =
NotificationObserver(notification: serverErrorNotification,
block: handleServerError) // <- Error
}

// MARK: - Listeners

private let serverErrorObserver: NotificationObserver!

private lazy var handleServerError: NSError -> () = {
[unowned self] (error) in
// Currently means that the token is expired, so remove stored instance
self.handleAuthorizationDidExpired()
}


It looks legit, but I'm getting the following complier error:


Use of 'self' in property access 'handleServerError' before all stored
properties are initialized


If it would help, this is the source behind NotificationObserver:

class ValueWrapper<T> {
let value: T
init(_ value: T) { self.value = value }
}

// Notification

struct Notification<A> {
let name: String
}

// Global Functions

func publish<A>(note: Notification<A>, value: A) {
let userInfo = ["value": ValueWrapper(value)]
NSNotificationCenter.defaultCenter().postNotificationName(note.name, object: nil, userInfo: userInfo)
}

//

class NotificationObserver {

let observer: NSObjectProtocol

init<A>(notification: Notification<A>, block aBlock: A -> ()) {
observer = NSNotificationCenter.defaultCenter().addObserverForName(notification.name, object: nil, queue: nil) { note in
let wrapper = note.userInfo?["value"] as? ValueWrapper<A>
if let value = wrapper?.value {
aBlock(value)
} else {
assert(false, "Couldn't understand user info")
}
}
}

deinit {
NSNotificationCenter.defaultCenter().removeObserver(observer)
}

}

// Global variables

let serverErrorNotification: Notification<NSError> = Notification(name: "ServerErrorNotification")
let synchronizationDidCompleteNotification: Notification<Int> = Notification(name: "SynchronizationDidCompleteNotification")
let authorizationDidCompleteNotification: Notification<Authorization> = Notification(name: "SynchronizationDidCompleteNotification")

RJE RJE
Answer

You cannot call self until you have properly initialized the object using super.init()

if you have un-initialized let variables they should initialize before super.init() call. so doing so you cannot call to self - closure calls to self

so you have to change let to var, then call super.init() before assigning closure

private let serverErrorObserver: NotificationObserver!

to

private var serverErrorObserver: NotificationObserver!

eg.

init() {
 super.init()
    authenticationContext = AuthenticationContext()
    synchronizationContext = SynchronizationContext()

    employeesCoordinator = EmployeesCoordinator()

    serverErrorObserver =
        NotificationObserver(notification: serverErrorNotification,
                             block: handleServerError) // <- Error
}