93

I begin my project with a split view controller as initial view controller and start it automatically from storyboard.

Generally, an app with this UI have one and only one split view controller as root, so I create a static variable in the subclass and set it when initialisation was done.

So I want try this behaviour with swift.

I read the Swift programming language guide book on iBook about Type properties (with static and class keyword) and trying a piece of code to the job:

import UIKit

class SplitViewController: UISplitViewController {

    class func sharedInstance() -> SplitViewController {
        return SplitViewController.instance
    }

    class let instance: SplitViewController = nil

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.initialization()
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder);
        self.initialization()
    }

    func initialization() {
        SplitViewController.instance = self;
    }
}

but I figured out when Xcode say the class keyword for type properties wasn't supported yet.

error detail in image

Did you have a solution to do this ?

skywinder
  • 21,291
  • 15
  • 93
  • 123
Vincent Saluzzo
  • 1,377
  • 1
  • 11
  • 13
  • What happens if you replace 'let' with 'var'? – ZunTzu Jun 03 '14 at 12:46
  • It yields the same error. – Cezar Jun 03 '14 at 12:47
  • 1
    It's the first seed, calm down. :) If the book says it's supported and it's not yet available, it **will** be. Even the error says **"yet"**. – akashivskyy Jun 03 '14 at 12:48
  • 1
    Yes @akashivskyy you've reason but may be it could be and error on my side and someone have a solution to do this behavior... – Vincent Saluzzo Jun 03 '14 at 12:51
  • Would just like to add that if you write static instead of class you get an error: Static properties are only allowed within structs and enums; use 'class' to declare a class property – Epic Byte Jun 12 '14 at 01:10
  • With the Xcode 6 DP5 working around, class static properties are still not supported. – Luc-Olivier Aug 08 '14 at 20:18
  • Even with the GM 'seed' release still not supported :( – Jake Hall Sep 11 '14 at 22:40
  • This is too bad. I think this will be needed by a lot of people. – Bagusflyer Sep 14 '14 at 14:11
  • For myself, I think that's the only missing for using Swift in production... – Vincent Saluzzo Sep 15 '14 at 08:03
  • Still "not yet supported" – Andreas Jan 08 '15 at 21:29
  • Is there a reason it's not supported? Creating a structure seems to be a sort of "hack". Is there a different way to do this? Are they encouraging developers to stay away from static class variables by not supporting this? Or have they "just not gotten around to it"? Lotta questions. It just seems like a huge thing for Apple to just include later. – datWooWoo Jan 15 '15 at 16:44
  • 1
    @lespommes Apple is notoriously tight-lipped about anything that's pending. It's embarrassing for them that such a standard and obvious feature was lacking from their huge release of their new flagship language. There are many improvements required before Swift is ready for serious use. – Hyperbole Feb 03 '15 at 18:28
  • I tried this again in Xcode 6.1.1 and it seems that this is now supported – Clafou Feb 09 '15 at 17:00
  • Someone have tried in new Xcode beta and Swift 1.2, I appreciate a feedback if you have ! – Vincent Saluzzo Feb 11 '15 at 08:57

12 Answers12

73

Embedding a struct can work just fine as a workaround:

class SomeClass
{
  // class var classVariable: Int = 0
  // "Class variables not yet supported." Weird.

  // Workaround:
  private struct SubStruct { static var staticVariable: Int = 0 }

  class var workaroundClassVariable: Int
  {
    get { return SubStruct.staticVariable }
    set { SubStruct.staticVariable = newValue }
  }
}

The SomeClass.workaroundClassVariable computed type property can then be used as if it were a stored type property.

Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421
glessard
  • 730
  • 1
  • 4
  • 8
  • 1
    Worked for me - except as I had to drop the 'public' as XCode 6.0 did not like me declaring a public class within an internal class. – Ali Beadle Oct 25 '14 at 11:03
  • Works great, except that xcode does not allow nested type in a generic type... so if you have a generic class, it seems rather hopeless as only computed properties are possible. – BenMQ Jan 15 '15 at 15:52
37

Swift now has support for static variables in classes. This is not exactly the same as a class variable (because they aren't inherited by subclasses), but it gets you pretty close:

class X {
  static let y: Int = 4
  static var x: Int = 4
}

println(X.x)
println(X.y)

X.x = 5

println(X.x)
Bill
  • 44,502
  • 24
  • 122
  • 213
  • 1
    As Bill says, that's the not the same but that's I need ! – Vincent Saluzzo Apr 21 '15 at 21:41
  • @VincentSaluzzo, (and Bill) What the difference between this and class variable? – skywinder May 13 '15 at 08:40
  • The Apple documentation have changed recently to update status : https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID265 In fact, `class` keyword can only used for computed properties now and static are for all type properties (in enum, class or struct) – Vincent Saluzzo May 13 '15 at 13:08
  • @skywinder As I mentioned in my answer, true class variables can be inherited by subclasses. Static variables can't. – Bill May 13 '15 at 15:47
  • @VincentSaluzzo Does Apple update its document? https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID264 look at the fourth paragraph: "For value types (that is, structures and enumerations), you can define stored and computed type properties. For classes, you can define computed type properties only." – fujianjin6471 Jul 17 '15 at 14:05
  • @Bill Your answer, if talking about Swift, is wrong (at the moment of speaking). Type properties, means properties defined as static, are inherited by subclasses no matter if they are stored or computed. Stored type properties are not overridable in subclasses. Unlike stored type properties, a computed type properties are, if you use class keyword instead of static keyword. – Whirlwind Jan 24 '16 at 19:50
  • @Whirlwind Um, I'm not making a distinction between stored and computed properties...if you read my answer and comment, I'm talking about the difference between `static` and `class` properties... – Bill Nov 16 '19 at 12:40
19

It seems to be possible to declare variables with static storage duration in file scope (as in C):

var sharedInstance: SplitViewController? = nil

class SplitViewController: UISplitViewController {
    ....
    func initialization() {
        sharedInstance = self
    }
}
Nikolai Ruhe
  • 81,520
  • 17
  • 180
  • 200
  • mmmh, why not, but define a var at file scope doesn't do a memory leak in a long time usage ? – Vincent Saluzzo Jun 03 '14 at 13:47
  • @VincentSaluzzo There's no difference to what you did before Swift: store the sole instance in a static variable. There's nothing to be leaked here, except the single instance which lives as long as the process. – Nikolai Ruhe Jun 03 '14 at 13:56
  • I tried this in playground with my own class. It doesn't work 'cos the class has not be declared yet when you initialized that "static" var. I have not tried it in Xcode project (i guess it must have worked there?). So I may need to figure out "class forward declaration" like you always do when specifying protocol for a class. – kawingkelvin Sep 13 '14 at 21:23
  • 2
    Note that in Xcode 6.0, you cannot have two file scope variables with the same name, even if they are `private`. – nschum Sep 22 '14 at 20:23
  • @NikolayTsenkov Exactly. – Nikolai Ruhe Oct 23 '14 at 16:42
14

My preferred method is to just use a private file scope var outside of the class and then implement class/static getters and setters:

private var _classVar: Int = 0;

class SomeClass
{
    public class var classVar: Int
    {
        get { return _classVar }
        set { _classVar = newValue }
    }
}
BobDickinson
  • 2,156
  • 21
  • 18
5

As of Swift 1.2 (available with Xcode 6.3b1 and onwards), static class properties and methods are supported.

class SomeClass
{
    static var someVariable: Int = 0
}
Andreas Ley
  • 9,109
  • 1
  • 47
  • 57
4

Using a dispatch_once singleton model in Swift

Seems to be the best answer so far, avoiding the use of a global variable.

Community
  • 1
  • 1
Gavin
  • 6,495
  • 3
  • 21
  • 22
4

A solution enough similar than var in file scope but more customisable and near singleton is to use a struct which support static var as property of class

struct PersonSharedData {
    static var backstore = ""
    var data: String {
    get { return PersonSharedData.backstore }
    set { PersonSharedData.backstore = newValue }
    }
}

class Person {
    var shared=PersonSharedData() //<< pseudo class var
    var family: String {
        get { return shared.data }
        set { shared.data=newValue }
    }
    var firstname = ""
    var lastname = ""
    var sexe: Sexe = .Unknown
}
Luc-Olivier
  • 3,715
  • 2
  • 29
  • 29
2

Ok, with the solution of Nikolai that do the work. I post my changes in this thread for information

var instance: SplitViewController? = nil

class SplitViewController: UISplitViewController {

    class func sharedInstance() -> SplitViewController? {
        return instance;
    }

    init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
        super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
        self.initialization()
    }

    init(coder aDecoder: NSCoder!) {
        super.init(coder: aDecoder);
        self.initialization()
    }

    func initialization() {
        instance = self
    }
}

and for example, in my appDelegate, I can access this static method like this

SplitViewController.sharedInstance()!.presentsWithGesture = false
Vincent Saluzzo
  • 1,377
  • 1
  • 11
  • 13
  • I'm just curious, but isn't the variable "instance" a global variable then? This would mean that if you have another singleton class your variable "instance" would be overwritten, right? – Raphael Dec 01 '14 at 15:04
1

The wording in the error heavily implies this will be a language feature in the future.

You may want to resort temporarily to declaring a property variable in the Application Delegate and retrieve it from there. Not ideal, definitely an anti-pattern, but would give you a central place to retrieve the UISplitViewController when needed.

Cezar
  • 55,636
  • 19
  • 86
  • 87
  • No because in my case, the SplitViewController was initizalize by runtime when awake from storyboard, so I can't directly access to this view controller from my application delegate – Vincent Saluzzo Jun 03 '14 at 12:52
1

You have to wrap the class variables inside an inner struct variable

class Store{
    var name:String
    var address:String
    var lat:Int
    var long:Int
    init(name:String, address:String, lat:Int, long:Int){
        self.name = name
        self.address = address
        self.lat = lat
        self.long=long
    }

    private struct FACTORY_INITIALIZED_FLAG { static var initialized: Bool = false
       static var  myStoreList:[Store]?
        static func getMyStoreList()->[Store]{
            if !initialized{
                println("INITIALIZING")
                myStoreList = [
                    Store(name: "Walmart", address: "abcd", lat: 10, long: 20),
                    Store(name: "JCPenny", address: "kjfnv", lat: 23, long: 34)
                ]
                initialized = true
            }
                return myStoreList!
    }
    }
}


var a = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()

var b = Store.FACTORY_INITIALIZED_FLAG.getMyStoreList()

// only prints INITIALIZING once
Morteza Shahriari Nia
  • 1,392
  • 18
  • 24
0

Try this:

class var instance: SplitViewController {
    return nil
}
0

It is called Type Property in Swift.

You define type properties with the static keyword. For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation. The example below shows the syntax for stored and computed type properties:

struct SomeStructure {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 1
    }
}
enum SomeEnumeration {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 6
    }
}
class SomeClass {
    static var storedTypeProperty = "Some value."
    static var computedTypeProperty: Int {
        return 27
    }
    class var overrideableComputedTypeProperty: Int {
        return 107
    }
}

Read more at link below,

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html#//apple_ref/doc/uid/TP40014097-CH14-ID254

XY L
  • 25,431
  • 14
  • 84
  • 143