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.