Reputation: 8391
In Swift classes we can use a class function
to create preset instances. Like the calendar example below:
let calender = NSCalendar.currentCalendar()
Which will have a similar pattern as this :
class SomeClass {
var attribute : String
init(value:String) {
attribute = value
}
class func testClass() -> SomeClass {
return SomeClass(value: "test")
}
}
let test = SomeClass.testClass()
But there are no class functions in structs obviously. Xcode recommends using static
instead. This is very close to the singleton pattern.
struct SomeStruct {
var attribute : String
init(value:String) {
attribute = value
}
static var testStruct = SomeStruct(value: "test")
}
Singleton pattern
class Singleton {
static let shared = Singleton()
private init() {
}
}
So is this an ok way to init a struct with preset values since structs are value types. If it is not ok, what is the correct way?
Upvotes: 1
Views: 181
Reputation: 539805
The equivalent of class func
for struct types is static func
:
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
and a static property (the "singleton-pattern") works identically with both class and struct types:
static let singleStruct = SomeStruct(value: "foo")
testStruct()
creates a value on each call, whereas singleStruct
creates the value once (on the first call).
In most cases that would make no difference because structures are
value types. The static property has advantages if creating the
value is "expensive". Also, as @Lance noticed in a comment,
this pattern is used by Apple frequently, such as CGRect.zero
.
However, it makes a difference if the struct has properties which are reference types (or pointers to unmanaged memory). Here is an example:
class MyClass {
var attribute : String
init(value : String) {
attribute = value
}
}
struct SomeStruct {
var ptr : MyClass
init(value : String) {
ptr = MyClass(value: value)
}
static func testStruct() -> SomeStruct {
return SomeStruct(value: "foo")
}
static let singleStruct = SomeStruct(value: "foo")
}
Using the static function:
let test1 = SomeStruct.testStruct()
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.testStruct()
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // foo
Here test1
and test2
are separate values and we get the expected
output.
Using the static property:
let test1 = SomeStruct.singleStruct
print(test1.ptr.attribute) // foo
let test2 = SomeStruct.singleStruct
test2.ptr.attribute = "bar"
print(test1.ptr.attribute) // bar <--- What?
Here, test1
and test2
are set to the same value returned from
the static property. Changing test2.ptr
does not mutate test2
,
resulting in the somewhat unexpected output for test1.ptr.attribute
See Friday Q&A 2015-04-17: Let's Build Swift.Array for an interesting article on how this can be solved.
Btw, static
can be used with class types as well, here static
is a shortcut for class final
: a type method that cannot be overridden
in a subclass. Since there is no inheritance for struct types it makes
sense that type methods for struct types are written as static
.
Upvotes: 2