2

I'm following a tutorial learning about delegates and protocols while using the UITextField object. In the tutorial I noticed that I didn't have to instantiate the NSCharacterSet object first by typing

let letterCharacters = NSCharacterSet()

The tutorial's code worked by reaching directly for the letters variable of NSCharacterSet which is mind blowing. I assumed objects always needed to be instantiated first before using them or making reference to them. Here is the full function that works:

func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        let existingTextHasDecimalSeperator = textField.text?.range(of: ".")
        let replacementTextHasDecimalSeperator = string.range(of: ".")
        let letterCharacters = NSCharacterSet.letters
        let foundCharacter = string.rangeOfCharacter(from: letterCharacters)


        if existingTextHasDecimalSeperator != nil && replacementTextHasDecimalSeperator != nil {
            return false
        } else if foundCharacter != nil {
            return false
        } else {
            return true
        }
    }

Why am I allowed to use NSCharacterSet.letters directly instead of creating a NSCharacterSet object first?

Laurence Wingo
  • 3,912
  • 7
  • 33
  • 61
  • 5
    Did you look up the documentation? [`letters`](https://developer.apple.com/documentation/foundation/nscharacterset/1408569-letters) is a **class** property and returns an instance of `CharacterSet` – Martin R Oct 26 '17 at 19:33
  • @MartinR oh okay! Is that what class properties do? I've read countless blogs and documentation in an attempt to understand class properties but I'd like to understand it from your perspective. – Laurence Wingo Oct 26 '17 at 19:37

2 Answers2

4

From the Apple documentation:

class var letters: CharacterSet

A character set containing the characters in Unicode General Category L* & M*.

The key piece here is the class part of that definition. If it is a class variable, than you do not need to instantiate the object with NSCharacterSet().

A quick primer on variable types.

  • A class variable can be accessed simply by calling the variable with the class name CharacterSet.letters for example
  • An instance variable needs to have its class instantiated first before it can be accessed, characterSet.inverted would be an example of this

Typically, a class variable would never change so it has no need to maintain state. An instance variable likely will.

CodeBender
  • 35,668
  • 12
  • 125
  • 132
3

If you look closely into the documentation (I prefer use jump to definition over apple docs) you can see that the class NSCharacterSet does offer class variables NSCharacterSet

You could compare this to enum with cases, but this a bit different case since you get actual values and well... just not cases. Difference between static and class variable are that class variables can be overriden, static cannot.

But to answer your question: You can access these variables directly because they are static.

You can create yourself a nice example, if you open playground:

class Car {

// This might be bad example, but you will see on next lines...
  class var brand: String { return "Volkswagen" }

  /// Because Volkswagen... :D 
  class func emitSmog() {
     // Do wonderful things to earth and basically product rainbows
    }
}

// You don't need to create the Car instance 
print(Car.brand)

// Again, this function is static, so you don't need to construct anything...
Car.emitSmog()

Please refer to Apple documentation:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html

See Type methods.

Dominik Bucher
  • 2,120
  • 2
  • 16
  • 25