R Menke
R Menke

Reputation: 8391

What is the correct way to create preset Structs?

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

Answers (1)

Martin R
Martin R

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

Related Questions