fuzzygoat
fuzzygoat

Reputation: 26223

Access class property from instance?

I am not sure is this is correct behaviour or if its unintended. I have setup StealthFighter so that it returns a class type computed property variable called ammunition.

func globalTests() {
    println("globalTests")
    println("AMMUNITION: \(StealthFighter.ammunition)")
    var myStealthFighter = StealthFighter()
    println("MISSILES: \(myStealthFighter.missiles)")
    println("AMMUNITION: \(myStealthFighter.ammunition)") // ERROR
}

class StealthFighter {
    class var ammunition:Int {
    return 500;
    }
    var missiles: Int = 5
}

When directly accessing the class StealthFighter this works fine and returns 500 as expected. But if I create and instance myStealthFighter and then try and access the class property on the instance I get the error: 'StealthFighter' does not have a member named 'ammunition' I can't find any mention of this, I am assuming from this that class properties are accessible only via the class? and not on any instances created from it? I just want to make sure I am understanding this correctly ...

EDIT:

So I have probably worded the type variable name wrong as it should probably be maxAmmunition to signify that StealthFighters can only take 500 rounds. I can see the point, if you want the maxAmmunition for the class then you ask the class.

As @Kreiri and @0x7fffffff points out it does seem that you can ask the instance what the class ammunition (or maxAmmunition) is by using dynamicType.

println("CLASS - AMMUNITION: \(StealthFighter.ammunition)")
var myStealthFighter = StealthFighter()
println("INSTA - AMMUNITION: \(myStealthFighter.dynamicType.ammunition)")

.

// OUTPUT
// CLASS - AMMUNITION: 500
// INSTA - AMMUNITION: 500

Upvotes: 13

Views: 7743

Answers (5)

Vlad
Vlad

Reputation: 6732

Swift 4:

var myStealthFighter = StealthFighter()
type(of: myStealthFighter).ammunition

Upvotes: 3

Mick MacCallum
Mick MacCallum

Reputation: 130193

Your assumption is correct. Type variables are only meant to be accessed directly from the class. If you want to get at them from an instance, you can do so by accessing the dynamicType property on your instance, like so.

let theFighter = StealthFighter()
let missiles = theFighter.dynamicType.missiles
println(missiles)

However, I don't think that this is the correct approach for you to be taking here. Assuming that you want to have one class "StealthFighter", and possibly multiple instances of that class, each with the ability to have its own number of missiles independent of the others, you should probably make this an instance variable by simply ditching the class keyword.

Upvotes: 10

Anil Varghese
Anil Varghese

Reputation: 42977

These properties are known as Type properties in swift. It should be called on its type ie class name, not on instance. Type properties holds same value across all the instances of the class just like static constant in C.

Querying and Setting Type Properties

Type properties are queried and set with dot syntax, just like instance properties. However, type properties are queried and set on the type, not on an instance of that type

Excerpt from : swift programming language

Upvotes: 3

Kreiri
Kreiri

Reputation: 7850

dynamicType allows access instance’s runtime type as a value, so accessing class property from instance would look like this:

var myStealthFighter = StealthFighter()
myStealthFighter.dynamicType.ammunition

Works in playground, at least.

Upvotes: 3

Prine
Prine

Reputation: 12528

Yes. This is a correct behaviour. These Type Properties can only be accessed over the Type and are not available on the instance itself.

In the Swift Book from Apple it is described in the section "Type Properties" (Page 205).

Swift Type Properties

“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"

Upvotes: 2

Related Questions