As R Menke has already pointed out; since you have no instance of these utility classes/structure, it doesn't make much of a difference.
One possible vote for using classes over structs would be for the very specific situation where you declare your static
functions in a protocol which you specifically constrain to class
usage (protocol ...: class
): the counterpart for structures (protocol ...: struct
) is not available.
/* only class types can conform to this protocol */
protocol MyClassProtocol: class {
static func split(str: String) -> [String]
}
extension MyClassProtocol {
static func split(str: String) -> [String]{
return str.characters.split{$0 == "."}.map(String.init)
}
}
/* Use custom implementation */
class BasicTools: MyClassProtocol {
class func split(str: String) -> [String]{
return str.characters.split{$0 == ","}.map(String.init)
}
}
/* Use default implementation */
class OtherBasicTools: MyClassProtocol { }
BasicTools.split("foo,bar") // ["foo", "bar"]
OtherBasicTools.split("foo.bar") // ["foo", "bar"]
In your context (class/struct of only utility tools), the above :class
constraint for MyClassProtocol
is not really relevant. It is, however, relevant if the MyClassProtocol
protocol---in addition to containing static tools---were to be used as a delegate in a context were a strong reference to this delegate would create a retain cycle. In such a case, we need to constrain the delegate protocol to only be available (for conformance) to reference types, which allow us to use weak references to the delegate itself. In this case, naturally our toolbox must be use in class
context (and not in a structure).
E.g., consider the following example, where we have some static toolbox of functions we want to make available to all our different kind of delegates:
/* Delegate toolbox: static/class functions for use
with your delegates */
protocol MyBasicDelegateTools {
static func delegateCalled() -> ()
}
extension MyBasicDelegateTools {
static func delegateCalled() -> () {
print("Logging: delegate was called")
}
}
Used here by some delegate:
/* Delegate with access to your basic delegate tools */
protocol MyDelegate: class, MyBasicDelegateTools {
func arrUpdated(baz: [Int])
}
/* It's inherrent here that we let the reference to
the delegate be weak, to avoid a retain cycle. */
class Foo {
private var baz : [Int] = [] {
didSet {
if let _ = delegate?.arrUpdated(baz) {
delegate?.dynamicType.delegateCalled()
}
}
}
weak var delegate: MyDelegate?
}
/* Why? Since 'foo' in 'Bar' keeps a strong reference to the 'Foo' instance */
class Bar: MyDelegate {
var foo : Foo
var idx: Int = 0 {
didSet {
print("idx updated: \(idx)")
}
}
init(foo: Foo) {
self.foo = foo
self.foo.delegate = self
}
// MyDelegate
func arrUpdated(baz: [Int]) {
idx = baz.count
}
}
Example usage:
var a = Foo()
var b = Bar(foo: a)
a.baz.append(1)
// idx updated: 1 <-- from custom delegate
// Logging: delegate was called <-- from delegate toolbox