Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper way to reference a static variable on a Swift Protocol?

Assume a protocol defined below:

protocol Identifiable {
  static var identifier: String { get }
}
extension Identifiable {
  static var identifier: String { return "Default Id" }
}

What is the best way to reference the static variable? The example below illustrates two ways to access the variable. What is the difference, and is the type(of:) better?

func work<I: Identifiable>(on identifiable: I) {
  let identifier: String = I.identifier
  print("from Protocol: \(identifier)")

  let identiferFromType: String = type(of: identifiable).identifier
  print("using type(of:): \(identiferFromType)")
}

struct Thing: Identifiable {
  static var identifier: String { return "Thing" }
}

work(on: Thing())
like image 592
sean woodward Avatar asked Mar 22 '17 15:03

sean woodward


People also ask

How do you declare a static variable in Swift?

You create static variable by appending static keyword in front of your variable declaration. We will be using playground to explore more. When we define any variable as let, it means it's values cannot be modified, On the other hand if we define any variable as var it means it's values can be modified.

What is static variable in Swift?

When you define a static var/let into a class (or struct), that value will be shared among all the instances (or values). static variables/class are variables can be accessed without need of creation of any instance/object.

Where static variables are stored in Swift?

data segment stores Swift static variables, constants and type metadata.

When should I use static in Swift?

The Static keyword makes it easier to utilize an objects properties or methods without the need of managing instances. Use of the Static keyword in the Singleton pattern can reduce memory leaks by mismanaging instances of classes.


1 Answers

In the example you show, there is no difference. Because identifier is a protocol requirement, it will be dynamically dispatched to in both cases, therefore you don't need to worry about the wrong implementation being called.

However, one difference arises when you consider the value of self inside the static computed property when classes conform to your protocol.

self in a static method/computed property is the metatype value that it's is called on. Therefore when called on I, self will be I.self – which is the static type that the compiler infers the generic placeholder I to be. When called on type(of: identifiable), self will be the dynamic metatype value for the identifiable instance.

In order to illustrate this difference, consider the following example:

protocol Identifiable {
    static var identifier: String { get }
}

extension Identifiable {
    static var identifier: String { return "\(self)" }
}

func work<I : Identifiable>(on identifiable: I) {
    let identifier = I.identifier
    print("from Protocol: \(identifier)")

    let identiferFromType = type(of: identifiable).identifier
    print("using type(of:): \(identiferFromType)")
}

class C : Identifiable {}
class D : C {}

let d: C = D()

// 'I' inferred to be 'C', 'type(of: d)' is 'D.self'.
work(on: d)

// from Protocol: C
// using type(of:): D

In this case, "which is better" completely depends on the behaviour you want – static or dynamic.

like image 128
Hamish Avatar answered Nov 15 '22 06:11

Hamish