1

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.

Acoop
  • 2,586
  • 2
  • 23
  • 39
  • Is ParseSubclass subclass of another class ? – Zell B. Aug 11 '15 at 14:27
  • No. I guess the naming is a little confusing, but since this class will not be directly used but only subclassed, I gave it this name. – Acoop Aug 11 '15 at 14:29
  • http://stackoverflow.com/questions/31942742/swift-variable-not-initialized-before-use-but-its-not-used – Will M. Aug 11 '15 at 14:30
  • 1
    @user3650087 In that case, `ParseSuperclass` or `ParseBase` would be a more appropriate name. – Stuart Aug 11 '15 at 14:49

1 Answers1

1

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.

Stuart
  • 36,683
  • 19
  • 101
  • 139