Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I'm porting some Obj-C code to Swift, and I've written the following code to allow me to deal with "static local variables" which do not exist in Swift.

A static local variable has these requirements:

  • it is shared between all instances that access it
  • it has one assignment method which only sets the value when it is first declared.
  • has another assignment method which sets its value normally (i.e. any time it is used)

There has to be a better way then what I have coded. For starters, I know that using UnsafeBitcast is not good practice.

class Container<T:Any>{

    var _memory:Any
    var memory:T {
        get {

            if let typed_value = self._memory as? T {
                // for value types, such as "String"
                return typed_value
            } else {
                // for types conforming to "AnyObject", such as "NSString"
                return unsafeBitCast( self._memory, T.self )
            }

        }
        set {
            self._memory = newValue
        }
    }

    init( memory:Any ){
        self._memory = memory
    }

}

var Static_Containers = [String:AnyObject]()

func static_var <T:Any>(
    value:T,
    file: StaticString = __FILE__,
    line: UWord = __LINE__,
    col: UWord = __COLUMN__,
    fun: StaticString = __FUNCTION__
) -> Container<T> {

        let unique_key = "FUNC_\(fun)__LINE\(line)_COL\(col)__FILE_\(file)"

        let needs_init = !contains( Static_Containers.keys, unique_key )

        if needs_init {
            Static_Containers[unique_key] = Container<T>( memory:value )
        }

        return Static_Containers[unique_key]! as! Container<T>

}

Here's a couple tests:

func test_with_nsstring( str:NSString, init_only:Bool ) -> NSString {   
    var stat_str = static_var( str )
    if !init_only {
        stat_str.memory = str
    }
    return stat_str.memory
}
test_with_nsstring( "this should get set", true )
test_with_nsstring( "this should be ignored", true ) // only repeated declaration
test_with_nsstring( "this should change the value", false )
test_with_nsstring( "as should this", false )

func test_with_int( i:Int, init_only:Bool ) -> Int {
    var stat_int = static_var( i )
    if !init_only {
        stat_int.memory = i
    }
    return stat_int.memory
}
test_with_int( 0, true ) 
test_with_int( 1, true ) // only repeated declaration
test_with_int( 2, false ) 
test_with_int( 3, false ) 

func test_with_optstr( optstr:String?, init_only:Bool ) -> String? {
    var stat_optstr = static_var( optstr )
    if !init_only {
        stat_optstr.memory = optstr
    }
    return stat_optstr.memory
}
test_with_optstr( nil, true ) 
test_with_optstr( "this should be ignored", true ) // only repeated declaration
test_with_optstr( "this should change the value", false )
test_with_optstr( "as should this", false )

When I test this code in a Playground, it seems to behave correctly. I'd just like a less nutty, and less brittle, way to accomplish this.


Update: Thanks to nhgrif for suggesting an inline struct. Using that, my revised code looks like this:

func test_with_nsstring( str:NSString, init_only:Bool ) -> NSString {

    // this line replaces *all* the code I originally posted 
    struct stat_str { static var memory:NSString=str }

    if !init_only {
        stat_str.memory = str
    }
    return stat_str.memory
}
share|improve this question
1  
Have you seen this? stackoverflow.com/questions/25354882/… –  nhgrif 17 hours ago
    
@nhgrif It works. Can you please repost your comment as an answer, so I can give you proper credit? Thanks! –  Charlesism 17 hours ago

1 Answer 1

up vote 3 down vote accepted

The only work around for this that I've come up with thus far is something that looks like this:

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

It's pretty clunky in my opinion, and I'm not sure why Apple doesn't just allow straight static function variables, but this seems quite a bit cleaner than your approach.

share|improve this answer
    
I imagine Apple will get around to it. In the meantime, your solution should work fine. Thanks! –  Charlesism 14 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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