Swift: The rules of being static (Xcode 6 GM)


The same but different 

"In Objective-C, you can define type-level methods only for Objective-C classes. In Swift, you can define type-level methods for all classes, structures, and enumerations. Each type method is explicitly scoped to the type it supports." (Apple)
As explained in the above quotation, enums and structs support type methods in Swift. But rather than use the class keyword (as classes do), enums and structs use the static keyword to define type methods. This difference means that when it comes to protocols there is a certain mismatch of terms, as can be seen from this code (adapted from the class post):
enum FoodGroups {
    case Carbohydrates, Proteins, Fats, Fibre, Minerals, Vitamins
}

protocol Food {
    class var varieties:[String] {get}
    class func goesWith(type:FoodGroups) -> Bool
}

struct Rice:Food {
    static var varieties:[String] {
    return ["white","brown"]
    }
    static func goesWith(type:FoodGroups) -> Bool {
        if type == .Carbohydrates {
            return false
        }
        else {
            return true
        }
    }
}

Rice.goesWith(.Proteins)
Rice.varieties
While the protocol defines type methods with the keyword class, a struct (or enum) uses the keyword static in order to adhere to the protocol's requirements.

This is not the only difference between static and class keywords. At present static can be used before a (non-computed) property and this itself carries a set of considerations, since it must be taken into account that there is, for example, no init() method to initialize type properties.

So without further ado here are the rules of being static.

The rules of being static

  1. static is used to define type methods and properties in structs and enums
  2. static can be used with properties, computed properties and methods
  3. static cannot be used in protocols (you must always use class)
  4. where a protocol defines a type method or property with the class keyword, structs and enums replace the keyword with static to perform the same task
  5. "a type method can call another type method with the other method’s name, without needing to prefix it with the type name" (Apple)

Type properties

In addition to the global rules of using static, it must be noted when working with (non-computed) properties that:
  • variable and constant type properties are permitted
  • the value of a type property can be a closure
  • (non-computed) type properties cannot be included in a protocol (at present)
  • "Unlike stored instance properties, you must always give stored type properties a default value. This is because the type itself does not have an initializer that can assign a value to a stored type property at initialization time." (Apple)
  • while a type property requires a default value (see above note), it can also be an optional (?) or force unwrapped optional (!). If this is a case then no value need be assigned, it can be left as nil.

Basic example

enum FoodGroups {
    case Carbohydrates, Proteins, Fats, Fibre, Minerals, Vitamins
}

struct Rice {
    static var averagePricePerKiloInDollars:Double!
    static var varieties:[String] {
    return ["white","brown"]
    }
    static let greetings:(String) -> String = {
        name in return "Hello \(name). Do you like rice?"
    }
    static func goesWith(type:FoodGroups) -> Bool {
        if type == .Carbohydrates {
            return false
        }
        else {
            return true
        }
    }
}

Rice.goesWith(.Proteins)
Rice.varieties
Rice.averagePricePerKiloInDollars = 1.23
Rice.averagePricePerKiloInDollars // returns 1.23
Rice.greetings("Bert") // "Hello Bert. Do you like rice?" 
In this example, an implicitly unwrapped optional is used for the type property, averagePricePerKiloInDollars, we also have a read-only computed property (although we could have a computed property with a getter and setter if we wished), we also have a property with the value of a closure and finally a function.

Beyond the limits (... sort of)

While attempts to use a protocol alongside a struct to require stored (i.e. non-computed) properties currently raises an error when we do this
protocol Pro {
    class var a:String {get set}
}

struct Struc:Pro {

    static var a:String = "" // compiler warning that Struc does not follow Pro protocol
} 
it is possible to find a work around by doing this instead:
protocol Pro {
    class var a:String {get set}
}

struct Struc:Pro {

    static var a:String {get {return b} set{b=newValue}}
    static var b:String = ""
} 
Although it must be confessed that the protocol cannot force the use of the stored property to support the computed one.


Endorse on Coderwall

Comments