Computed property not computed on set

372 views Asked by At

In my app, I want to allow the user to give me a Display Name when they register, but if they don't give me one, I want to create one using their first name and last initial.

This appeared to me to somewhat fit the computed property paradigm, but not exactly. I tried to do this in my class:

    var displayName: String {
    get {
        if (!self.displayName.isEmpty) {
            return self.displayName
        }
        else {
            let index = self.lastName.index((self.lastName.startIndex), offsetBy: 1)

            return self.firstName + " " + self.lastName.substring(to: index)
        }
    }
    set(displayName) {
        self.displayName = displayName
    }
}

But it crashed in several different places. Is this a correct situation for a computed property, or should I just create a regular property and check for displayName.isEmpty and set it to firstname.lastinitial if that is the case?

Thanx in advance.

2

There are 2 answers

1
Luca Davanzo On BEST ANSWER

Your app crashes for a loop issue.

On your get you have:

if (!self.displayName.isEmpty) {
   return self.displayName
}

I suggest you a solution like this:

class User {

    private var compoundName: String
    var displayName: String {
        get {
            guard !self.compoundName.isEmpty else {
                return self.compoundName
            } 
            if let firstLastNameChar = self.lastName.characters.first {
                 return return "\(self.firstName) \(firstLastNameChar)"
            }
            return self.firstName
        }
        set(displayName) {
            self.compoundName = displayName
        }
    }

}
2
vadian On

The code crashes because in the setter the assignment self.displayName = calls the setter which calls the setter which calls the setter ... which causes an infinite loop. The setter of a computed property must be computed from somewhere else.

An suitable solution for a computed property with getter and setter is to map firstName and lastName from and to displayName for example

var displayName: String {
    get {
        return firstName.isEmpty ? lastName : firstName + " " + lastName
    }
    set {
        let components = newValue.components(separatedBy: " ")
        if components.count == 2 {
            firstName = components[0]
            lastName = components[1]
        } else {
            firstName = ""
            lastName = newValue
        }
    }
}

Note: It's a bad idea to rename the default newValue to the name to the property, newValue must not be related to the property.