105

I'm trying to figure out how to declare a static variable scoped only locally to a function in Swift.

In C, this might look something like this:

int foo() {
    static int timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

In Objective-C, it's basically the same:

- (NSInteger)foo {
    static NSInteger timesCalled = 0;
    ++timesCalled;
    return timesCalled;
}

But I can't seem to do anything like this in Swift. I've tried declaring the variable in the following ways:

static var timesCalledA = 0
var static timesCalledB = 0
var timesCalledC: static Int = 0
var timesCalledD: Int static = 0

But these all result in errors.

  • The first complains "Static properties may only be declared on a type".
  • The second complains "Expected declaration" (where static is) and "Expected pattern" (where timesCalledB is)
  • The third complains "Consecutive statements on a line must be separated by ';'" (in the space between the colon and static) and "Expected Type" (where static is)
  • The fourth complains "Consecutive statements on a line must be separated by ';'" (in the space between Int and static) and "Expected declaration" (under the equals sign)
1
  • Has this changed at all? Does Swift enable the creation of static variables or constants in functions now?
    – daniel
    Jul 6, 2022 at 12:09

4 Answers 4

175

I don't think Swift supports static variable without having it attached to a class/struct. Try declaring a private struct with static variable.

func foo() -> Int {
    struct Holder {
        static var timesCalled = 0
    }
    Holder.timesCalled += 1
    return Holder.timesCalled
}

  7> foo()
$R0: Int = 1
  8> foo()
$R1: Int = 2
  9> foo()
$R2: Int = 3
11
  • Yeah, I continued playing around a bit and this was basically the really clunky solution I came up with as well.
    – nhgrif
    Aug 18, 2014 at 0:29
  • 26
    Upwoted, but I’m sad we have to resort to this.
    – Tricertops
    Feb 23, 2016 at 9:51
  • 1
    Type properties and methods belong to a type (i.e. a Class, Struct or Enum) and cannot belong to a function alone. Apple Documentation on Type Properties. @Tricertops. Another way to go about this would be to put the function "foo" in a class, create a type property for that class and use it inside the function.
    – NSCoder
    Mar 2, 2016 at 13:54
  • 7
    @NSCoder But it’s possible to declare struct Holder {…} inside multiple functions and they will not collide. Swift could support static let without this struct boilerplate around.
    – Tricertops
    Mar 9, 2016 at 9:31
  • 1
    @Honey I am sorry but I can't find more updated other answer?
    – Bryan Chen
    Nov 8, 2016 at 20:55
24

Another solution

func makeIncrementerClosure() -> () -> Int {
    var timesCalled = 0
    func incrementer() -> Int {
        timesCalled += 1
        return timesCalled
    }
    return incrementer
}

let foo = makeIncrementerClosure()
foo()  // returns 1
foo()  // returns 2
6
  • 3
    this is a typical javascript way to do it
    – Bryan Chen
    Oct 29, 2014 at 0:05
  • 1
    But if I call ba() again, the inner function returns 1 on first call. This is different from a static variable.
    – nhgrif
    Nov 16, 2014 at 14:55
  • 2
    This is also taught in Apple's docs here: developer.apple.com/library/ios/documentation/Swift/Conceptual/… It seems to be the best solution just to keep in lines with "functional programming", but there are other solutions as well. This should be the accepted answer though.
    – byteWalrus
    Jan 15, 2015 at 16:36
  • 2
    I'm sorry, but this is an ugly hack adding more complexity for the same problem. What's your point? In that case I prefer a simple class property. @Brian Chen's answer is the closest one you can get. I use his answer for a flipflop kind of solution. Daniel is maybe the best conforming Apple's rules of Swift programming.
    – AndaluZ
    Oct 2, 2015 at 12:34
  • 1
    I particularly liked this solution. This is a perfect example of using a higher-order function to achieve the same result as a static variable inside the scope of a function. Static function vars are not natively supported in Swift for good reasons. It's the natural evolution of programming. Trying to code in old fashion ways requires hacks. In my opinion, adding an extra nested data type as opposed to utilising variable capturing reduces code readability.
    – nstein
    Jul 25, 2016 at 12:07
18

Swift 1.2 with Xcode 6.3 now supports static as expected. From the Xcode 6.3 beta release notes:

“static” methods and properties are now allowed in classes (as an alias for “class final”). You are now allowed to declare static stored properties in classes, which have global storage and are lazily initialized on first access (like global variables). Protocols now declare type requirements as “static” requirements instead of declaring them as “class” requirements. (17198298)

It appears that functions cannot contain static declarations (as asked in question). Instead, the declaration must be done at the class level.

Simple example showing a static property incremented inside a class (aka static) function, although a class function is not required:

class StaticThing
{
    static var timesCalled = 0

    class func doSomething()
    {
        timesCalled++

        println(timesCalled)
    }
}

StaticThing.doSomething()
StaticThing.doSomething()
StaticThing.doSomething()

Output:

1
2
3
5
  • 1
    I suspect this difference in the meaning of static might be intentional on Apple's part, though one is always welcome to file a bug to request a change. In C, static limits storage of a variable to source-file scope (which is not always the same as class scope), while the placement of the variable declaration determines the lexical scope (i.e. global vs within function vs many-nested-{}s). In Swift, storage scope always follows lexical scope, so you can't have a variable that's lexical to a function and that has global storage.
    – rickster
    Feb 10, 2015 at 21:23
  • 8
    Daniel, this is actually subtly (but importantly) different from what the question asks. I appreciate the answer though. @rickster I understand what you are saying and think your comment could be expanded to a good answer for this question.
    – nhgrif
    Feb 11, 2015 at 13:02
  • @nhgrif Yep, I indicated in answer that this doesn't address the specific question. I was just thinking that the changes in Swift 1.2 address the core need for this use case (certainly a better story than pre Swift 1.2). But it sounds like it's important for you to have variable scoped to the function - which currently is not possible.
    – Daniel
    Feb 11, 2015 at 23:26
  • @rickster in C I think static is always stored globally actually. I'm not sure though. I think that's the problem Apple is trying to address here. In swift, it is now always lexically and storage scoped to the class
    – BTRUE
    Apr 16, 2017 at 15:48
  • @nhgrif With my previous comment said, I think Daniel's answer actually should be the accepted answer, because although you can lexically declare a static var in a function in objc, it wasn't scoped there, having the same effect as using a static Type property in swift. the only difference is, the swift declaration point is a lot more descriptive and not misleading as to what the scope of the variable is.
    – BTRUE
    Apr 16, 2017 at 15:50
0

Another solution

class Myclass {
    static var timesCalled = 0
    func foo() -> Int {
        Myclass.timesCalled += 1
        return Myclass.timesCalled
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.