Acoop
Acoop

Reputation: 2666

Initializing a variable inside a function inside the Class init() method

I have the following class (which is quite simple, and the only reason it exists by itself instead of its properties and methods being coded where they are needed is so that I can subclass it) and it is proving to be quite difficult.

class ParseSubclass{

    let object: PFObject

    init (objectPassed: PFObject){
        object = objectPassed
    }

    init (queryPassed: PFQuery, toCallWhenLoadFinishes: () -> ()){
        func toCallUponCompletion (response: PFObject){
            object = response
            toCallWhenLoadFinishes()
        }
        findFirstObjectsInBackgroundFromLocalDataStoreIfPossible(queryPassed, toCallUponCompletion: toCallUponCompletion)
    }
}

The error,

Cannot assign to 'object' in 'self'.

is being thrown at the following line: object = response.

I understand that it is impossible to assign to a let value after initilization, but specifically inside the class's init method, it is allowed as documented in the Swift documentation.

Since I am only giving the value to object inside of the initializer, how would I change the code to explicitly tell the compiler that the function I am using to set it will only be used inside the initializer? Or do I have to trick the compiler in some way? Or is what I am trying to accomplish impossible?

(Note: I tried declaring object as a var but it also threw several more errors including:

  1. on line: func toCallUponCompletion (response: PFObject){ "Variable 'self.object' used before being initialized
  2. on line: findFirstObjectsInBackgroundFromLocalDataStoreIfPossible(queryPassed, toCallUponCompletion: toCallUponCompletion) - "Use of 'self' in method call 'findFirstObjectsInBackgroundFromLocalDataStoreIfPossible' before all stored properties are initialized"
  3. On the following line: (only a } is on this line) - Return from initializer without initializing all stored properties

Thanks for any help in advance.

Upvotes: 1

Views: 1512

Answers (1)

Stuart
Stuart

Reputation: 37043

You are subtly misunderstanding the rules for variable initialisation. It isn't that all variables must be initialised within the init method, but rather that by the time the initialiser returns all variables must be initialised. This is an important distinction, because the role of an initialiser in Swift is to guarantee that the object is always fully initialised before being used. This is also the reason you cannot use self in a method call before initialising all stored variables - the method must expect self to be fully initialised.

In your init(queryPassed:toCallWhenLoadFinishes:) initialiser, you are not meeting this requirement - when it returns, the object variable is not initialised, and what's more it's non-optional so you are guaranteeing that it will have a value. Think about it - what happens when an instance of your class is created using this initialiser, and then you try to access its object variable on the next line? What should happen? It doesn't make sense, so you're not allowed to do it.

Changing object to var doesn't help because you're still not satisfying the requirement that all variables are initialised before returning from init. You have two options: either give object a default initialised value, and update it after your asynchronous method calls its completion handler, or make it an optional variable that is allowed to be nil after initialisation.

Upvotes: 1

Related Questions